import java.util.*;
import java.util.concurrent.*;




public class MultipleInstance
{
	static final int MaxCustomerCount=3;
	static Container container=new Container();
	static Customer customerList[]=new Customer[MaxCustomerCount];
	static String customerNames[]={ "Lenova", "IBM","Intel"};
	static float customerBalances[]={5000.0f, 5000.0f, 5000.0f};
	static int ThreadRunningTimes=10;
	
	static CyclicBarrier barrier=new CyclicBarrier(2);
	static MyThread thread0;
	static MyThread thread1;
	static int finished=0;
	public static void main(String args[])
	{
		init();
		thread0=new MyThread(0);
		thread1=new MyThread(1);
		thread0.start();
		thread1.start();
		Customer trouble=new Customer("Lenova", -5000.0f);

		while (finished<2)
		{
			try
			{
				Thread.sleep(1000);
				System.out.println("let trouble starts here and see if IBM is still 5000.0");
				container.addCustomer(trouble);
				container.getCustomer("IBM").display();
				container.removeCustomer(trouble);
			}
			catch(Exception er)
			{
			}
		}

		System.out.println("if synchronized keyword can apply to multiple instance, then "+
			" the balance should be 5000+10*50*2=6000 and let's see how much it is:");
		container.getCustomer("IBM").display();
	}

	static void init()
	{
		for (int i=0; i<MaxCustomerCount; i++)
		{
			customerList[i]=new Customer(customerNames[i], customerBalances[i]);
			container.addCustomer(customerList[i]);
		}
	}


	static class MyThread extends Thread
	{
		int id;
		public MyThread(int myID)
		{
			id=myID;
		}

		public void run()
		{
			try
			{
				barrier.await();
			
				int counter=0; 
				//Note: we get a "copy" from container instead of "reference" in C++
				Customer cust=container.getCustomer("IBM");

				while (counter<ThreadRunningTimes)
				{
					if (id==0)
					{
						cust.addBalance(50.0f);
					}
					else
					{
						cust.minusBalance(50.0f);
					}
					counter++;
					if (id==0)
					{
						counter++;
					}
					cust.display();
					Thread.sleep(1000);
				}
				System.out.println(id +" finished "+ThreadRunningTimes+" times and now write back to container");
				cust=container.putCustomer(cust);
				System.out.println("the old value is:");
				cust.display();

				finished++;
			}
			catch(Exception er)
			{
			}
		}
	}


/*
	static class Container
	{
		Hashtable customerTable=new Hashtable();

		public Customer getCustomer(String custName)
		{
			return (Customer)customerTable.get(custName);
		}

		//we already know Hashtable are synchronized class
		public Customer putCustomer(Customer cust)
		{
			return (Customer)customerTable.put(cust.customerName, cust);
		}

		public void addCustomer(Customer cust)
		{
			//here I omit necessary validating of customer name
			customerTable.put(cust.customerName, cust);
		}

	}
*/
	static class Container
	{
		Vector customerTable=new Vector();

		public synchronized Customer getCustomer(String custName)
		{
			Customer cust=null;
			for (int i=0; i<customerTable.size(); i++)
			{
				cust=(Customer)customerTable.elementAt(i);
				if (cust.customerName.compareTo(custName)==0)
				{
					break;
				}
			}
			return cust;//maybe null
		}

		//we already know Hashtable are synchronized class
		public synchronized Customer putCustomer(Customer cust)
		{
			Customer old=null;
			for (int i=0; i<customerTable.size(); i++)
			{
				old=(Customer)customerTable.elementAt(i);
				if (old.customerName.compareTo(cust.customerName)==0)
				{
					customerTable.setElementAt(cust, i);
					break;
				}
			}
			return old;//maybe null indicating failure
		}

		public void addCustomer(Customer cust) //no need synchronized
		{
			//here I omit necessary validating of customer name
			customerTable.add(cust);
		}
		public void removeCustomer(Customer cust)
		{
			customerTable.removeElement(cust);
		}
			

	}

	static class Customer
	{
		String customerName;
		float balance;
		public Customer(String name, float aBalance)
		{
			customerName=name;
			balance=aBalance;
		}
		//note the method is synchronized!
		public synchronized void addBalance(float value) 
		{
			balance+=value;
		}
		public synchronized void minusBalance(float value)
		{
			balance-=value;
		}
		public void display()
		{
			System.out.println("customer name:"+customerName+" balance:"+balance);
		}
	}
}
				
				
		
		