//WalrasModel.java

package lt.ktu.gmj.tasks;

import lt.ktu.gmj.*;
import lt.ktu.gmj.propertySheet.*;
import lt.ktu.gmj.tasks.*;
import java.util.Random;
import java.util.Vector;

/**
 * <p>Title: </p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2003</p>
 * <p>Company: </p>
 * @author not attributable
 * @version 1.0
 */

class WalrasMarket {
  //Member variables
  private final int
      N_Servers = 2;
   public double
        Seed = 0.0;
  public double
      dCurrentTime = 0.0,
      Max_Client_Can_Pay = 40.0,
      Max_Resourse1 = 20.0, Max_Resourse2 = 20.0,
      Max_Resourse11 = 0.12, Max_Resourse22 = 0.2,
      Max_Resourse12 = 0.1, Max_Resourse21 = 0.1,
      Z01 = 1, Z11 = 1, Z21 = 1,
      Z02 = 1, Z12 = 1, Z22 = 1,
      Averange_Client_Come_Time = 20, Time_Units = 5,

      Precision = 50.0;
  public int
      ClientGone = 0,
      firstiteration = 0;

private static Random rand;

public double GetB1() {
    return Max_Resourse1;
  }

  public double GetB2() {
    return Max_Resourse2;
  }

  public double GetB11() {
    return Max_Resourse11;
  }
  public double GetB22() {
      return Max_Resourse22;
    }
    public double GetB12() {
      return Max_Resourse12;
    }
    public double GetB21() {
        return Max_Resourse21;
      }

  private WalrasDomain domain = null;
  public WalrasServer wlServers[];

  public WalrasMarket(WalrasDomain domain) {
    //domain reference
    this.domain = domain;
    //create servers vector
    this.wlServers = new WalrasServer[this.N_Servers];
    //initialization
    for (int iServer = 0; iServer < this.N_Servers; iServer++) {
      this.wlServers[iServer] = new WalrasServer();
    }
  }

//Seed funcion for testing monte carlo imitation

//Function sets server parameter
  private void SetServerParameters() {

    this.wlServers[0].SetserviceMinPrice(domain.min[2]);
    this.wlServers[0].SetserviceMaxPrice(domain.max[2]);
    this.wlServers[0].SetserviceMinResPrice(domain.min[0]);
    this.wlServers[0].SetserviceMaxResPrice(domain.max[0]);
    this.wlServers[0].SetServerMinSelRes(this.GetB21());
    this.wlServers[0].SetServerMaxSelRes(this.GetB1() - this.GetB11() );
    this.wlServers[0].SetMinOwnRes(0);
    this.wlServers[0].SetMaxOwnRes(this.GetB1());
    this.wlServers[1].SetserviceMinPrice(domain.min[3]);
    this.wlServers[1].SetserviceMaxPrice(domain.max[3]);
    this.wlServers[1].SetserviceMinResPrice(domain.min[1]);
    this.wlServers[1].SetserviceMaxResPrice(domain.max[1]);
    this.wlServers[1].SetServerMinSelRes(this.GetB12());
    this.wlServers[1].SetServerMaxSelRes(this.GetB2()- this.GetB22() );
    this.wlServers[1].SetMinOwnRes(0);
    this.wlServers[1].SetMaxOwnRes(this.GetB2());
    this.wlServers[0].SetPriceYStep(this.Precision);
    this.wlServers[0].SetPricePStep(this.Precision);
    this.wlServers[0].SetChangeQTStep(this.Precision);
    this.wlServers[1].SetPriceYStep(this.Precision);
    this.wlServers[1].SetPricePStep(this.Precision);
    this.wlServers[1].SetChangeQTStep(this.Precision);
    this.wlServers[0].SetZ0(Z01);
    this.wlServers[0].SetZ1(Z11);
    this.wlServers[0].SetZ2(Z12);
    this.wlServers[1].SetZ0(Z02);
    this.wlServers[1].SetZ1(Z21);
    this.wlServers[1].SetZ2(Z22);

  }

