package lt.ktu.mockus.srgm;

import java.util.*;
import javax.swing.SwingUtilities;

public class StockTradeThread extends Thread
{
	//for testing purposes, dEps is not random
	//private static double dEps1[] = {-0.08, 0.05, 0.04, 0.07, 0.13, 0.01, 0.0, -0.07, -0.18, -0.04, -0.01, -0.04,-0.07, 0.0, -0.13, -0.13, -0.08, 0.1, -0.07, -0.3, -0.02, -0.06, -0.02, -0.09, -0.06, -0.13, -0.08, -0.03, 0.01, 0.17, 0.01, 0.12, 0.22, 0.01, 0.01, 0.16, 0.0, 0.01, 0.09, 0.09, 0.11, 0.08, 0.06, 0.14, 0.07, 0.03, 0.0, -0.16, -0.11, -0.02, -0.02, 0.05, -0.14,-0.03, 0.0, -0.02, -0.24,-0.02, -0.01, -0.02, -0.17, -0.12, -0.01, 0.1, -0.02, 0.07, 0.07, 0.05, 0.21, 0.09, 0.02, 0.04, 0.01, 0.02, 0.05, 0.05, 0.12, 0.14, 0.04, 0.06, 0.05, 0.02, 0.01, 0.1, 0.25, 0.01, -0.06, -0.01, -0.01, -0.01, -0.01, 0.12, 0.11, 0.02, 0.01, 0.15, 0.02, 0.05, 0.04, 0.09, 0.03, 0.0, -0.01, 0.08, 0.12, 0.1, 0.04, 0.09, -0.05, -0.07, 0.0, -0.03, -0.03, -0.03, -0.04, 0.0, 0.03, 0.07, 0.02, -0.09, 0.05, 0.08, 0.11, 0.15, 0.07, 0.1, -0.09, 0.0, -0.03, 0.02, 0.13, 0.08, 0.01, -0.17, 0.04, 0.18, -0.01, -0.14, -0.03, -0.11, -0.07, -0.07, 0.14, 0.11, 0.02, -0.03, -0.07, -0.08, -0.06, -0.1, 0.03, -0.17, -0.14, -0.14, 0.01, -0.09, 0.13, 0.04, 0.09, -0.12, 0.03, 0.05, 0.02, -0.11, -0.05, -0.02, -0.02, -0.13, -0.08, -0.03, -0.06, -0.04, -0.02, -0.06, -0.01, -0.01, 0.0, -0.01, -0.01, -0.01, -0.02, -0.15, 0.06, 0.08, 0.05, 0.05, 0.1, 0.01, 0.14, 0.0, 0.01, 0.01, -0.09, -0.04, -0.1, 0.0, -0.12, -0.15, -0.01, 0.11, -0.15};
	//private static int iter = 0;
	//public Market market = null;
	private StartupApplet applet = null;
	private int delay = 0;
	private boolean requestStop = false;
	private GUIUpdateNotifier doGUIUpdate = null;
	public boolean running = false;
	
	public StockTradeThread( StartupApplet applet )
	{
		this.applet = applet;
		doGUIUpdate = new GUIUpdateNotifier( applet );
	}
	
	public void setDelay( int delay )
	{
		this.delay = delay;
	}
	
	public void requestStop()
	{
		requestStop = true;
	}
	
	public void run()
	{
		running = true;
		while ( !requestStop )
		{
			while ( applet.readingData )
			{
				try { sleep( 100 ); }
				catch ( Exception ex ) { ex.printStackTrace(); }
			}
									
			//do shopping
			System.out.println("Shop pradedam");
			shop( applet );
			System.out.println("Shop baigiam");
			
			//update GUI
			try { SwingUtilities.invokeAndWait( doGUIUpdate ); }
			catch ( Exception ex )
			{
				System.out.println("Shop 3");
				ex.printStackTrace();
				System.out.println("Shop 4");
			}
			
			//wait
			try { sleep( delay ); }
			catch ( Exception ex )
			{
				System.out.println("Shop 5");
				ex.printStackTrace();
				System.out.println("Shop 6");
			}
		}
		System.out.println("Shop 7");
		running = false;
	}
	
