//WalrasModel.java
package lt.ktu.gmj.tasks;

import lt.ktu.gmj.*;
import lt.ktu.gmj.propertySheet.*;

public class WalrasModel implements Task 
{
	public WalrasDomain domain = new WalrasDomain();
	public BuyQuantityByPrice buyQuantity = null;
	public BestParameters bestParams = null;
	double bestdiff = 999999D;
	public double
    	B1 = 1,
    	B2 = 1,
    	B11 = 0.1,
    	B22 = 0.1,
    	B12 = 0.1,
    	B21 = 0.1,
    	C0 = 20,
    	Z01 = 1, Z11 = 1, Z12 = 1,
    	Z02 = 1, Z21 = 1, Z22 = 1,
    	Precision = 33.3, Precision_Analyzer = 10.0,
    	A = 20,
    	Reg = 1;
	public int Iteration_best;
	public int Iteration_current;
	
	public int pointnum[];
	
	public ModelValues modelValues = new ModelValues();
	
	public BestParameters getBestParams() { return bestParams; }
	
	public BuyQuantityByPrice getBuyQuantity() { return buyQuantity; } 

//	public double getServerProfit(int nr) { return market.GetProfit(nr); }

	public void customize(PropertyManager manager) 
	{
	    manager.add(new DoubleProperty("B1 (for Sale)", new WalrasModelB1Provider(this), 0.001, 100));
	    manager.add(new DoubleProperty("B2 (for Sale)", new WalrasModelB2Provider(this), 0.001, 100));
	    manager.add(new DoubleProperty("B11 (Own resource )", new WalrasModelB11Provider(this), 0.001, 100));
	    manager.add(new DoubleProperty("B22 (Own resource )", new WalrasModelB22Provider(this), 0.001, 100));
	    manager.add(new DoubleProperty("B12 (Min resource other )", new WalrasModelB12Provider(this), 0.001, 100));
	    manager.add(new DoubleProperty("B21 (Min resource other)", new WalrasModelB21Provider(this), 0.001, 100));
	    manager.add(new DoubleProperty("C0 (critical cost, when customer goes away)", new WalrasModelC0Provider(this), 0.0, 100));
	    manager.add(new DoubleProperty("A (number of clients per time unit)", new WalrasModelAProvider(this), 1, 100));
	    manager.add(new DoubleProperty("Z01 (1-st server resources usefulness coefficient (value systems differ...) )", new WalrasModelZ01Provider(this), 0.0, 10));
	    manager.add(new DoubleProperty("Z11 (1-st server resource x1 coefficient of usefulness)", new WalrasModelZ11Provider(this), 0.0, 10));
	    manager.add(new DoubleProperty("Z21 (1-st server resource x2 coefficient of usefulness)", new WalrasModelZ21Provider(this), 0.0, 10));
	    manager.add(new DoubleProperty("Z02 (2-nd server resources usefulness coefficient)", new WalrasModelZ02Provider(this), 0.0, 10));
	    manager.add(new DoubleProperty("Z12 (2-nd server resource x1 coefficient of usefulness)", new WalrasModelZ12Provider(this), 0.0, 10));
	    manager.add(new DoubleProperty("Z22 (2-nd server resource x2 coefficient of usefulness)", new WalrasModelZ22Provider(this), 0.0, 10));
	    manager.add(new DoubleProperty("Accuracy % (Accuracy for Equilibrium)", new WalrasModelP2StepProvider(this), 0.001, 100));
	    manager.add(new DoubleProperty("Accuracy % (Accuracy for Analyzer)", new WalrasModelP3StepProvider(this), 0.001, 100));
	    manager.add(new DoubleProperty("Regular client come 1 means T=1/A T_i=1/Wi", new WalrasModelRegularProvider(this),0,1));
	}

	// gWalrasModel is used to get data from WalrasModel into Analyzer
	public static WalrasModel gWalrasModel = null;

	public static WalrasModel getWalrasModel() { return gWalrasModel; }

//	public WalrasMarket getWalrasMarket() { return market; }
	public double GetB1() { return modelValues.B1; }
	public double GetB2() { return modelValues.B2; }

	public WalrasMarket ProcessServers(double x0, double x1, double x2, double x3, double x4, double x5, double x6, double x7) 
	{
		Point pt = new Point(domain());
		pt.x[0] = x2;//p1
		pt.x[1] = x5;//P2
		pt.x[2] = x1;//Y1
		pt.x[3] = x4;//Y2
		
		WalrasMarket market = new WalrasMarket(pt, modelValues, x6, x0, x7, x3);
		market.RunWalrasMarket();
		return market;
	}
/*
	public double GetX12() { return market.matrix_changing[0][2]; }
	public double GetX21() { return market.matrix_changing[1][2]; }
*/
	public WalrasModel() 
	{
            System.out.println("-------create model-------------");
            gWalrasModel = this;
	}