  public double tempP_1, tempX2_1, tempY_1, tempP, tempY, tempX2;
  public double[] DriezhasMarketstate = new double[4];
  double final_x_12;
  double final_x_21;
  double[] minBrokenX = new double[this.N_Servers];
  double[] minUnbrokenX = new double[this.N_Servers];
  double[] minBroken = new double[this.N_Servers];
  double[] minUnbroken = new double[this.N_Servers];

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 les relevant to
  //
  {
    final_x_12 = 0.0;
   final_x_21 = 0.0;
  double test = 999999999.9;
   //we suggest contract values for buy resources for each server
  for (double dCurrResBuy_2 = this.wlServers[0].GetServerMinSelRes();
               dCurrResBuy_2 <= this.wlServers[0].GetServerMaxSelRes();
               dCurrResBuy_2 += (this.wlServers[0].GetResBuyStep()))
          {

  for (double dCurrResBuy_1 = this.wlServers[1].GetServerMinSelRes();
           dCurrResBuy_1 <= this.wlServers[1].GetServerMaxSelRes();
           dCurrResBuy_1 += (this.wlServers[1].GetResBuyStep()))
      {


            this.DriezhasMarketstate[0] = (this.GetB1() - dCurrResBuy_2); //x11
            this.DriezhasMarketstate[1] = (dCurrResBuy_1); //x21
            this.DriezhasMarketstate[2] = (this.GetB2() - dCurrResBuy_1); //x22
            this.DriezhasMarketstate[3] = (dCurrResBuy_2); //X12

            RunWalrasMarket(pt);

            minBrokenX[1] = minUnbrokenX[1] = this.wlServers[1].GetProfit(this.wlServers[0].GetX2(), this.wlServers[0].GetP());
            minBrokenX[0] = minUnbrokenX[0] = this.wlServers[0].GetProfit(this.wlServers[1].GetX2(), this.wlServers[1].GetP());

            // first server breaks contract!!!!

            for (double dCurrResBuy_1_Broken = this.wlServers[1].GetServerMinSelRes();
                      dCurrResBuy_1_Broken <= this.wlServers[1].GetServerMaxSelRes();
                      dCurrResBuy_1_Broken += (this.wlServers[1].GetResBuyStep()))
                 {
  //           if ( dCurrResBuy_1_Broken==0 & dCurrResBuy_1==0 & dCurrResBuy_2==0)
  //           {
                   this.DriezhasMarketstate[1] = (dCurrResBuy_1_Broken); //x21
              //look how feels market
                   RunWalrasMarket(pt);
                  //calculate first server profit
                if   (this.wlServers[0].GetProfit(this.wlServers[1].GetX2(), this.wlServers[1].GetP()) >= minBrokenX[0])
                {
                       minBrokenX[0]  = this.wlServers[0].GetProfit(this.wlServers[1].GetX2(), this.wlServers[1].GetP());
                 } // if firs break contract
        //     }
               } // dCurrResBuy

             this.DriezhasMarketstate[0] = (this.GetB1() - dCurrResBuy_2); //x11
             this.DriezhasMarketstate[1] = (dCurrResBuy_1); //x21
             this.DriezhasMarketstate[2] = (this.GetB2() - dCurrResBuy_1); //x22
             this.DriezhasMarketstate[3] = (dCurrResBuy_2); //X12

          //breaking contract - second server!!

          for (double dCurrResBuy_2_Broken = this.wlServers[0].GetServerMinSelRes();
               dCurrResBuy_2_Broken <= this.wlServers[0].GetServerMaxSelRes();
               dCurrResBuy_2_Broken += (this.wlServers[0].GetResBuyStep()))
          {
 //           if ( dCurrResBuy_2_Broken==0 & dCurrResBuy_1==0 & dCurrResBuy_2==0)
 //            {
            this.DriezhasMarketstate[3] = (dCurrResBuy_2_Broken); //X12
           //look how feels marrket
            RunWalrasMarket(pt);
           //check maximum profit
           if  (this.wlServers[1].GetProfit(this.wlServers[0].GetX2(), this.wlServers[0].GetP()) >=  minBrokenX[1])
           {
                 minBrokenX[1] = this.wlServers[1].GetProfit(this.wlServers[0].GetX2(), this.wlServers[0].GetP());
           } //if second breaks
  //           }
         }// second breaks contract
        // find whats was achieved

        double sk = 0.0;
         for (int iServer = 0; iServer < this.N_Servers; iServer++)
             {
               sk += Math.abs(minBrokenX[iServer] - minUnbrokenX[iServer]);
             }
         if (sk < test){
                           final_x_12 = (dCurrResBuy_1); //x21
                           final_x_21 = (dCurrResBuy_2); //X12
                         test = sk;
                         }

    }// dCurrResBuy_1
  }//dCurrResBuy_2
    this.DriezhasMarketstate[0] = (this.GetB1() - final_x_21); //x11
    this.DriezhasMarketstate[1] = (final_x_12); //x21
    this.DriezhasMarketstate[2] = (this.GetB2() - final_x_12); //x22
    this.DriezhasMarketstate[3] = (final_x_21); //X12


}


public double CalculateEqDriezhas(Point pt) {
//run resource quantity buy calcalation procedure depending on new y an p from GMJ
   this.RestartWalrasMarket(pt);
   this.CalculateResourceBuyNashCriteria(pt);
//now we will model market state by breaking 'suggested' contract vetors p and y for both servers from GMJ
  this.RunWalrasMarket(pt);
  minBroken[0] = minUnbroken[0]= this.wlServers[0].GetProfit(this.wlServers[1].GetX2(), this.wlServers[1].GetP());
  minBroken[1] = minUnbroken[1]=this.wlServers[1].GetProfit(this.wlServers[0].GetX2(), this.wlServers[0].GetP());
  /******************************************
  * Now let us say that one server keeps contract vector, but other breaks contract
  * for maximizing its profit so let first server breaks conract
  *******************************************/
  for (double dCurrResPrice = this.wlServers[0].GetserviceMinResPrice(); dCurrResPrice <= this.wlServers[0].GetserviceMaxResPrice();dCurrResPrice += this.wlServers[0].GetResPStep())
  {
      for (double y = this.wlServers[0].GetserviceMinPrice(); y <= this.wlServers[0].GetserviceMaxPrice(); y += (this.wlServers[0].GetPriceYStep()))
      {
                    Point ptNewPoint = new Point(pt);
                    ptNewPoint.x[2] = y; //Y1
                    ptNewPoint.x[0] = dCurrResPrice;
                    //run resource quantity buy calcalation procedure depending on new y an p
                    this.CalculateResourceBuyNashCriteria(ptNewPoint);
                    //run market with changed y and p (x_ij and x_ji already calculated by procedure above)
                    this.RunWalrasMarket(ptNewPoint);
                    //has another minimum achieved?
                    if (minBroken[0] < this.wlServers[0].GetProfit(this.wlServers[1].GetX2(), this.wlServers[1].GetP()))
                    {
                      minBroken[0] = this.wlServers[0].GetProfit(this.wlServers[1].GetX2(), this.wlServers[1].GetP());
                      this.tempY = pt.x[2];
                      this.tempP = pt.x[0];
                    }//if profit
        }//y1
    }//p1
RestartWalrasMarket(pt);
   /******************************************
   * Now let us say that one server keeps contract vector, but other breaks contract
   * for maximizing its profit so let second server breaks conract
   *******************************************/
  for (double dCurrResPrice = this.wlServers[1].GetserviceMinResPrice(); dCurrResPrice <= this.wlServers[1].GetserviceMaxResPrice(); dCurrResPrice += this.wlServers[1].GetResPStep())
  {
    for (double y = this.wlServers[1].GetserviceMinPrice(); y <= this.wlServers[1].GetserviceMaxPrice(); y += (this.wlServers[1].GetPriceYStep()))
       {
        //look whats happening in  the market with fixed price p
                    Point ptNewPoint = new Point(pt);
                    ptNewPoint.x[3]  = y; //Y2
                    ptNewPoint.x[1] = dCurrResPrice;
                    //run resource quantity buy calcalation procedure depending on new y an p
                    this.CalculateResourceBuyNashCriteria(ptNewPoint);
                    //run market
                    this.RunWalrasMarket(ptNewPoint);
                    //has another minimum achieved?
                    if (minBroken[1] < this.wlServers[1].GetProfit(this.wlServers[0].GetX2(), this.wlServers[0].GetP()))
                    {
                      minBroken[1] = this.wlServers[1].GetProfit(this.wlServers[0].GetX2(), this.wlServers[0].GetP());
                      this.tempY_1 = pt.x[3];
                      this.tempP_1 = pt.x[1];
                    }//if profit
               }//y2
              }//p2
          //************************************************************************

    this.wlServers[0].SetP(tempP);
    this.wlServers[0].SetY(tempY);
    this.wlServers[0].SetX2(final_x_12);
    this.wlServers[0].SetX1(this.GetB1() - this.final_x_21);
    this.wlServers[1].SetP(tempP_1);
    this.wlServers[1].SetY(tempY_1);
    this.wlServers[1].SetX2(final_x_21);
    this.wlServers[1].SetX1(this.GetB2() - this.final_x_12);

    double dDifference =0.0;
    //return what has been achieved
    for (int iServer = 0; iServer < this.N_Servers; iServer++)
    {
      dDifference += Math.abs(minBroken[iServer] - minUnbroken[iServer]);
    }
    return dDifference;

  }

private void RestartWalrasMarket(Point pt) {
      SetServerParameters();
      //restart time
      this.dCurrentTime = 0.0;
      this.ClientGone = 0;
      // update market state
      this.wlServers[0].RestartWalrasServer();
      this.wlServers[0].SetX1(this.DriezhasMarketstate[0]); //x11
      this.wlServers[0].SetP(pt.x[0]); // p1
      this.wlServers[0].SetY(pt.x[2]); //y1
      this.wlServers[0].SetX2(this.DriezhasMarketstate[1]); //x21
      this.wlServers[1].RestartWalrasServer();
      this.wlServers[1].SetX1(this.DriezhasMarketstate[2]); //x22
      this.wlServers[1].SetP(pt.x[1]); //p2
      this.wlServers[1].SetX2(this.DriezhasMarketstate[3]); //x12
      this.wlServers[1].SetY(pt.x[3]); //y2

    }

