/*
 * IFAlgorithm.java
 *
 * Created on Ketvirtadienis, 2007, Sausio 25, 17.08
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package Main.algorithms;
import java.util.*;
import Main.*;
import Main.equation.*;
import lp.*;

public class IFAlgorithm
    extends AbstractAlgorithm 
{

  public void solve() {
    solve(true);
  }

  public void solve(boolean calculteUV) {
   /* mLog.logn("----------------------------------");
    mLog.logn("IFA BEGINS");*/
      indeksas = 0;
      indeksas3 = 5;
          if (indeksas2 == 0 ){
                mLog.logn("----------------------------------");
                mLog.logn("IFA BEGINS");
          }
	if(calculteUV)
	{
		if (indeksas2 == 0 )
                    mLog.logn("-- MATRIX U");
		calculateMatrixU();
		if (indeksas2 == 0 ){
                    outputMatrix(getMatrixU());
                    mLog.logn("-- MATRIX V");
                }
		calculateMatrixV();
		if (indeksas2 == 0 )
                    outputMatrix(getMatrixV());
	}

    /*if (calculteUV) {
      mLog.logn("-- MATRIX U");
      calculateMatrixU();
      outputMatrix(getMatrixU());
      mLog.logn("-- MATRIX V");
      calculateMatrixV();
      outputMatrix(getMatrixV());
    }*/

    /**
     *  building matrix of Y
     */

 /*    if (indeksas2 == 0)
         mLog.logn("-- SOLVING Y");*/
          
    int rows = matrixU.length + 2;
    int cols = matrixU.length * 2 + 3;
    double[][] matrixSolve = new double[rows][cols];

    int k;
    for (int i = 1; i < rows - 1; i++) {
      k = 1;
      for (int j = 1; j < cols - 2; j += 2, k++) {
        matrixSolve[i][j]= matrixU[i-1][k-1];
        matrixSolve[i][j+1]= -matrixU[i-1][k-1];
        //matrixSolve[i][j] = matrixU[k - 1][i - 1];
        //matrixSolve[i][j + 1] = -matrixU[k - 1][i - 1];
      }
      matrixSolve[i][cols - 1] = -1;
      matrixSolve[i][cols - 2] = 1;
    }

    for (int j = 1; j < cols - 2; j += 2) {
      matrixSolve[rows - 1][j] = 1;
      matrixSolve[rows - 1][j + 1] = -1;
    }
    matrixSolve[rows - 1][cols - 1] = 0;
    matrixSolve[rows - 1][cols - 2] = 0;

    for (int i=0;i<rows;i++){
      System.out.print("R&V: ");
      for (int j=0;j<cols;j++){
        System.out.print(matrixSolve[i][j]+" ");
      }
      System.out.println("");
    }

    //create
    solve lpSolve = new solve();
    lprec lpIn = new lprec(0, cols - 1);

    double[] bvalue = new double[cols];
    Arrays.fill(bvalue, 0);

    bvalue[cols - 1] = 1;
    bvalue[cols - 2] = -1;
    //bvalue[1]= 1;

    //max
    lpSolve.set_obj_fn(lpIn, bvalue);
    lpSolve.set_maxim(lpIn);

    //x-y
    for (int i = 1; i < rows - 1; i++) {
      lpSolve.add_constraint(lpIn, matrixSolve[i], constant.EQ, 0);

    }
    lpSolve.add_constraint(lpIn, matrixSolve[matrixSolve.length - 1], constant.EQ, 1);

    //x1,y1

    int resultInt = lpSolve.solve(lpIn);
    if (resultInt != constant.OPTIMAL) {
        indeksas3 = 0;
     /*    if (indeksas2 == 0 )
            mLog.logn("-- IFA ALGORITHM FAILED");*/
      setSolved(false);
      //return res;
    }
    else {
      setSolved(true);
    }

    result = new double[matrixU.length][2];

    k = 1;
    for (int i = 0; i < result.length; i++, k += 2) {
      double v1 = lpIn.getBestSolution(lpIn.getRows() + k);
      double v2 = lpIn.getBestSolution(lpIn.getRows() + k + 1);
      v1 = v1 - v2;
      result[i][1] = v1;
    }

    k = 1;
    for (int i = 0; i < result.length; i++, k += 1) {
      double v1 = lpIn.getBestSolution(lpIn.getRows() + k);
      System.out.println("BEST SOLUTION" + i + " :  " + v1);
    }
    //U = lpIn.getBestSolution(lpIn.getRows() + k + 1) -
    //    lpIn.getBestSolution(lpIn.getRows() + k);


    //lpSolve.print_solution(lpIn);

    //double[][] rezultsY= lpSolve.getMatrix();

    /**
     *  building matrix of X
     */