	public Domain domain() { return domain; }

	double diff, tempdiff;

	public double f(Point pt) 
	{

                        System.out.println("-----------------------------------------");
			System.out.println("Call F()");
			System.out.println("pt = " + pt.x[0] + " " + pt.x[1] + " " + pt.x[2] + " " + pt.x[3] + " " );
		if (modelValues.Changed(this)) 
		{
			modelValues.SetValues(this);
			buyQuantity = new BuyQuantityByPrice(modelValues);
			//if (bestParams == null )
                            bestParams = new BestParameters();
			
			pointnum = new int[12];
			for (int i = 0; i < 11; i++)
				pointnum[i] = 0;
			
			for (double i = domain().min[2]; i <= domain().max[2]; i += (domain().max[2] - domain().min[2]) / (100 / this.Precision_Analyzer))
				pointnum[0] = pointnum[0] + 1;

			for (double i = domain().min[3]; i <= domain().max[3]; i += (domain().max[3] - domain().min[3]) / (100 / this.Precision_Analyzer))
				pointnum[1] = pointnum[1] + 1;
      
			for (double i = domain().min[0]; i <= domain().max[0]; i += (domain().max[0] - domain().min[0]) / (100 / this.Precision_Analyzer) )
				pointnum[2] = pointnum[2] + 1;
      
			for (double i = domain().min[1]; i <= domain().max[1]; i += (domain().max[1] - domain().min[1]) / (100 / this.Precision_Analyzer)) 
				pointnum[3] = pointnum[3] + 1;
       
			for (double i = 0.0; i <= modelValues.B2; i += modelValues.SellableResourceStepFor2ndServer) 
				pointnum[4] = pointnum[4] + 1;
       
			for (double i = 0.0; i <= modelValues.B1; i += modelValues.SellableResourceStepFor1stServer) 
				pointnum[5] = pointnum[5] + 1;
       
			for (double i = 0.0; i <= modelValues.B2; i += modelValues.SellableResourceStepFor2ndServer) 
				pointnum[6] = pointnum[6] + 1;
       
			for (double i = 0.0; i <= modelValues.B1; i += modelValues.SellableResourceStepFor1stServer) 
				pointnum[7] = pointnum[7] + 1;
       
			for (double i = 0.0; i <= modelValues.B2; i += modelValues.SellableResourceStepFor2ndServer) 
				pointnum[8] = pointnum[8] + 1;
       
			for (double i = 0.0; i <= modelValues.B1; i += modelValues.SellableResourceStepFor1stServer) 
				pointnum[9] = pointnum[9] + 1;
       
			for (double i = 0.0; i <= modelValues.B2; i += modelValues.SellableResourceStepFor2ndServer) 
				pointnum[10] = pointnum[10] + 1;

			for (double i = 0.0; i <= modelValues.B1; i += modelValues.SellableResourceStepFor1stServer) 
				pointnum[11] = pointnum[11] + 1;
                                    
			Iteration_current = -1;

			System.out.println("-----------------------------------------");
			System.out.println("BEST RESULTS");
			System.out.println("-----------------------------------------");
		}


		BestParameters tempParameters = CalculateEqDriezhas(pt);

		Iteration_current = Iteration_current + 1;
		System.out.println("Iteration " + Iteration_current);
                System.out.println( "tempdiff = " + tempParameters.Diff );

		if (tempParameters.Diff < bestParams.Diff) 
		{
			bestParams.SetParameters(tempParameters);
      
			Iteration_best = Iteration_current;
                }
			System.out.println("-----------------------------------------");
			System.out.print("iter= ");
			System.out.println(Iteration_best);
			System.out.print("f= ");
			System.out.println(bestParams.Diff);
			System.out.print("X11= ");
			System.out.println(bestParams.X11);
			System.out.print("Y1= ");
			System.out.println(bestParams.Y1);
			System.out.print("P1= ");
			System.out.println(bestParams.P1);
			System.out.print("X22= ");
			System.out.println(bestParams.X22);
			System.out.print("Y2= ");
			System.out.println(bestParams.Y2);
			System.out.print("P2= ");
			System.out.println(bestParams.P2);
			System.out.print("X12= ");
			System.out.println(bestParams.X12);
			System.out.print("X21= ");
			System.out.println(bestParams.X21);
			System.out.println();
			System.out.print("W1= ");
			System.out.println(bestParams.W1);
			System.out.print("W2= ");
			System.out.println(bestParams.W2);
			System.out.print("U1= ");
			System.out.println(bestParams.U1);
			System.out.print("U2= ");
			System.out.println(bestParams.U2);
			System.out.print("served1= ");
			System.out.println(bestParams.Served1);
			System.out.print("served2= ");
			System.out.println(bestParams.Served2);
			System.out.print("gone= ");
			System.out.println(bestParams.Gone);
		

		return bestParams.Diff;
	}
	