  public void RunWalrasMarket(Point pt)
  {
    this.RestartWalrasMarket(pt);
    //share n clients
    int served_1 = 0;
    int served_2 = 0;
    if (this.Seed > 0.0)
          rand = new Random((long)(this.Seed));
        else rand = new Random();


    for (int m = 0; m < (int)(this.Time_Units); m++)
   {
      this.RestartWalrasMarket(pt);

      for (int iClient = 0; iClient < (int)(this.Averange_Client_Come_Time); iClient++)
      {
        this.dCurrentTime += ( -1.0 / this.Averange_Client_Come_Time) *
            (Math.log(1.0 - rand.nextDouble()));
        //serve clients
        for (int iServer = 0; iServer < this.N_Servers; iServer++)
        {
          this.wlServers[iServer].ServeClient(this.dCurrentTime);
        }
        //chose best server
        int iBest = ClientChoseServer();
        if (iBest == -1)
        {
          this.ClientGone++;
        }
        else
        {
          //Chosen server Acepts client
          double servetime = rand.nextDouble();
          this.wlServers[iBest].AcceptClient(this.dCurrentTime, servetime);
        }
      }//for iclient
served_1 += wlServers[0].nClientsServed+wlServers[0].TimesClientsWait.size();
served_2 += wlServers[1].nClientsServed+wlServers[1].TimesClientsWait.size();
    }//for time units
    wlServers[0].nClientsServed = (int)(served_1/Time_Units);
    wlServers[1].nClientsServed = (int)(served_2/Time_Units);
  }
  private int ClientChoseServer() {
    int iBest = 0; //-1 indicates that client abandom servers
    double dTotalPrice = this.wlServers[0].GetTotalServicePrice();
    double dTotalPrice2 = this.wlServers[1].GetTotalServicePrice();
    if (dTotalPrice2 < dTotalPrice) {
      iBest = 1;
    }
    // if prices equal then select server randomly
    if (dTotalPrice == dTotalPrice2) {
      double random = rand.nextDouble();
      if (random %1000 > 500) {
        iBest = 1;
      }
      else {
        iBest = 0;
      }
    }
    //minimal price

    if (Math.min(dTotalPrice,dTotalPrice2) > this.Max_Client_Can_Pay) {
      return -1; //client goes way
    }
    return iBest;
  }

};
//***********************
//end Walras Market
//***********************
//-----------------------------------------------------------------------------
//BEGIN WalrasDomain
//-----------------------------------------------------------------------------

  class WalrasDomain
      extends Domain {
    static final String[] dimensions = {
        "p1 ( 1-st server charges for 1-st resource)",
        "p2 (2-nd server charges for 2-nd resource)",
        "y1 (1-st server charge for the service)",
        "y2 (2-nd server charge for the service)"
    };

    public String[] dimensions() {
      return dimensions;
    }

    WalrasDomain() {
      min[0] = 0.0;
      max[0] = 10.0; // p1
      min[1] = 0.0;
      max[1] = 11.0; // p2
      min[2] = 0.0;
      max[2] = 25.0; //y1
      min[3] = 0.0;
      max[3] = 20.0; //y2
      defaultPoint.x[0] = (min[0] + max[0]) / 2;
      defaultPoint.x[1] = (min[1] + max[1]) / 2;
      defaultPoint.x[2] = (min[2] + max[2]) / 2;
      defaultPoint.x[3] = (min[3] + max[3]) / 2;
    }
  };

