import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.io.*;

public class FinancialApplet extends Applet
{
    /* history of the account */
    private FinancialHistory history;

    /* name of the file where history is serialized */
    private String fileName; 

    /* bottoni sull'applet  */ 
    private Button depositButton=new Button("Deposit");
    private Button withdrawButton=new Button("Withdraw");
    private Button printButton=new Button("Info");

    /* finestre ausiliarie di dialogo */
    private Dialog3 depositDialog;
    private Dialog3 withdrawDialog;
    private Dialog1 infoDialog;
    private Dialog1 errorDialog;

    /* COSTRUTTORI */

    public FinancialApplet()
    {
	try { history=new FinancialHistory(1000); }
	catch(NegAmountException e){}
    }

    public FinancialApplet(String fileName)
    {
	try
        {
	    FileInputStream fis = new FileInputStream(fileName);
	    ObjectInputStream ois = new ObjectInputStream(fis);
	    history=(FinancialHistory) ois.readObject();
	    ois.close();
            fis.close();
	}
	catch(Exception e)
        {
	    System.out.println(e.getMessage());
	    try { history=new FinancialHistory(1000); }
	    catch(NegAmountException ne){}
	}
	this.fileName=fileName;
    }

    /* INIT */

    public void init()
    {
	/* finestra di dialogo modale per informazioni */
	infoDialog=new Dialog1(getFrame(),"Information",true);
	infoDialog.addOkListener(new HideListener(infoDialog));
	/* finestra di dialogo modale per deposito */
	depositDialog=new Dialog3(getFrame(),"Deposit",true);
        depositDialog.addOkListener(new DoDeposit());
	depositDialog.addClearListener(new ClearListener(depositDialog));  
	depositDialog.addDismissListener(new HideListener(depositDialog));  
	/* finestra di dialogo modale per prelievo */
	withdrawDialog=new Dialog3(getFrame(),"Withdraw",true);
	withdrawDialog.addOkListener(new DoWithdraw());
        withdrawDialog.addClearListener(new ClearListener(withdrawDialog));
        withdrawDialog.addDismissListener(new HideListener(withdrawDialog));
        /* finestra di dialogo modale per errori */
        errorDialog=new Dialog1(getFrame(),"Error",true);
        errorDialog.addOkListener(new HideListener(errorDialog));

	/* Bottoni presenti sull'applet */
	setLayout(new FlowLayout());
	depositButton.addActionListener(new ShowListener(depositDialog));  
	add(depositButton);
	withdrawButton.addActionListener(new ShowListener(withdrawDialog));  
	add(withdrawButton);
	printButton.addActionListener(new ShowListener(infoDialog));  
	add(printButton);
    }

    private Frame getFrame()
    { // retrieve applet frame
	Component c=this;
	while (c.getParent()!=null)  c = c.getParent();
	return (Frame) c;
    }

    /* METODI PER PREPARARE I DIALOGHI PRIMA DI MOSTRARLI */

    void prepareErrorDialog(String msg)
    {
      Panel p = new Panel(new BorderLayout());
      Label l = new Label(msg);
      p.add(l,BorderLayout.CENTER);
      errorDialog.addCenter(p);
    }

    void prepareInfoDialog()
    {
       Panel p = new Panel(new BorderLayout());
       TextArea sx = new TextArea("",8,40,TextArea.SCROLLBARS_VERTICAL_ONLY);
       TextArea dx = new TextArea("",8,40,TextArea.SCROLLBARS_VERTICAL_ONLY);
       StringWriter w = new StringWriter();
       sx.setText(history.printIncomes());
       p.add(sx,BorderLayout.WEST);
       w = new StringWriter();
       dx.setText(history.printExpenditures());
       p.add(dx,BorderLayout.EAST);
       Label l = new Label("Total amount: "+history.cashOnHand());
       p.add(l,BorderLayout.SOUTH);  
       infoDialog.addCenter(p);
    }

    /* ACTION LISTENER */

    class ShowListener implements ActionListener
    {
	private Dialog dialog;
	public ShowListener(Dialog dialog)
	{ this.dialog=dialog;  }
	public void actionPerformed(ActionEvent event)
        {  
          if (dialog==infoDialog) prepareInfoDialog();
          else if (dialog==depositDialog) depositDialog.clear();
          else if (dialog==withdrawDialog) withdrawDialog.clear();
          dialog.setVisible(true);
        }
    }

