import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import java.rmi.server.UnicastRemoteObject;
import net.jini.core.discovery.LookupLocator;
import net.jini.core.entry.Entry;
import net.jini.core.lease.Lease;
import net.jini.core.lease.LeaseDeniedException;
import net.jini.core.lookup.ServiceRegistrar; 
import net.jini.core.lookup.ServiceTemplate; 
import net.jini.core.transaction.server.TransactionConstants;
import net.jini.core.transaction.server.TransactionManager.Created;
import net.jini.core.transaction.server.TransactionManager;
import net.jini.core.transaction.server.TransactionParticipant;
import net.jini.core.transaction.UnknownTransactionException;
import net.jini.lookup.entry.Name;
import sdsu.util.ProgramProperties;

public class AuctionClient extends Thread implements TransactionParticipant
	{
	AuctionInterface auctioneer;
	int bidAmount;
	Bid bidTicket;
	int bank = 100;
	int bidsWon = 0;
	int bidAttempts = 0;
	
	public static void main (String[] args) throws Exception
		{
		System.out.println( "Start" );
		ProgramProperties flags = new ProgramProperties( args);
		
		int commandBid = flags.getInt( "bid", 5 );
		System.setSecurityManager (new RMISecurityManager ());
		LookupLocator lookup = new LookupLocator ("jini://eli.sdsu.edu");
		ServiceRegistrar registrar = lookup.getRegistrar ();
		AuctionClient aClient = new AuctionClient( commandBid, registrar );
		aClient.start();
		}
		
	public AuctionClient( int bid, ServiceRegistrar registrar ) throws RemoteException
		{
		System.out.println( "New Client" );
		this.bidAmount = bid;
		Entry[] serverAttributes = new Entry[1];
		serverAttributes[0] = new Name ("Auction");
		ServiceTemplate template = new ServiceTemplate (null, null, serverAttributes);
		
		System.out.println( "Get auctioneer" );
		auctioneer = (AuctionInterface) registrar.lookup (template);

		System.out.println( "export" );

		UnicastRemoteObject.exportObject( this );
		}

		
	public synchronized void abort(TransactionManager mgr, long transactionID) 
		{
		System.out.println( "Abort" );
		bidTicket = null;
		notifyAll();
		}
		
	public synchronized void commit(TransactionManager mgr, long transactionID) 
		{
		System.out.println( "Commit" );
		bank = bank - bidAmount;
		bidTicket = null;
		bidsWon++;
		notifyAll();
		}
		
	public int prepare(TransactionManager mgr, long transactionID) 
		{
		System.out.println( "Prepare" );
		if ( bidAmount > bank)
			{
			bidAmount = bank;
			abort(mgr,transactionID );
			return ABORTED;
			}
		else
			return PREPARED;
		}

	public int prepareAndCommit(TransactionManager mgr, long transactionID) 
		{
		System.out.println( "prepare & commit" );
		int result = prepare( mgr, transactionID );
		if ( result == PREPARED )
			{
			commit(  mgr, transactionID );
			result = COMMITTED;
			}
		return result;
		}

	public synchronized void run()
		{
		try
			{
			do
				{
				System.out.println( "Make bid" );
				bidTicket = auctioneer.bid( bidAmount, this );
				bidAttempts++;
				while (bidTicket != null )
					wait();
				
				System.out.println( "Bid attempts: " + bidAttempts + 
					" bids won " + bidsWon + " bank " + bank );
				}
			while (bank > 0 );
			}
		catch (Exception rmiError )
			{
			rmiError.printStackTrace();
			}
		finally
			{
			finalize();
			}
		}

	public void finalize()
		{
		try
			{
			UnicastRemoteObject.unexportObject( this, true );
			}
		catch (Exception problem )
			{
			problem.printStackTrace();
			}
		}
		
	}