//-----------------------------------------------------------------------------
//END WalrasDomain
//-----------------------------------------------------------------------------

//****************************
//Clas walras server
//****************************
  class WalrasServer {
     public int nClientsServed = 0;
    private double
        _MinX1, _MaxX1, _X1,
        _MinY, _MaxY, _Y,
        _MinP, _MaxP, _P,
        _MinX2, _MaxX2, _X2,
        _Resourse_Step,
        _OwnRes_step,
        _Price_YStep,
        _Change_PStep,
        _Z0,
        _Z1,
        _Z2;
//time vectors
    public Vector TimesClientsWait = new Vector(0, 100);
    public Vector TimesClientGoAway = new Vector(0, 100);
//customizible vrialbles
    public WalrasServer( ) {
      _MinX1 = 0.0;
      _MaxX1 = 30.0;
      _X1 = 1.0;
      _MinY = 0.0;
      _MaxY = 20.0;
      _Y = 1.0;
      _MinP = 0.0;
      _MaxP = 30.0;
      _P = 1.0;
      _MinX2 = 0.0;
      _MaxX2 = 40.0;
      _X2 = 1.0;
      _Resourse_Step = 2;
      _Price_YStep = 1.5;
      _Change_PStep = 2.5;
      _OwnRes_step = 5;
      _Z0 = 1.0;
      _Z1 = 1.0;
      _Z2 = 1.0;
     }

//reseting servers quee
    public void RestartWalrasServer() {
      this.nClientsServed = 0;

//reset quee
      this.TimesClientsWait = new Vector(0, 100);
      this.TimesClientGoAway = new Vector(0, 100);

    }

//***********************
// minimal/ maximal servers price for the service
//********************************
      public double SetserviceMinPrice(double dNewServicePrice) {
        return this._MinY = dNewServicePrice;
      }

    public double GetserviceMinPrice() {
      return this._MinY;
    }

    public double SetserviceMaxPrice(double dNewServicePrice) {
      return this._MaxY = dNewServicePrice;
    }

    public double GetserviceMaxPrice() {
      return this._MaxY;
    }

//****************************

//******************
// buy resourses
//******************
       public double SetMinOwnRes(double dNewSetMinOwnRes) {
         return this._MinX1 = dNewSetMinOwnRes;
       }

    public double GetMinOwnRes() {
      return this._MinX1;
    }

    public double SetMaxOwnRes(double dNewSetMaxOwnRes) {
      return this._MaxX1 = dNewSetMaxOwnRes;
    }

    public double GetMaxOwnRes() {
      return this._MaxX1;
    }

//*****************************
//managing resourses prices
//*****************************
      public double SetserviceMinResPrice(double dNewServiceResPrice) {
        return this._MinP = dNewServiceResPrice;
      }

    public double GetserviceMinResPrice() {
      return this._MinP;
    }

    public double SetserviceMaxResPrice(double dNewServiceResPrice) {
      return this._MaxP = dNewServiceResPrice;
    }

    public double GetserviceMaxResPrice() {
      return this._MaxP;
    }

//*************Max/Min keeping resourses

     public double SetServerMinSelRes(double dNewServerResourceSel) {
       return this._MinX2 = dNewServerResourceSel;
     }

    public double GetServerMinSelRes() {
      return this._MinX2;
    }

    public double SetServerMaxSelRes(double dNewServerResourceSel) {
      return this._MaxX2 = dNewServerResourceSel;
    }

    public double GetServerMaxSelRes() {
      return this._MaxX2;
    }

//**************
//******** changing steps for the changable values
      public double SetPriceYStep(double dNewPriceYStep) {
        return this._Price_YStep = (this.GetserviceMaxPrice() -
                                    this.GetserviceMinPrice()) /
            ( (100) / dNewPriceYStep);
      }

    public double SetPricePStep(double dNewPricePStep) {
      return this._Change_PStep = (this.GetserviceMaxResPrice() -
                                   this.GetserviceMinResPrice()) /
          ( (100) / dNewPricePStep);
    }

    public double SetChangeQTStep(double dNewChangeQTStep) {
      return this._Resourse_Step = (this.GetServerMaxSelRes() -
                                    this.GetServerMinSelRes()) /
          ( (100) / dNewChangeQTStep);
    }

//*********end steps

//***Koeficients for the server resourse usefulness
      public double SetZ0(double dNewZ0) {
        return this._Z0 = dNewZ0;
      }

    public double SetZ1(double dNewZ1) {
      return this._Z1 = dNewZ1;
    }

    public double SetZ2(double dNewZ2) {
      return this._Z2 = dNewZ2;
    }

    public double GetZ0() {
      return this._Z0;
    }

    public double GetZ1() {
      return this._Z1;
    }

    public double GetZ2() {
      return this._Z2;
    }

//**********************end koef

//******************Curent server values from GMJ
      public double SetY(double dNewServiceY) {
        return this._Y = dNewServiceY;
      }

    public double SetP(double dNewServiceP) {
      return this._P = dNewServiceP;
    }

    public double SetX1(double dNewServiceX1) {
      return this._X1 = dNewServiceX1;
    }

    public double SetX2(double dNewServiceX2) {
      return this._X2 = dNewServiceX2;
    }

    public double GetX1() {
      return this._X1;
    }

    public double GetX2() {
      return this._X2;
    }

    public double GetY() {
      return this._Y;
    }

    public double GetP() {
      return this._P;
    }

//*******************************************
     public double GetPriceYStep() {
       return (this._Price_YStep);
     }

    public double GetResPStep() {
      return (this._Change_PStep);
    }

    public double GetResBuyStep() {
      return (this._Resourse_Step);
    }

    public double GetOwnResCangeStep() {
      return this._OwnRes_step;
    }

//*****************************************

     public void ServeClient(double dCurrentTime) {
       if (this.TimesClientsWait.size() == 0) {
         return;
       }
       //if there is a client serve him
       if (dCurrentTime >=
           ( ( (Double)this.TimesClientGoAway.elementAt(0)).doubleValue())) {
         this.nClientsServed++;
         //remove client from quee
         this.TimesClientsWait.removeElementAt(0);
         this.TimesClientGoAway.removeElementAt(0);
       }
     }

    public void AcceptClient(double dCurrentTime, double dservetime) {
//generate cliens time dependig on capasity
      double dTimeToWait = ( -1.0 / (this.GetX1() + this.GetX2()) * Math.log(1.0 - dservetime));
      //total time to wait
      double dTotalTimeToWait = dTimeToWait;
      if (this.TimesClientsWait.size() != 0) {
        //calcultae when clients will be served
        for (int iClient = 0; iClient < this.TimesClientsWait.size(); iClient++) {
          dTotalTimeToWait += ( (Double)this.TimesClientsWait.elementAt(iClient)).
              doubleValue();
        }
      }
//save client time of quit
      this.TimesClientGoAway.addElement(new Double(dTotalTimeToWait +
          dCurrentTime));
//save clients wait time
      this.TimesClientsWait.addElement(new Double(dTimeToWait));
    }
    public double GetTotalServicePrice() {
      return this.GetY() + (this.TimesClientsWait.size() / GetWi());

    }
    public double GetWi() {
      return this._Z0 *
          (1.0 -
           Math.exp( - (this.GetZ1() * (this.GetX1() + this.GetX2()))))*(1.0 -
           Math.exp( - (this.GetZ2() * (this.GetX1() + this.GetX2()))));
    }

    public double GetProfit(double sel, double buyPrice) {
      return (double) (this.nClientsServed *
          this.GetY() - this.GetX2() *buyPrice  + this.GetP() * sel);
    }
  };
