package lt.ktu.gmj.tasks;

import java.util.Vector;

import lt.ktu.gmj.Point;

public class BuyQuantityByPrice
{
	private double final_X_12 = 0.0;
	private double final_X_21 = 0.0;
	private int nServed1 = 0;
	private int nServed2 = 0;
	private int nGone = 0;
	private double W1 = 0;
	private double W2 = 0;
	private double Profit1 = 0;
	private double Profit2 = 0;
	private ModelValues values = null;
	
	Vector<QuantityPriceElement> array;
	
	public BuyQuantityByPrice(ModelValues values)
	{
		array = new Vector<QuantityPriceElement>();
		this.values = new ModelValues(values);
	}
	
	public void Add(double P1, double Y1, double X21, double P2, double Y2, double X12, int nServed1, int nServed2, int nGone, double dW1, double dW2, double dProfit1, double dProfit2) 
	{ 
		double P1Rounded = MathUtils.roundToDecimals(P1);
		double Y1Rounded = MathUtils.roundToDecimals(Y1);
		double X21Rounded = MathUtils.roundToDecimals(X21);
		double P2Rounded = MathUtils.roundToDecimals(P2);
		double Y2Rounded = MathUtils.roundToDecimals(Y2);
		double X12Rounded = MathUtils.roundToDecimals(X12);
		array.add(new QuantityPriceElement(P1Rounded, Y1Rounded, X21Rounded, P2Rounded, Y2Rounded, X12Rounded, nServed1, nServed2, nGone, dW1, dW1, dProfit1, dProfit2)); 
	}
	
	public OptimalContractInfo Get(double P1, double Y1, double P2, double Y2)
	{
		double P1Rounded = MathUtils.roundToDecimals(P1);
		double Y1Rounded = MathUtils.roundToDecimals(Y1);
		double P2Rounded = MathUtils.roundToDecimals(P2);
		double Y2Rounded = MathUtils.roundToDecimals(Y2);
		
		for(int i = 0; i < array.size(); i++)
		{
			if(array.get(i).getP1() == P1Rounded && array.get(i).getY1() == Y1Rounded && 
			   array.get(i).getP2() == P2Rounded && array.get(i).getY2() == Y2Rounded)
			{
				QuantityPriceElement element = array.get(i);
				return new OptimalContractInfo(element.getX12(), element.getX21(), element.getServed1(), element.getServed2(), element.getGone(), element.getW1(), element.getW2(), element.getProfit1(), element.getProfit2());
			}
		}
		//work around to create new point since there is no empty constructor
		WalrasDomain domain = new WalrasDomain();
		Point pt = new Point(domain);
		pt.x[0] = P1;
		pt.x[1] = P2;
		pt.x[2] = Y1;
		pt.x[3] = Y2;
		CalculateResourceBuyNashCriteria(pt);
		
		Add(P1Rounded, Y1Rounded, MathUtils.roundToDecimals(final_X_21), P2Rounded, Y2Rounded, MathUtils.roundToDecimals(final_X_12), nServed1, nServed2, nGone, W1, W2, Profit1, Profit2);
		return new OptimalContractInfo(final_X_12, final_X_21, nServed1, nServed2, nGone, W1, W2, Profit1, Profit2);
	}
	
	public void CalculateResourceBuyNashCriteria(Point pt)
	{
		//this procedure calculates optimal X_12 and X_21 resource buy for each server
		//suggests contract resource prices and returns these where cheating is less relevant to

		double test = 999999999.9;
		double[] minBrokenX = new double[2];
		double[] minUnbrokenX = new double[2];
		//we suggest contract values for buy resources for each server
		for (double X21 = 0; X21 <= values.B1; X21 += values.SellableResourceStepFor1stServer) 
		{
			for (double X12 = 0; X12 <= values.B2; X12 += values.SellableResourceStepFor2ndServer) 
			{
				//netikslumai ...
                                WalrasMarket market = new WalrasMarket(pt, values, X12, values.B1 - X21, X21, values.B2 - X12);
				market.RunWalrasMarket();
				minBrokenX[1] = minUnbrokenX[1] = market.GetProfit(1);
				minBrokenX[0] = minUnbrokenX[0] = market.GetProfit(0);
				// first server breaks contract!!!!
				for (double X12_Broken = 0; X12_Broken <= values.B2; X12_Broken += values.SellableResourceStepFor2ndServer) 
				{
					WalrasMarket marketBroken = new WalrasMarket(pt, values, X12_Broken, values.B1 - X21, X21, values.B2 - X12_Broken);
					marketBroken.RunWalrasMarket();
					//calculate first server profit
					if (marketBroken.GetProfit(0) > minBrokenX[0]) 
					{
						minBrokenX[0] = marketBroken.GetProfit(0);
					} // if first break contract
				} // X12_Broken
				//breaking contract - second server!!
				for (double X21_Broken = 0; X21_Broken <= values.B1; X21_Broken += values.SellableResourceStepFor1stServer) 
				{
					//look how feels market
					WalrasMarket marketBroken = new WalrasMarket(pt, values, X12, values.B1 - X21_Broken, X21_Broken, values.B2 - X12);
					marketBroken.RunWalrasMarket();
					//check maximum profit
					if (marketBroken.GetProfit(1) > minBrokenX[1]) 
					{
						minBrokenX[1] = marketBroken.GetProfit(1);
					} //if second breaks
				} // second breaks contract
				// find what was achieved
				double sk = 0.0;
                                sk = Math.abs( minBrokenX[0] - minUnbrokenX[0] + minBrokenX[1] - minUnbrokenX[1] );
                                if (sk < test)
				{
					final_X_12 = X12; //x12
					final_X_21 = X21; //X21
					WalrasMarket marketFinal = new WalrasMarket(pt, values, final_X_12, values.B1 - final_X_21, final_X_21, values.B2 - final_X_12);
					marketFinal.RunWalrasMarket();
					nServed1 = marketFinal.served_1;
					nServed2 = marketFinal.served_2;
					nGone = marketFinal.ClientGone;
					test = sk;
				}
			} // X12
		} //X21
	}
}