	public BestParameters CalculateEqDriezhas(Point pt) 
	{
		double[] minBroken = new double[2];
		double[] minUnbroken = new double[2];
		
		OptimalContractInfo bq = buyQuantity.Get(pt.x[0], pt.x[2], pt.x[1], pt.x[3]);
                //System.out.println( "pt " + pt.x[0] + " " + pt.x[2] + " " + pt.x[1] + " " + pt.x[3] );
                //System.out.println( "bq " + bq.Profit1 + " " + bq.Profit2 + " " + bq.W1 + " " + bq.W2 );
		//public WalrasMarket (Point pt, ModelValues val, double X12, double X11, double X21, double X22)
                //WalrasMarket market = new WalrasMarket(pt, modelValues, bq.X12, modelValues.B1 - bq.X21, bq.X21, modelValues.B12 - bq.X12);
		//modelValues.B1 - bq2.X12, bq2.X21, modelValues.B2 - bq2.X21
                WalrasMarket market = new WalrasMarket(pt, modelValues, bq.X12, modelValues.B1 - bq.X12, bq.X21, modelValues.B2 - bq.X21);
		minBroken[0] = minUnbroken[0] = market.GetProfit(0);
		minBroken[1] = minUnbroken[1] = market.GetProfit(1);
		/******************************************
		 * Now let us say that one server keeps contract vector, but other breaks contract
		 * for maximizing its profit so let first server breaks contract
		 *******************************************/
		//igor
	     /******************************************
	     * Now let us say that one server keeps contract vector, but other breaks contract
	     * for maximizing its profit so let second server breaks contract
	     *******************************************/
		/*
                for (double P1 = modelValues.p1Min; P1 <= modelValues.p1Max; P1 += modelValues.StepP1) {
                    for (double P2 = modelValues.p2Min; P2 <= modelValues.p2Max; P2 += modelValues.StepP2){
                     for (double Y1 = modelValues.y1Min; Y1 <= modelValues.y1Max; Y1 += modelValues.StepY1) {   
                        for (double Y2 = modelValues.y2Min; Y2 <= modelValues.y2Max; Y2 += modelValues.StepY2) {
		        //look what's happening in  the market with fixed price p
		        Point ptNewPoint = new Point(pt);
		        ptNewPoint.x[3] = Y2; //Y2
		        ptNewPoint.x[1] = P2;
                        ptNewPoint.x[2] = Y1; //Y1
		        ptNewPoint.x[0] = P1;
		        //run resource quantity buy calcalation procedure depending on new y an p
		        //CalculateResourceBuyNashCriteria(ptNewPoint);
		        //run market
		        //OptimalContractInfo bq1 = buyQuantity.Get(ptNewPoint.x[0], ptNewPoint.x[2], ptNewPoint.x[1], ptNewPoint.x[3]);
                        OptimalContractInfo bq2 = buyQuantity.Get(ptNewPoint.x[0], ptNewPoint.x[2], ptNewPoint.x[1], ptNewPoint.x[3]);
		        //WalrasMarket marketBroken = new WalrasMarket(ptNewPoint, modelValues, bq1.X12, modelValues.B1 - bq1.X21, bq1.X21, modelValues.B12 - bq1.X12);
                        //WalrasMarket marketBroken = new WalrasMarket(ptNewPoint, modelValues, bq2.X12, modelValues.B1 - bq2.X21, bq2.X21, modelValues.B12 - bq2.X12);
                                            //public WalrasMarket (Point pt, ModelValues val, double X12, double X11, double X21, double X22)
                        WalrasMarket marketBroken = new WalrasMarket(ptNewPoint, modelValues, bq2.X12, modelValues.B1 - bq2.X12, bq2.X21, modelValues.B2 - bq2.X21);
		        marketBroken.RunWalrasMarket();
		        //RunWalrasMarket(ptNewPoint,bq2.X12,matrix[0][8] - bq2.X21,bq2.X21,matrix[1][8] - bq2.X12);
		        //has another minimum achieved?
		       if (minBroken[0] < marketBroken.GetProfit(0)) minBroken[0] = marketBroken.GetProfit(0);
                       if (minBroken[1] < marketBroken.GetProfit(1)) minBroken[1] = marketBroken.GetProfit(1);
		        
			} //y2
		} //y1
		//************************************************************************
                }//p2
                }//p1
                //igor
                 
                 */
                for (double P1 = modelValues.p1Min; P1 <= modelValues.p1Max; P1 += modelValues.StepP1)
		{
			for (double Y1 = modelValues.y1Min; Y1 <= modelValues.y1Max; Y1 += modelValues.StepY1)
			{
			Point ptNewPoint = new Point(pt);
		        ptNewPoint.x[2] = Y1; //Y1
		        ptNewPoint.x[0] = P1;
		        OptimalContractInfo bq1 = buyQuantity.Get(ptNewPoint.x[0], ptNewPoint.x[2], ptNewPoint.x[1], ptNewPoint.x[3]);
		        //run resource quantity buy calculation procedure depending on new y an p
		        //CalculateResourceBuyNashCriteria(ptNewPoint);
		        //run market with changed y and p (x_ij and x_ji already calculated by procedure above)

		        //WalrasMarket marketBroken = new WalrasMarket(ptNewPoint, modelValues, bq1.X12, modelValues.B1 - bq1.X21, bq1.X21, modelValues.B12 - bq1.X12);

                        WalrasMarket marketBroken =   new WalrasMarket(ptNewPoint, modelValues, bq1.X12, modelValues.B1 - bq1.X12, bq1.X21, modelValues.B2 - bq1.X21);
                        marketBroken.RunWalrasMarket();
		        //RunWalrasMarket(ptNewPoint,bq1.X12,matrix[0][8] - bq1.X21,bq1.X21,matrix[1][8] - bq.X12);
		        //has another minimum achieved?
		        if (minBroken[0] < marketBroken.GetProfit(0))
		        {
		        	minBroken[0] = marketBroken.GetProfit(0);
		        } //if profit
			} //y1
		} //p1

		//RestartWalrasMarket(pt,final_X_12,matrix[0][8] - final_X_21,final_X_21,matrix[1][8] - final_X_12);
	     /******************************************
	     * Now let us say that one server keeps contract vector, but other breaks contract
	     * for maximizing its profit so let second server breaks contract
	     *******************************************/
		for (double P2 = modelValues.p2Min; P2 <= modelValues.p2Max; P2 += modelValues.StepP2)
		{
			for (double Y2 = modelValues.y2Min; Y2 <= modelValues.y2Max; Y2 += modelValues.StepY2)
			{
		        //look what's happening in  the market with fixed price p
		        Point ptNewPoint = new Point(pt);
		        ptNewPoint.x[3] = Y2; //Y2
		        ptNewPoint.x[1] = P2;
		        //run resource quantity buy calcalation procedure depending on new y an p
		        //CalculateResourceBuyNashCriteria(ptNewPoint);
		        //run market
		        OptimalContractInfo bq2 = buyQuantity.Get(ptNewPoint.x[0], ptNewPoint.x[2], ptNewPoint.x[1], ptNewPoint.x[3]);
		        //                          new WalrasMarket(ptNewPoint, modelValues, bq2.X12, modelValues.B1 - bq2.X12, bq2.X21, modelValues.B2 - bq2.X21);
                        //WalrasMarket marketBroken = new WalrasMarket(ptNewPoint, modelValues, bq2.X12, modelValues.B1 - bq2.X21, bq2.X21, modelValues.B12 - bq2.X12);
                        WalrasMarket marketBroken =   new WalrasMarket(ptNewPoint, modelValues, bq2.X12, modelValues.B1 - bq2.X12, bq2.X21, modelValues.B2 - bq2.X21);
		        marketBroken.RunWalrasMarket();
		        //RunWalrasMarket(ptNewPoint,bq2.X12,matrix[0][8] - bq2.X21,bq2.X21,matrix[1][8] - bq2.X12);
		        //has another minimum achieved?
		        if (minBroken[1] < marketBroken.GetProfit(1))
		        {
		        	minBroken[1] = marketBroken.GetProfit(1);
		        } //if profit
			} //y2
		} //p2
		double dDifference = 0.0;
		//return what has been achieved
		/*
                for (int iServer = 0; iServer < 2; iServer++)
		{
			dDifference += Math.abs(minBroken[iServer] - minUnbroken[iServer]);
		}
                 * */

                dDifference = Math.abs( minBroken[0] - minUnbroken[0] + minBroken[1] - minUnbroken[1]  );
		BestParameters params = new BestParameters();
		params.Diff = MathUtils.roundToDecimals(dDifference);
		params.P1 = pt.x[0];
		params.P2 = pt.x[1];
		params.Y1 = pt.x[2];
                params.Y2 = pt.x[3];
                params.X12 = bq.X12;
                params.X11 = modelValues.B1 - bq.X21;
                params.X21 = bq.X21;
                params.X22 = modelValues.B2 - bq.X12;
                params.Served1 = bq.nServed1;
                params.Served2 = bq.nServed2;
                params.Gone = bq.nGone;
                params.W1 = bq.W1;
                params.W2 = bq.W2;
                params.U1 = bq.Profit1;
                params.U2 = bq.Profit2;
       	
		return params;
	}
};