package demo.bank.transaction.implicit;

/**
 * Simple Transaction Service example, code taken and adapted 
 * from http://www.wiley.com/compbooks/vogel/ejb/code.html
 */

import org.omg.CORBA.*;
import org.omg.CosTransactions.*;

public class AccountImpl
    extends AccountPOA
{
  private float balance;
  private float newBalance;
  private float amount;
  private boolean credit;
  private ORB orb;
  private String name;
  private Lock lock;
  private org.omg.CosTransactions.Current ts_current = null;

  private boolean nasty = false;
  private int nasty_count = 0;

  public AccountImpl( ORB orb, String name, float deposit ){
    this(orb, name, deposit, false);
  }

  public AccountImpl( ORB orb, String name, float deposit, boolean nasty ) 
  {
    this.name = name;
    this.orb = orb;
    this.nasty = nasty;

    balance = deposit;
    lock = new Lock();
	
    try{
      ts_current = (org.omg.CosTransactions.Current)
	orb.resolve_initial_references("TransactionCurrent");
    }catch (Exception e){
      jacorb.util.Debug.output(2, e);
    }
  }

  public float balance()
  {
    return balance;
  }

  public synchronized void credit( float amount ) 
  {
    try 
      {
	if (nasty){
	  switch (nasty_count++){
	  case 0 : 
	    break;
	  case 1 :
	    System.out.println("Step 1 nastyness: error");
	    throw new Error("Bank Holidays");
	  case 2:
	    System.out.println("Step 2 nastyness: COMM_FALIURE");
	    throw new org.omg.CORBA.COMM_FAILURE();
	  }
	}

	// lock account
	lock.lock();

	Control control = jacorb.transaction.TransactionCurrentImpl.getControl(orb);

	// memorize current activitity
	this.amount = amount;
	credit = true;

	System.err.println("Account " + name + "::credit: get coordinator");
	Coordinator coordinator = control.get_coordinator();

	// register resource
	System.out.println("Account " + name +
			   "::credit: register resource (Account) with ITS");
	RecoveryCoordinator recCoordinator =
	  coordinator.register_resource( _this() );

	newBalance = balance + amount;
	System.out.println(" credit $" + amount );
	System.out.println(" new balance is $" + newBalance );
      }
    catch( Exception ex ) 
      {
	System.err.println("Account " + name + "::credit: exception: " + ex );
      };
  }

  public synchronized void debit( float amount )
    throws InsufficientFunds 
  {
    try 
      {

	if (nasty){
	  switch (nasty_count++){
	  case 0 : 
	    System.out.println("Step 0 nastyness: InsufficientFunds");
	    throw new InsufficientFunds();
	  case 1 :
	    System.out.println("Step 1 nastyness: error");
	    throw new Error("Bank Holidays");
	  case 2:
	    System.out.println("Step 2 nastyness: COMM_FALIURE");
	    throw new org.omg.CORBA.COMM_FAILURE();
	  }
	}
	// lock account
	lock.lock();

	Control control = jacorb.transaction.TransactionCurrentImpl.getControl(orb);

	// memorize current activitity
	this.amount = amount;
	credit = false;
	
	System.err.println("Account " + name + "::debit: get coordinator");
	Coordinator coordinator = control.get_coordinator();

	// register resource
	System.out.println("Account " + name + 
			   "::debit: register resource (Account) with ITS");
	RecoveryCoordinator recCoordinator =
	  coordinator.register_resource( _this() );
	System.out.println("Account " + name + "::debit: resource registered");

	if( amount > balance ) 
	  {
	    System.out.println("no sufficient funds");
	    lock.unlock();
	    System.out.println("Resource: " + name + " account unlocked");
	    throw new InsufficientFunds();
	  }
	newBalance = balance - amount;
	System.out.println(" debit $" + amount );
	System.out.println(" new balance is $" + newBalance );

      }
    catch( Unavailable u ) {
      System.err.println("Account " + name + "::debit: exception: " + u );
    }
    catch( Inactive i ) {
      System.err.println("Account " + name + "::debit: exception: " + i );
    }
    catch( SystemException se ) {
      System.err.println("Account " + name + "::debit: exception: " + se );
    }
  }

  // implement methods of the Resource interface

  public Vote prepare() 
  {
    System.out.println("Resource " + name + " : prepare()");
    if( balance == newBalance )
      return Vote.VoteReadOnly;
    return Vote.VoteCommit;
  }

  public void rollback() 
  {
    // remove data from temporary storage
    System.out.println("Resource " + name + " : rollback()");
    System.out.println("Resource " + name +
		       " : original balance restored: $" + balance);
    lock.unlock();
    System.out.println("Resource " + name + " account unlocked");
  }

  public void commit() 
  {
    // move data to final storage
    System.out.println("Resource " + name + " : commit()");
    balance = newBalance;
    lock.unlock();
    System.out.println("Resource " + name + " account unlocked");
  }

  public void commit_one_phase() 
  {
    // store data immediately at final destination
    System.out.println("Resource " + name + " : commit_one_phase()");
    if(prepare() == Vote.VoteCommit) 
      {
	commit();
      }
  }

  public void forget() 
  {
    System.out.println("Resource " + name + " : forget()");
  }
}
