// Fig. 15_14: TransactionProcessor.java
// Transaction processing program using RandomAccessFiles.

// This program reads a random access file sequentially,
// updates data already written to the file, creates new
// data to be placed in the file, and deletes data
// already in the file.
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.text.DecimalFormat;

public class TransactionProcessor extends Frame
             implements ActionListener {
   
   // Application window components
   private Button update,    // update record
                  newRecord, // add new record
                  delete,    // delete record
                  done;      // quit program

   private UpdateDialog updateDialog; // record update
   private NewDialog newDialog;       // add new records
   private DeleteDialog deleteDialog; // delete records

   // Application other pieces
   private RandomAccessFile file;  
   private Record data;   

   // Constructor -- intialize the Frame
   public TransactionProcessor()
   {
      super( "Transaction Processor" );

      // Open the file
      try {
         file = new RandomAccessFile( "credit.dat", "rw" );
      }
      catch ( IOException ioe ) {
         System.err.println( ioe.toString() );
         System.exit( 1 );
      }

      data = new Record();

      setSize( 300, 80 );
      setLayout( new GridLayout( 2, 2 ) );
      
      update = new Button( "Update Record" );
      update.addActionListener( this );
      add( update );

      newRecord = new Button( "New Record" );
      newRecord.addActionListener( this );
      add( newRecord );

      delete = new Button( "Delete Record" );
      delete.addActionListener( this );
      add( delete );

      done = new Button( "Done" );
      done.addActionListener( this );
      add( done );

      setVisible( true );             // show the Frame

      // Create dialog boxes
      updateDialog = new UpdateDialog( this, file );
      newDialog = new NewDialog( this, file );
      deleteDialog = new DeleteDialog( this, file );      
   }

   // Process actions
   public void actionPerformed( ActionEvent e )
   {
      if ( e.getSource() == update ) 
         updateDialog.setVisible( true );
      else if ( e.getSource() == newRecord ) 
         newDialog.setVisible( true );
      else if ( e.getSource() == delete ) 
         deleteDialog.setVisible( true );
      else
         closeFile();
   }

   public void closeFile()
   {
      try {
         file.close();
         System.exit( 0 );
      }
      catch ( IOException ioe ) {
         System.err.println( ioe.toString() );
         System.exit( 1 );
      }
   }

   public static void main( String args[] )
   { 
      new TransactionProcessor();
   }
}

class UpdateDialog extends Dialog implements ActionListener {
   private TextField account, firstName, lastName, 
                     balance, transaction;
   private Button cancel, save;

   private RandomAccessFile file;
   private Record data;
   private int accountNumber;

   public UpdateDialog( TransactionProcessor t,
                        RandomAccessFile f )
   {     
      super( t, "Update Record", true );

      file = f;  
      data = new Record();

      setSize( 320, 180 );
      setLayout( new GridLayout( 6, 2 ) );

      add( new Label( "Account" ) );
      account = new TextField();
      account.addActionListener( this );
      add( account );

      add( new Label( "First name" ) );
      firstName = new TextField();
      add( firstName );

      add( new Label( "Last name" ) );
      lastName = new TextField();
      add( lastName );

      add( new Label( "Balance name" ) );
      balance = new TextField();
      add( balance );

      add( new Label( "Transaction amount" ) );
      transaction = new TextField();
      transaction.addActionListener( this );
      add( transaction );

      save = new Button( "Save Changes" );
      save.addActionListener( this );
      add( save );

      cancel = new Button( "Cancel" );
      cancel.addActionListener( this );
      add( cancel );
   }

   public void actionPerformed( ActionEvent e )
   {
      if ( e.getSource() == account ) {
         accountNumber = Integer.parseInt( account.getText() );
         readAccountInformation();
      }
      else if ( e.getSource() == save )  {
         accountNumber = Integer.parseInt( account.getText() );
         updateAccountInformation();
      }
      else if ( e.getSource() == cancel ) {
         setVisible( false );
         clear();
      }
      else if ( e.getSource() == transaction ) {   
         DecimalFormat twoDigits = new DecimalFormat( "0.00" );
         Double transactionAmount = 
                   Double.valueOf( transaction.getText() );
         data.setBalance( 
            data.getBalance() + transactionAmount.doubleValue() );
         balance.setText( twoDigits.format( data.getBalance() ) );
      }
   }

   private void readAccountInformation()
   {
      DecimalFormat twoDigits = new DecimalFormat( "0.00" );

      if ( accountNumber < 1 || accountNumber > 100 ) {
         account.setText( "Invalid account" );
         return;
      } 
 
      try {
         file.seek( ( accountNumber - 1 ) * Record.size() );
         data.read( file );

         if ( data.getAccount() != 0 ) {
            account.setText( String.valueOf( data.getAccount() ) );
            firstName.setText( data.getFirstName() );
            lastName.setText( data.getLastName() );
            balance.setText( twoDigits.format(
                                data.getBalance() ) );
            transaction.setText( "charge(+) or payment(-)" );
         }
         else
            account.setText( String.valueOf( accountNumber ) +
                          " does not exist" );
         }
      catch ( IOException ioe ) {
         account.setText( "Error reading file" );
      }
   }