class WalrasModelB1Provider
    extends SimplePropertyProvider {
  public WalrasModel _model;
  public WalrasModelB1Provider(WalrasModel _m) {
    _model = _m;
  }

  public Object get() {
    return new Double(_model.B1);
  }

  public void set(Object value) throws InvalidPropertyException {
    _model.B1 = ( (Double) value).doubleValue();
  }
};

class WalrasModelB11Provider
    extends SimplePropertyProvider {
  public WalrasModel _model;
  public WalrasModelB11Provider(WalrasModel _m) {
    _model = _m;
  }

  public Object get() {
    return new Double(_model.B11);
  }

  public void set(Object value) throws InvalidPropertyException {
    _model.B11 = ( (Double) value).doubleValue();
  }
};

class WalrasModelB2Provider
    extends SimplePropertyProvider {
  public WalrasModel _model;
  public WalrasModelB2Provider(WalrasModel _m) {
    _model = _m;
  }

  public Object get() {
    return new Double(_model.B2);
  }

  public void set(Object value) throws InvalidPropertyException {
    _model.B2 = ( (Double) value).doubleValue();
  }
};

class WalrasModelB22Provider
    extends SimplePropertyProvider {
  public WalrasModel _model;
  public WalrasModelB22Provider(WalrasModel _m) {
    _model = _m;
  }

  public Object get() {
    return new Double(_model.B22);
  }

  public void set(Object value) throws InvalidPropertyException {
    _model.B22 = ( (Double) value).doubleValue();
  }
};
class WalrasModelB12Provider
    extends SimplePropertyProvider {
  public WalrasModel _model;
  public WalrasModelB12Provider(WalrasModel _m) {
    _model = _m;
  }

  public Object get() {
    return new Double(_model.B12);
  }

  public void set(Object value) throws InvalidPropertyException {
    _model.B12 = ( (Double) value).doubleValue();
  }
};
class WalrasModelB21Provider
    extends SimplePropertyProvider {
  public WalrasModel _model;
  public WalrasModelB21Provider(WalrasModel _m) {
    _model = _m;
  }

  public Object get() {
    return new Double(_model.B21);
  }

  public void set(Object value) throws InvalidPropertyException {
    _model.B21 = ( (Double) value).doubleValue();
  }
};