	public static void shop( StartupApplet applet )
	{
		
		for (int stockNr = 0; stockNr < applet.stockCount; stockNr++)
				{
				doShopping(applet, stockNr, false, false, 0, 0);
				};
		
	}
	
	/**
	 * pirkimo - pardavimo logika
	 */
	public static void doShopping(StartupApplet applet, int stockNo, boolean forcesell, boolean forcebuy, int forcingCustomer, int forceIndex)
	{
				
		System.out.println ("--------------------------------------");
		int forceIndexB = 0; //skaiciavimui
		int forceIndexA = 0; 

		Random rNorm = new Random( (new Date()).getTime() );
		double dEps = ((Double)applet.volatility.get(stockNo)).doubleValue() * rNorm.nextGaussian();
		//double dEps = dEps1[iter++];
	
		
		int iIterN = applet.stocksPrices[stockNo].getIterNr() + 1; // Iteracijos numeris
		System.out.println("===start of day" + iIterN + "===");

		//1 zingsnis. nustatom Zopen, kuri = Zclose

		double price = applet.stocksPricesT[stockNo].get(iIterN-1);
		double priceT = price; //tarpine kaina
		double dBmax=price; //paskutiniai sitie kainos nustatymui po sandorio
		double dSmin=price;
		double dSor=price;

		int CREDIT= applet.MAX_CAN_HAVE_CREDIT;
		int STOCK = applet.MAX_CAN_HAVE_STOCK;
		int tarp1 = 0;
		int tarp2 =0;

		System.out.println("  pries sprendimus ienos ryta  PRICE " + price + "  forceIndex " + forceIndex);
		
		
		applet.stocksPrices[stockNo].set(iIterN, price);



		// 2 zingsnis. Agentai prognozuoja, koks bus Zopen(t+1)
		// MBA Apskaiciuojami klientu kainu slenksciai

		for (int j = 0; j < applet.firmCount; j++)
		{
			SRGMCustomer customer = (SRGMCustomer)applet.customers.get(j);
			
			//jei AR parametras p>0 tai naudoti AR modeli
			if ( customer.iStrategy > 0 && iIterN > 1)
			{
				if (customer.iStrategy<10)
				{
					AR model = new AR(applet.stocksPrices[stockNo].toArray(), iIterN, customer.iStrategy );
					if (model.predict()<0) {customer.dZpred[stockNo]=0.1d;}
					else {customer.dZpred[stockNo] = model.predict();};
				}
				else // SOROS
				{customer.dZpred[stockNo] = applet.stocksPrices[stockNo].get(iIterN)*1.2;};
			}
			//Wiener'io procesas
			else
			{
				customer.dZpred[stockNo] = applet.stocksPrices[stockNo].get(iIterN);
			};

			// Beta - spejamas kainos pokytis
			double dBeta = (customer.dZpred[stockNo] - applet.stocksPrices[stockNo].get(iIterN))/ (applet.stocksPrices[stockNo].get(iIterN));	

			// Expected profit - pagal formulyna tai D, tiketinas pelnas po palukanu, 
			//jei kainos prognoze pasitvirtins. gali buti <>0 
			// tai santykinis dydis, procentine israiska, pz 0,1 reiskia, kad tikiuosi 10% pelno
			double dExpectedProfit = dBeta + ((Double)applet.dividend.get(stockNo)).doubleValue() - applet.yieldOfCd;
			System.out.println(" Eprofit " + dExpectedProfit + "  for " + j + "  Beta " +dBeta);


			customer.dZbuy[stockNo].set(iIterN,  (-((Double)applet.kBuy.get(j)).doubleValue()  +1+dExpectedProfit) * applet.stocksPrices[stockNo].get(iIterN));
			customer.dZsell[stockNo].set(iIterN, (-((Double)applet.kSell.get(j)).doubleValue() +1+dExpectedProfit) * applet.stocksPrices[stockNo].get(iIterN));
			customer.dZbuy1[stockNo].set(iIterN, (-((Double)applet.kBuy1.get(j)).doubleValue() +1+dExpectedProfit) * applet.stocksPrices[stockNo].get(iIterN));			
			customer.dZsell1[stockNo].set(iIterN, (-((Double)applet.kSell1.get(j)).doubleValue() +1+dExpectedProfit) * applet.stocksPrices[stockNo].get(iIterN));
			customer.dZbuy2[stockNo].set(iIterN, (-((Double)applet.kBuy2.get(j)).doubleValue() +1+dExpectedProfit) * applet.stocksPrices[stockNo].get(iIterN));
			customer.dZsell2[stockNo].set(iIterN, (-((Double)applet.kSell2.get(j)).doubleValue() +1+dExpectedProfit) * applet.stocksPrices[stockNo].get(iIterN));

			System.out.println("Agentas " + j + "  kBuy " + ((Double)applet.kBuy.get(j)).doubleValue()+ "  kSell " + ((Double)applet.kSell.get(j)).doubleValue()+"  dZbuy "+customer.dZbuy[stockNo].get(iIterN) + "  dZsel" + customer.dZsell[stockNo].get(iIterN));

			customer.dProfAll[stockNo] = customer.dProfit[stockNo] + ((Integer)customer.iN.get(stockNo)).intValue() * applet.stocksPrices[stockNo].get(iIterN);

			customer.Delta[stockNo] = dExpectedProfit;

			applet.customers.set(j, customer);
		};

		//ziurim, ka turim		
		for (int i=0; i<applet.firmCount; i++)
		{
			System.out.println("customer:"+i+"   buy:"+((SRGMCustomer)applet.customers.get(i)).dZbuy[stockNo].get(iIterN)+"   buy1:"+((SRGMCustomer)applet.customers.get(i)).dZbuy1[stockNo].get(iIterN)+"   buy2:"+((SRGMCustomer)applet.customers.get(i)).dZbuy2[stockNo].get(iIterN)+"   sell:"+((SRGMCustomer)applet.customers.get(i)).dZsell[stockNo].get(iIterN) +"   sell1:"+((SRGMCustomer)applet.customers.get(i)).dZsell1[stockNo].get(iIterN)+"   sell2:"+((SRGMCustomer)applet.customers.get(i)).dZsell2[stockNo].get(iIterN));
		};
		
		// 3 zingsnis. 
		// --- Akciju pirkimas pardavimas ---
		
		for (int j = 0; j < applet.firmCount; j++)
		{
			int customeriN = ((Integer)((SRGMCustomer)applet.customers.get(j)).iN.get(stockNo)).intValue();
		
			System.out.println("j cikle pries ieinant  Forceind "+forceIndex+"  ForceindA "+forceIndexA+"  ForceindB "+forceIndexB);

			if (forceIndex==0)
			{
				System.out.println(" CustomerIn" + customeriN);
				double DD=((SRGMCustomer)applet.customers.get(j)).Delta[stockNo];
				System.out.println(" DD" + DD);
				
				if (DD<=((Double)applet.kSell2.get(j)).doubleValue()) 
				{
					forceIndexA = customeriN; 
					priceT= ((SRGMCustomer)applet.customers.get(j)).dZsell2[stockNo].get(iIterN);
					System.out.println(j + " : D<=KSell2 ");
				}
				else if (DD<=((Double)applet.kSell1.get(j)).doubleValue()) 
				{ 
					forceIndexA = (int)customeriN/2; 
					priceT= ((SRGMCustomer)applet.customers.get(j)).dZsell1[stockNo].get(iIterN);
					System.out.println(j + " :  D<=Ksell1");
				}
				else if (DD<=((Double)applet.kSell.get(j)).doubleValue()) 
				{
					forceIndexA = (int)customeriN/3;
					priceT= ((SRGMCustomer)applet.customers.get(j)).dZsell[stockNo].get(iIterN);
					System.out.println(j + " : D<=KSell"); 
				}
				else {forceIndexA=0;};

				if (j==0) 				{
					CREDIT=CREDIT*applet.Soros_modifier*applet.Soros_modifier;
					STOCK=STOCK*applet.Soros_modifier;
				}
				else {CREDIT=applet.MAX_CAN_HAVE_CREDIT; STOCK=applet.MAX_CAN_HAVE_STOCK;};
	
				if (DD>=((Double)applet.kBuy2.get(j)).doubleValue()) 
				{ 				
					forceIndexB= (int)((((SRGMCustomer)applet.customers.get(j)).dProfit[stockNo]-CREDIT)/price); 
					priceT= ((SRGMCustomer)applet.customers.get(j)).dZbuy2[stockNo].get(iIterN);
					System.out.println(j + " : D>=Kbuy2 " + "   prof " + (int)(((SRGMCustomer)applet.customers.get(j)).dProfit[stockNo]) + " MAX_CAN_HAVE_CREDIT" + CREDIT);
				}
				else if (DD>=((Double)applet.kBuy1.get(j)).doubleValue())
				{
					forceIndexB = (int)(((((SRGMCustomer)applet.customers.get(j)).dProfit[stockNo]-CREDIT)/2)/price);
					priceT= ((SRGMCustomer)applet.customers.get(j)).dZbuy1[stockNo].get(iIterN);
					System.out.println(j + " : D<=Kbuy1 " + "   prof " + (int)(((SRGMCustomer)applet.customers.get(j)).dProfit[stockNo]) + " MAX_CAN_HAVE_CREDIT" + CREDIT);
				}
				else if (DD>=((Double)applet.kBuy.get(j)).doubleValue()) 
				{
					forceIndexB= (int)(((((SRGMCustomer)applet.customers.get(j)).dProfit[stockNo]-CREDIT)/3)/price); 
					priceT= ((SRGMCustomer)applet.customers.get(j)).dZbuy[stockNo].get(iIterN);
					System.out.println(j + " : D>=Kbuy " + "   prof " + (int)(((SRGMCustomer)applet.customers.get(j)).dProfit[stockNo]) + " MAX_CAN_HAVE_CREDIT" + CREDIT);
				}
				else {forceIndexB=0;};

				System.out.println("Forceind "+forceIndex+"  ForceindA "+forceIndexA+"  ForceindB "+forceIndexB+" price"+price+" priceT"+priceT);
			
				if (forceIndexB<0) {forceIndexB = 0;};
				if (priceT<=0) {priceT=0.1d;};
			}
			else
			{System.out.println(" **************kodel NEIejo ? " );};
	
			// Jei j nenupirko
			if ((forceIndexA<=0)&&(forceIndexB<=0)&&(forceIndex<=0))
			{
				System.out.println(j + " makes no action id day " + iIterN);
			}
			else // j klietas perka arba parduoda
			{
				//pardavimas priverstinis arba savo noru, priverstinis tik jei forcing customer
				if ((forceIndexA >0) || (forcesell&&(j==forcingCustomer)))
				{
					tarp1++;
					if ((j==0)&&(forceIndexA >0)) {tarp2++;dSor=priceT;};
					if (forceIndex>0) {forceIndexA=forceIndex;};
					SRGMCustomer customer = (SRGMCustomer)applet.customers.get(j);
					Integer IN = (Integer)customer.iN.get(stockNo);
					int iN = IN.intValue();
	
					for (int i=1; i<=forceIndexA; i++) //kiek parduos vienetais
					{
						// perskaiciuojamas akciju kiekis
						if ((IN.intValue())>0) //tikrinam kol turi ka parduot - parduoda
						{
							((SRGMCustomer)applet.customers.get(j)).dProfit[stockNo] +=price;
							iN = iN - 1;
						}
					}
					//applet.stocksPrices[stockNo].set(iIterN, price + dEps);
					customer.iN.set(stockNo, new Integer(iN) );
					System.out.println(j + " sell action "  + (int)(IN.intValue()-iN)+" "+forceIndexA);
					System.out.println("akcijos kaina bus po to se: "+ priceT);
				};
	
				// perka akcijas, savo noru arba priverstinai
				if ((forceIndexB>0) || (forcebuy&&(j==forcingCustomer)))
				{
					tarp1++;
					if ((j==0)&&(forceIndexB >0)) {tarp2++;dSor=priceT;};
					// perskaiciuojami kiekiai
					if (forceIndex>0) {forceIndexB=forceIndex;};
					SRGMCustomer customer = (SRGMCustomer)applet.customers.get(j);
					Integer IN = (Integer)customer.iN.get(stockNo);
					int iN = IN.intValue();
			
					for (int i = 1; i <= forceIndexB; i++)
					{
						//if (iN < STOCK)
						//{
							((SRGMCustomer)applet.customers.get(j)).dProfit[stockNo] -=price;
							iN = iN + 1;
						//}
					}
					customer.iN.set(stockNo, new Integer(iN) );
					System.out.println(j + " buy action " + (int)(iN-IN.intValue())+" "+forceIndexB);
					System.out.println("akcijos kaina bus po to bu: "+ priceT);
				};
				// jei ir perka, ir parduoda, tada imam vidrine kaina tarp abieju
				forceIndexA=0;
				forceIndexB=0;
				//forceIndex=0;
				if (tarp1==1) {dSmin=priceT; dBmax=priceT;}
				else 
				{
					if (priceT<=dSmin) {dSmin=priceT;};
					if (priceT>=dBmax) {dBmax=priceT;};
				};
					priceT=price;
				
			};

			
		};
		
		//4 zingsnis
		//kainos pakeitimas dienos pabaigoje Zclose nustatymas, kur but Zopen(t+1) = Zclose(t)

		if (tarp1==0) //nebuvo nei vieno pirkimo nei vieno pardavimo
		{
			priceT = price + dEps; 
			if (priceT<=0) {priceT=0.01d;};
			applet.stocksPricesT[stockNo].set(iIterN, priceT); //nustatom kaina dienos t+1 pabaigai, 
									//kuri bus atidarmo kaina diena t+2
									//siandien yra diena t+1

			System.out.println(" priceT " + priceT + "  dEps" + dEps + "  tarp1 " + tarp1);
		}
		else if (tarp2>0) //jei sandorius dare Sorosas ir jis juos dare savo noru
		{
			System.out.println(" dSor " + dSor + "  dEps" + dEps + "  tarp2 " + tarp2);
			dSor=dSor+dEps;
			applet.stocksPricesT[stockNo].set(iIterN, dSor);
		}
		else // jei kiti dare sandorius, bet Sorosas ne
		{
			priceT=(dBmax-dSmin)*Math.random() + dSmin;
			System.out.println(" darom vidurki, kuris yra : " +priceT); 
			applet.stocksPricesT[stockNo].set(iIterN, priceT);
			System.out.println(" priceT " + priceT + "  Math.random()" + Math.random() + " dSmin " + dSmin + "  dBmax " + dBmax);	
		};
		tarp1=0;
		tarp2=0;
		System.out.println("galutine dabartine akcijos kaina vidutine : "+ applet.stocksPricesT[stockNo].get(iIterN) + " open kaina " + applet.stocksPrices[stockNo].get(iIterN));
				

	};

}

final class GUIUpdateNotifier implements Runnable
{
	
	StartupApplet applet = null;
	
	
	public GUIUpdateNotifier( StartupApplet applet )
	{
		this.applet = applet;
	}
	
	
    public void run()
    {
		applet.updateGUI();
    }
}