/*     if (indeksas2 == 0)
         mLog.logn("-- SOLVING X");*/
    
    matrixSolve = new double[rows][cols];
    for (int i = 1; i < rows - 1; i++) {
      k = 1;
      for (int j = 1; j < cols - 2; j += 2, k++) {
        matrixSolve[i][j] = matrixV[k - 1][i - 1];
        matrixSolve[i][j + 1] = -matrixV[k - 1][i - 1];
      }
      matrixSolve[i][cols - 1] = -1;
      matrixSolve[i][cols - 2] = 1;
    }

    for (int j = 1; j <= cols - 2; j += 2) {
      matrixSolve[rows - 1][j] = 1;
      matrixSolve[rows - 1][j + 1] = -1;
    }
    matrixSolve[rows - 1][cols - 1] = 0;
    matrixSolve[rows - 1][cols - 2] = 0;

    lpSolve = new solve();
    lpIn = new lprec(0, cols - 1);


    //max
    lpSolve.set_obj_fn(lpIn, bvalue);
    lpSolve.set_maxim(lpIn);

    //x-y
    for (int i = 0; i < rows - 1; i++) {
      lpSolve.add_constraint(lpIn, matrixSolve[i], constant.EQ, 0);

    }
    lpSolve.add_constraint(lpIn, matrixSolve[matrixSolve.length - 1],
                           constant.EQ, 1);

    //x1,y1

    resultInt = lpSolve.solve(lpIn);
    if (resultInt != constant.OPTIMAL) {
        indeksas3 = 0;
     /*    if (indeksas2 == 0 )
            mLog.logn("-- IFA ALGORITHM FAILED");*/
        
      setSolved(false);
    }
    else {
      setSolved(true && isSolved());
    }

    k = 1;
    for (int i = 0; i < result.length; i++, k += 2) {
      double v1 = lpIn.getBestSolution(lpIn.getRows() + k);
      double v2 = lpIn.getBestSolution(lpIn.getRows() + k + 1);

      v1 -= v2;
      result[i][0] = v1;
    }

    V = lpIn.getBestSolution(lpIn.getRows() + k + 1) -
        lpIn.getBestSolution(lpIn.getRows() + k);

    U = 0;
    //V = 0;
    for (int i=0;i < result.length; i++){
      for (int j=0; j < result.length; j++){
        U = U + result[i][1] * getMatrixU()[i][j] * result[j][0]; // x[i]*u[i][j]*y[j]
        //V = V + result[i][1] * getMatrixV()[i][j] * result[j][0]; // x[i]*v[i][j]*y[j]
      }
    }
    
    lpSolve.print_lp(lpIn);
    lpSolve.print_duals(lpIn);
    lpSolve.print_solution(lpIn);
    lpSolve.print_scales(lpIn);

    //lpSolve.print_solution(lpIn);

    //double[][] rezultsX= temp.getMatrix();

    //result= new double[matrixU.length][2];
    //indeksas3 = 5;
    if (indeksas2 == 0)
        mLog.logn("-- GENERATING OUTPUT");
    
    for (int i = 0; i < result.length; i++) {
      if (result[i][0] < 0 || result[i][1] < 0) {
      /*     if (indeksas2 == 0 )
                mLog.logn("-- IFA ALGORITHM FAILED");   */
        setSolved(false);
        indeksas3 = 0;
        //indeksas2 = 0;
        break;
      }
    }
    
/*    if (indeksas2 == 0)
    {
        mLog.logn("IFA U = " + Utility.Round(U));
        mLog.logn("IFA V = " + Utility.Round(V));
        mLog.logn("IFA ENDS");
        mLog.logn("------------------------------------------------------");
    }*/
    indeksas2 = 1;
     
    //solveTMP(true);
    }
    //indeksas3 = 0;
  }