class WalrasModelC0Provider
    extends SimplePropertyProvider {
  public WalrasModel _model;
  public WalrasModelC0Provider(WalrasModel _m) {
    _model = _m;
  }

  public Object get() {
    return new Double(_model.C0);
  }

  public void set(Object value) throws InvalidPropertyException {
    _model.C0 = ( (Double) value).doubleValue();
  }
};

class WalrasModelMProvider
    extends SimplePropertyProvider {
  public WalrasModel _model;
  public WalrasModelMProvider(WalrasModel _m) {
    _model = _m;
  }

  public Object get() {
    return new Double(_model.M);
  }

  public void set(Object value) throws InvalidPropertyException {
    _model.M = ( (Double) value).doubleValue();
  }
};
class WalrasModelAProvider
    extends SimplePropertyProvider {
  public WalrasModel _model;
  public WalrasModelAProvider(WalrasModel _m) {
    _model = _m;
  }

  public Object get() {
    return new Double(_model.A);
  }

  public void set(Object value) throws InvalidPropertyException {
    _model.A = ( (Double) value).doubleValue();
  }
};

class WalrasModelZ01Provider
    extends SimplePropertyProvider {
  public WalrasModel _model;
  public WalrasModelZ01Provider(WalrasModel _m) {
    _model = _m;
  }

  public Object get() {
    return new Double(_model.Z01);
  }

  public void set(Object value) throws InvalidPropertyException {
    _model.Z01 = ( (Double) value).doubleValue();
  }
};

class WalrasModelZ11Provider
    extends SimplePropertyProvider {
  public WalrasModel _model;
  public WalrasModelZ11Provider(WalrasModel _m) {
    _model = _m;
  }

  public Object get() {
    return new Double(_model.Z11);
  }

  public void set(Object value) throws InvalidPropertyException {
    _model.Z11 = ( (Double) value).doubleValue();
  }
};

class WalrasModelZ21Provider
    extends SimplePropertyProvider {
  public WalrasModel _model;
  public WalrasModelZ21Provider(WalrasModel _m) {
    _model = _m;
  }

  public Object get() {
    return new Double(_model.Z21);
  }

  public void set(Object value) throws InvalidPropertyException {
    _model.Z21 = ( (Double) value).doubleValue();
  }
};

class WalrasModelZ02Provider
    extends SimplePropertyProvider {
  public WalrasModel _model;
  public WalrasModelZ02Provider(WalrasModel _m) {
    _model = _m;
  }

  public Object get() {
    return new Double(_model.Z02);
  }

  public void set(Object value) throws InvalidPropertyException {
    _model.Z02 = ( (Double) value).doubleValue();
  }
};

class WalrasModelZ12Provider
    extends SimplePropertyProvider {
  public WalrasModel _model;
  public WalrasModelZ12Provider(WalrasModel _m) {
    _model = _m;
  }

  public Object get() {
    return new Double(_model.Z12);
  }

  public void set(Object value) throws InvalidPropertyException {
    _model.Z12 = ( (Double) value).doubleValue();
  }
};

class WalrasModelZ22Provider
    extends SimplePropertyProvider {
  public WalrasModel _model;
  public WalrasModelZ22Provider(WalrasModel _m) {
    _model = _m;
  }

  public Object get() {
    return new Double(_model.Z22);
  }

  public void set(Object value) throws InvalidPropertyException {
    _model.Z22 = ( (Double) value).doubleValue();
  }
};