   private void updateAccountInformation()
   {
      try {
         file.seek( ( accountNumber - 1 ) * Record.size() );
         data.write( file );
      }
      catch ( IOException ioe ) {
         account.setText( "Error writing file" );
         return;
      }

      setVisible( false );
      clear();
   }

   private void clear() 
   {
      account.setText( "" );
      firstName.setText( "" );
      lastName.setText( "" );
      balance.setText( "" );
      transaction.setText( "" );
   }
}

class NewDialog extends Dialog implements ActionListener {
   private RandomAccessFile file;
   private TextField account, firstName, lastName, balance;
   private Button cancel, save;
   
   private Record data;
   private int accountNumber;

   public NewDialog( TransactionProcessor t,
                     RandomAccessFile f )
   {     
      super( t, "New Record", true );
      file = f;  
      data = new Record();

      setSize( 300, 150 );
      setLayout( new GridLayout( 5, 2 ) );

      add( new Label( "Account" ) );
      account = new TextField();
      account.addActionListener( this );
      add( account );

      add( new Label( "First name" ) );
      firstName = new TextField();
      add( firstName );

      add( new Label( "Last name" ) );
      lastName = new TextField();
      add( lastName );

      add( new Label( "Balance" ) );
      balance = new TextField();
      add( balance );

      save = new Button( "Save Changes" );
      save.addActionListener( this );
      add( save );

      cancel = new Button( "Cancel" );
      cancel.addActionListener( this );
      add( cancel );
   }

   public void actionPerformed( ActionEvent e )
   {
      if ( e.getSource() == account ) 
         checkIfAccountExists();
      else if ( e.getSource() == save ) 
         addRecord();
      else if ( e.getSource() == cancel ) {
         setVisible( false );
         clear();
      }
   }

   private void checkIfAccountExists()
   {
      accountNumber = Integer.parseInt( account.getText() );

      if ( accountNumber < 1 || accountNumber > 100 ) {
         account.setText( "Invalid account" );
         return;
      } 
   
      try {
         file.seek( ( accountNumber - 1 ) * Record.size() );
         data.read( file );
      }
      catch ( IOException ioe ) {
         account.setText( "Error reading file" );
      }
 
      if ( data.getAccount() == 0 ) {
         firstName.setText( "Enter first name" );
         lastName.setText( "Enter last name" );
         balance.setText( "Enter balance" );
      }
      else {
         account.setText( data.getAccount() +
                          " already exists" );
         firstName.setText( "" );
         lastName.setText( "" );
         balance.setText( "" );
      }
   }

   private void addRecord()
   {
      try {
         data.setAccount( accountNumber );
         data.setLastName( lastName.getText() );
         data.setFirstName( firstName.getText() );
         data.setBalance( ( new Double (
            balance.getText() ) ).doubleValue() );
         file.seek( ( accountNumber - 1 ) * Record.size() );
         data.write( file );
      }
      catch ( IOException ioe ) {
         account.setText( "Error writing file" );
         return;
      }

      setVisible( false );
      clear();
   }

   private void clear() 
   {
      account.setText( "" );
      firstName.setText( "" );
      lastName.setText( "" );
      balance.setText( "" );
   }
}

class DeleteDialog extends Dialog implements ActionListener {
   private RandomAccessFile file;
   private TextField account;
   private Button cancel, delete;
   
   private Record data;
   private int accountNumber;

   public DeleteDialog( TransactionProcessor t,
                        RandomAccessFile f )
   {     
      super( t, "Delete Record", true );
      file = f;  
      data = new Record();

      setSize( 300, 80 );
      setLayout( new GridLayout( 2, 2 ) );

      add( new Label( "Account" ) );
      account = new TextField();
      account.addActionListener( this );
      add( account );

      delete = new Button( "Delete Record" );
      delete.addActionListener( this );
      add( delete );

      cancel = new Button( "Cancel" );
      cancel.addActionListener( this );
      add( cancel );
   }

   public void actionPerformed( ActionEvent e )
   {
      if ( e.getSource() == account )  {
         accountNumber = Integer.parseInt( account.getText() );

         if ( accountNumber < 1 || accountNumber > 100 ) {
            account.setText( "Invalid account" );
            return;
         } 
   
         try {
            file.seek( ( accountNumber - 1 ) * Record.size() );
            data.read( file );
         }
         catch ( IOException ioe ) {
            account.setText( "Error reading file" );
         }
   
         if ( data.getAccount() == 0 ) 
            account.setText( accountNumber + "does not exist" );
      }
      else if ( e.getSource() == delete ) {
         try {
            file.seek( ( accountNumber - 1 ) * Record.size() );
            data.setAccount( 0 );
            data.setFirstName( "" );
            data.setLastName( "" );
            data.setBalance( 0.0 );
            data.write( file );
         }
         catch ( IOException ioe ) {
            account.setText( "Error writing file" );
         }

         setVisible( false );
         account.setText( "" );
      }
      else if ( e.getSource() == cancel ) {
         setVisible( false );
         account.setText( "" );
      }
   }
}