    class DoWithdraw implements ActionListener
    {
	public void actionPerformed(ActionEvent event)
        {
	  try
          {
	    if(withdrawDialog.getAmount().equals(""))
		    throw new Exception("Please, insert the amount");
	    if(withdrawDialog.getReason().equals(""))
		    throw new Exception("Please, insert a reason");
            history.spendFor(Integer.parseInt(withdrawDialog.getAmount()),
                             withdrawDialog.getReason());
            withdrawDialog.setVisible(false);

	  }
	  catch(Exception e)
          {  prepareErrorDialog(e.getMessage());
 	     errorDialog.setVisible(true);    
          }
	}
    }

    class DoDeposit implements ActionListener
    {
	public void actionPerformed(ActionEvent event)
        {
	  try
          {
	    if(depositDialog.getAmount().equals(""))
		    throw new Exception("Please, insert the amount");
	    if(depositDialog.getReason().equals(""))
		    throw new Exception("Please, insert a reason");
	    history.receiveFrom(Integer.parseInt(depositDialog.getAmount()),
                                depositDialog.getReason());
            depositDialog.setVisible(false);

	  }
	  catch(Exception e)
          {  prepareErrorDialog(e.getMessage());
 	     errorDialog.setVisible(true);    
          }
	}
    }
 
    class HideListener implements ActionListener
    {
	private Dialog dialog;
	public HideListener(Dialog dialog)
	{ this.dialog=dialog;  }
	public void actionPerformed(ActionEvent event)
        {  dialog.setVisible(false);  }
    }

    class ClearListener implements ActionListener
    {
	private Dialog3 dialog;
	public ClearListener(Dialog3 dialog)
	{ this.dialog=dialog;  }
	public void actionPerformed(ActionEvent event)
        {   dialog.clear();  }
    }

    /* MAIN (per far girare l'applet come applicazione) */

    public static void main(String[] args)
    {
	Frame frame = new Frame("Financial Applet");
	final FinancialApplet app;
        if (args.length>0) app=new FinancialApplet(args[0]);
	else app=new FinancialApplet();
	frame.add(app);
	app.init();
        // nota: prima aggiungere app al frame e poi fare init perche'
        // init ha bisogno del frame per costruire i dialoghi
	frame.pack();
        WindowListener frameListener = new WindowAdapter()
        {
          public void windowClosing(WindowEvent event)
          {
            if (app.fileName!=null)
            try
            {
              FileOutputStream fos = new FileOutputStream(app.fileName);
              ObjectOutputStream oos = new ObjectOutputStream(fos);
              oos.writeObject(app.history);
              oos.close();
              fos.close();
            }
            catch(Exception e) {}
            System.exit(0);
          }
        };
	frame.addWindowListener(frameListener);
	frame.setVisible(true); 
    } 
}

/* dialogo con solo un bottone ok */
class Dialog1 extends Dialog
{
  protected Button okButton;
  protected Panel lowerPart;
  protected Panel centerPart;
  public Dialog1(Frame f, String title, boolean modal)
  {
    super(f,title,modal);
    setLayout(new BorderLayout());
    okButton = new Button("ok");
    lowerPart = new Panel();
    lowerPart.setLayout(new FlowLayout());
    lowerPart.add(okButton);
    add(lowerPart,BorderLayout.SOUTH);
    centerPart = null;
    pack();
  }
  public void addOkListener(ActionListener l)
  {  okButton.addActionListener(l);  }
  public void addCenter(Panel p)
  {  if (centerPart!=null) remove(centerPart);
     add(p,BorderLayout.CENTER);
     centerPart = p;
     pack();
  } 
}

/* dialogo con tre bottoni ok, clear, dismiss per chiusura 
   e dispositivi per chiedere soldi da prelevare / depositare */
class Dialog3 extends Dialog1
{
  protected Button clearButton;
  protected Button dismissButton;
  protected TextField amountField=new TextField("",6);
  protected TextField reasonField=new TextField("",8);
  protected Label amountLabel=new Label("Please, enter the amount:");
  protected Label reasonLabel=new Label("Please, enter the reason:");
  public Dialog3(Frame f, String title, boolean modal)
  {
    super(f,title,modal);
    clearButton = new Button("clear");
    dismissButton = new Button("dismiss");
    lowerPart.add(clearButton);
    lowerPart.add(dismissButton);
    centerPart = new Panel(new GridLayout(2,2));
    centerPart.add(amountLabel);
    centerPart.add(amountField);
    centerPart.add(reasonLabel);  
    centerPart.add(reasonField);   
    add(centerPart,BorderLayout.CENTER);  
    pack();
  }
  public void clear()
  {  amountField.setText("");  reasonField.setText("");  }
  public void addClearListener(ActionListener l)
  {  clearButton.addActionListener(l);  }
  public void addDismissListener(ActionListener l)
  {  dismissButton.addActionListener(l);  }
  public String getAmount() {  return amountField.getText();  }
  public String getReason() {  return reasonField.getText();  }

}