class WalrasModelP2StepProvider
    extends SimplePropertyProvider {
  public WalrasModel _model;
  public WalrasModelP2StepProvider(WalrasModel _m) {
    _model = _m;
  }

  public Object get() {
    return new Double(_model.Precision);
  }

  public void set(Object value) throws InvalidPropertyException {
    _model.Precision = ( (Double) value).doubleValue();
  }
};
class WalrasModelSeedProvider
    extends SimplePropertyProvider {
  public WalrasModel _model;
  public WalrasModelSeedProvider(WalrasModel _m) {
    _model = _m;
  }

  public Object get() {
    return new Double(_model.Seed);
  }

  public void set(Object value) throws InvalidPropertyException {
    _model.Seed = ( (Double) value).doubleValue();
  }
};

class sLayerLogo {
   private static int willDisplay = 1;
   public sLayerLogo () {  if (willDisplay != 0) { System.out.println ("Task Walras Model. Created by Povilas Treigys  EISm - 3 VGTU, Vilnius, 2004"); willDisplay = 0; } }
};

//****************************
//Claas walras Model
//****************************
public class WalrasModel
      implements Task {
    public WalrasDomain domain = new WalrasDomain();
    public WalrasMarket market;
    private int firstTime;
    private static final sLayerLogo _WalrasLogo = new sLayerLogo ();
    double bestdiff = 999999D;
    public double
        B1 = 0.758, B2 = 0.774, C0 = 40,
        B11 = 0.3, B22 = 0.4,
        B12 = 0.1, B21 = 0.1,
        Z01 = 1, Z11 = 1, Z21 = 1,
        Z02 = 1, Z12 = 1, Z22 = 1,
        Precision = 50.0,
        A = 20,
        M = 1;
public double
         Seed = 0.0;

    public int ibestiter;
    public int curriter;
    public double bestX11;
    public double bestY1;
    public double bestP1;
    public double bestX22;
    public double bestY2;
    public double bestP2;
    public double bestX12;
    public double bestX21;
    public double bestv1;
    public double bestv2;
    public double bestu1;
    public double bestu2;
    public double bestf;
    public double bestcond1;
    public double bestcond2;
    public int bestiter;
    public int bestserved1;
    public int bestserved2;
    public int bestgone;

    public int pointnum[];

    public double getServerProfit(int nr) {
      return market.wlServers[nr].GetProfit(market.wlServers[nr + 1 -
                                            nr * 2].GetX2(),
                                            market.wlServers[nr + 1 -
                                            nr * 2].GetP());
    }

    public void customize(PropertyManager manager) {
      manager.add(new DoubleProperty("B1 (max 1-st resource capacity)",
                                     new WalrasModelB1Provider(this), 0.0, 100));
      manager.add(new DoubleProperty("B2 (max 2-nd resource capacity)",
                                     new WalrasModelB2Provider(this), 0.0, 100));
      manager.add(new DoubleProperty("B11 Own resource must be B1>B11)",new WalrasModelB11Provider(this),0.0, 99));
      manager.add(new DoubleProperty("B22 Own resource must be B2>B22)",new WalrasModelB22Provider(this),0.0, 99));
      manager.add(new DoubleProperty("B12 Buy resource must be between B1-B11)",new WalrasModelB12Provider(this),0.0, 99));
      manager.add(new DoubleProperty("B21 Buy resource must be between B2-B22)",new WalrasModelB21Provider(this),0.0, 99));
      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("M (number of conditional time units)",
                                  new WalrasModelMProvider(this), 1, 1000));
      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.01,
                                     1000));
      manager.add(new DoubleProperty("Seed (0.0 means Real Monte Carlo)",
                                     new WalrasModelSeedProvider(this), 0.0,
                                     1000000000));


    }

// gWalrasModel is used to get data from WalrasModel into Analyser
    public static WalrasModel gWalrasModel = null;

    public static WalrasModel getWalrasModel() {
      return gWalrasModel;
    }

    public WalrasMarket getWalrasMarket() {
      return market;
    }

    public void 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;
      pt.x[1] = x5;
     market.DriezhasMarketstate[0] = x0;
      pt.x[2] = x1;
     market.DriezhasMarketstate[1] = x7;
     market.DriezhasMarketstate[2] = x3;
     pt.x[3] = x4;
     market.DriezhasMarketstate[3] = x6;
     market.CalculateEqDriezhas(pt) ;

    }

    public WalrasModel() {
      firstTime = 1;

      gWalrasModel = this;
    }

    public Domain domain() {
      return domain;
    }


    double diff, tempdiff;

    public double f(Point pt) {

      if (firstTime == 1) {
        pointnum = new int[6];
        for (int i = 0; i < 6; i++) {
          pointnum[i] = 0;
        }
            for (double i=domain().min[2]; i<=domain().max[2]; i+=(domain().max[2]-domain().min[2])/(100/this.Precision)) pointnum[2]=pointnum[2]+1;
            for (double i=domain().min[3]; i<=domain().max[3]; i+=(domain().max[3]-domain().min[3])/(100/this.Precision)) pointnum[3]=pointnum[3]+1;
            for (double i=domain().min[0]; i<=domain().max[0]; i+=(domain().max[0]-domain().min[0])/(100/this.Precision)) pointnum[4]=pointnum[4]+1;
            for (double i=domain().min[1]; i<=domain().max[1]; i+=(domain().max[1]-domain().min[1])/(100/this.Precision)) pointnum[5]=pointnum[5]+1;


        market = new WalrasMarket(domain);
        market.firstiteration = 0;
        market.Max_Resourse1 = B1;
        market.Max_Resourse2 = B2;
        market.Max_Resourse11 = B11;
        market.Max_Resourse22 = B22;
        market.Max_Resourse12 = B12;
        market.Max_Resourse21 = B21;
        market.Max_Client_Can_Pay = C0;
        market.Averange_Client_Come_Time = A;
        market.Time_Units = M;
        market.Z01 = Z01;
        market.Z11 = Z11;
        market.Z21 = Z21;
        market.Z02 = Z02;
        market.Z12 = Z12;
        market.Z22 = Z22;
        market.Precision = Precision;
        market.Seed = Seed;
        curriter = -1;
        firstTime = 0;

        System.out.println("-----------------------------------------");
        System.out.println("BEST RESULTS");
        System.out.println("-----------------------------------------");
          }


              market.DriezhasMarketstate[0] = market.GetB1(); //x11
              market.DriezhasMarketstate[1] = market.GetB21(); //x21
              market.DriezhasMarketstate[2] = market.GetB2(); //x22
              market.DriezhasMarketstate[3] = market.GetB12(); //X12

      tempdiff = market.CalculateEqDriezhas(pt);
      diff = (double) Math.round(tempdiff * 1000) / (double) 1000;
      curriter = curriter + 1;
      System.out.println("Iteration " + curriter);

       if (tempdiff < bestdiff) {
        bestdiff = tempdiff;
        bestf = diff;
        bestX11 = (double) Math.round( (market.GetB1() - market.final_x_21) *
                                      1000D) / 1000D;
        bestY1 = (double) Math.round(pt.x[2]  * 1000D) / 1000D;
        bestP1 = (double) Math.round(pt.x[0] * 1000D) /
            1000D;
        bestX22 = (double) Math.round( (market.GetB2() - market.final_x_12) * 1000D) /
            1000D;
        bestY2 = (double) Math.round(pt.x[3] * 1000D) / 1000D;
        bestP2 = (double) Math.round(pt.x[1] * 1000D) / 1000D;
        bestX12 = (double) Math.round(market.final_x_21 * 1000D) / 1000D;
        bestX21 = (double) Math.round(market.final_x_12 * 1000D) / 1000D;
        bestv1 = (double) Math.round(market.wlServers[0].GetWi() * 1000D) /
            1000D;
        bestv2 = (double) Math.round(market.wlServers[1].GetWi() * 1000D) /
            1000D;
        bestu1 = (double) Math.round(market.wlServers[0].GetProfit(market.
            wlServers[1].GetX2(), market.wlServers[1].GetP()) * 1000D) / 1000D;
        bestu2 = (double) Math.round(market.wlServers[1].GetProfit(market.
            wlServers[0].GetX2(), market.wlServers[0].GetP()) * 1000D) / 1000D;
        double cond1 = (market.wlServers[0].GetX1() + market.wlServers[1].GetX2()) -
            market.GetB1();
        cond1 = (double) Math.round(cond1 * 1000D) / 1000D;
        double cond2 = (market.wlServers[1].GetX1() + market.wlServers[0].GetX2()) -
            market.GetB2();
        cond2 = (double) Math.round(cond2 * 1000D) / 1000D;
        bestcond1 = cond1;
        bestcond2 = cond2;
        bestiter = curriter;
        bestserved1 = market.wlServers[0].nClientsServed;// +
            //market.wlServers[0].TimesClientsWait.size();
        bestserved2 = market.wlServers[1].nClientsServed ;//+
            //market.wlServers[1].TimesClientsWait.size();
        bestgone = market.ClientGone;
        System.out.println("-----------------------------------------");
        System.out.print("iter= ");
        System.out.println(bestiter);
        System.out.print("f= ");
        System.out.println(bestf);
        System.out.print("X11= ");
        System.out.println(bestX11);
        System.out.print("Y1= ");
        System.out.println(bestY1);
        System.out.print("P1= ");
        System.out.println(bestP1);
        System.out.print("X22= ");
        System.out.println(bestX22);
        System.out.print("Y2= ");
        System.out.println(bestY2);
        System.out.print("P2= ");
        System.out.println(bestP2);
        System.out.print("X12= ");
        System.out.println(bestX12);
        System.out.print("X21= ");
        System.out.println(bestX21);
        System.out.println();
        System.out.print("v1= ");
        System.out.println(bestv1);
        System.out.print("v2= ");
        System.out.println(bestv2);
        System.out.print("u1= ");
        System.out.println(bestu1);
        System.out.print("u2= ");
        System.out.println(bestu2);
        System.out.print("cond1= ");
        System.out.println(bestcond1);
        System.out.print("cond2= ");
        System.out.println(bestcond2);
        System.out.print("served1= ");
        System.out.println(bestserved1);
        System.out.print("served2= ");
        System.out.println(bestserved2);
        System.out.print("gone= ");
        System.out.println(bestgone);
      }

      return tempdiff;
    }
  };
//-----------------------------------------------------------------------------
//END WalrasModel
//-----------------------------------------------------------------------------

