//  QualityIndicator.java
//
//  Author:
//       Antonio J. Nebro <antonio@lcc.uma.es>
//       Juan J. Durillo <durillo@lcc.uma.es>
//
//  Copyright (c) 2011 Antonio J. Nebro, Juan J. Durillo
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
// 
//  You should have received a copy of the GNU Lesser General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.

package jmetal.qualityIndicator;

import java.io.*;
import java.util.*;
import jmetal.core.Problem;
import jmetal.core.Solution;
import jmetal.core.SolutionSet;
import jmetal.qualityIndicator.fastHypervolume.FastHypervolume;

/**
 * QualityIndicator class
 */
public class QualityIndicator implements Serializable{
  SolutionSet trueParetoFront_ ;
  double      trueParetoFrontHypervolume_ ;
  Problem     problem_; 
  public jmetal.qualityIndicator.util.MetricsUtil utils_  ;
  
  /**
   * Constructor
   * @param problem The problem
   * @param paretoFrontFile  Pareto front file
   */
  public QualityIndicator(Problem problem, String paretoFrontFile) {
    problem_ = problem ;
    utils_ = new jmetal.qualityIndicator.util.MetricsUtil() ;
    trueParetoFront_ = utils_.readNonDominatedSolutionSet(paretoFrontFile);
    trueParetoFrontHypervolume_ = new Hypervolume().hypervolume(
                 trueParetoFront_.writeObjectivesToMatrix(),   
                 trueParetoFront_.writeObjectivesToMatrix(),
                 problem_.getNumberOfObjectives());
  } // Constructor 
 
  /**
   * Returns the hypervolume of solution set
   * @param solutionSet Solution set
   * @return The value of the hypervolume indicator
   */
  public double getHypervolume(SolutionSet solutionSet) {
    return new Hypervolume().hypervolume(solutionSet.writeObjectivesToMatrix(),
                                         trueParetoFront_.writeObjectivesToMatrix(),
                                         problem_.getNumberOfObjectives());
  } // getHypervolume
   public double getHypervolume(String AchievePFPath) {
	   return getHypervolume(getSolutionSetFromFile(AchievePFPath));
  } // getDelta_p
    
  /**
   * Returns the hypervolume of the true Pareto front
   * @return The hypervolume of the true Pareto front
   */
  public double getTrueParetoFrontHypervolume() {
    return trueParetoFrontHypervolume_ ;
  }

  public double getFastHypervolume(SolutionSet solutionSet){
	return new FastHypervolume().computeHypervolume(solutionSet);
  }
  public double getFastHypervolume(String AchievePFPath) {
	   return getFastHypervolume(getSolutionSetFromFile( AchievePFPath));
  } // getDelta_p
  
  /**
   * Returns the inverted generational distance of solution set
   * @param solutionSet Solution set
   * @return The value of the hypervolume indicator
   */
  public double getIGD(SolutionSet solutionSet) {
    return new InvertedGenerationalDistance().invertedGenerationalDistance(
                    solutionSet.writeObjectivesToMatrix(),
                    trueParetoFront_.writeObjectivesToMatrix(),
                    problem_.getNumberOfObjectives());
  } // getIGD
    public double getIGD(String AchievePFPath) {
	   return getIGD(getSolutionSetFromFile(AchievePFPath));
  } // getIGD
  
 /**
   * Returns the generational distance of solution set
  * @param solutionSet Solution set
   * @return The value of the hypervolume indicator
   */
  public double getGD(SolutionSet solutionSet) {
    return new GenerationalDistance().generationalDistance(
                    solutionSet.writeObjectivesToMatrix(),
                    trueParetoFront_.writeObjectivesToMatrix(),
                    problem_.getNumberOfObjectives());
  } // getGD
     public double getGD(String AchievePFPath) {
	   return getGD(getSolutionSetFromFile(AchievePFPath));
  } // getGD

  public double getDelta_p(SolutionSet solutionSet) {
    return new Delta_p().delta_p(
                    solutionSet.writeObjectivesToMatrix(),
                    trueParetoFront_.writeObjectivesToMatrix(),
                    problem_.getNumberOfObjectives());
  } // getDelta_p

   public double getDelta_p(String AchievePFPath) {
	   return getDelta_p(getSolutionSetFromFile(AchievePFPath));
  } // getDelta_p
  
  /**
   * Returns the spread of solution set
   * @param solutionSet Solution set
   * @return The value of the hypervolume indicator
   */
  public double getSpread(SolutionSet solutionSet) {
    return new Spread().spread(solutionSet.writeObjectivesToMatrix(),
                               trueParetoFront_.writeObjectivesToMatrix(),
                               problem_.getNumberOfObjectives());
  } // getGD
  public double getSpread(String AchievePFPath) {
	   return getSpread(getSolutionSetFromFile(AchievePFPath));
  } // getDelta_p
    /**
   * Returns the epsilon indicator of solution set
     * @param solutionSet Solution set
   * @return The value of the hypervolume indicator
   */
  public double getEpsilon(SolutionSet solutionSet) {
    return new Epsilon().epsilon(solutionSet.writeObjectivesToMatrix(),
                                 trueParetoFront_.writeObjectivesToMatrix(),
                                 problem_.getNumberOfObjectives());
  } // getEpsilon
   public double getEpsilon(String AchievePFPath) {
	   return getEpsilon(getSolutionSetFromFile(AchievePFPath));
  } // getDelta_p

  public void printVectorToFile(String path, Object[] vector, boolean append){
    try {
      FileOutputStream fos   = new FileOutputStream(path,append)     ;
      OutputStreamWriter osw = new OutputStreamWriter(fos)    ;
      BufferedWriter bw      = new BufferedWriter(osw)        ;            

      if (vector.length>0) {
        
          for (int j = 0; j < vector.length; j++)
            bw.write(vector[j].toString()+ " ");
          bw.newLine();
      }
      bw.close();
    }catch (IOException e) {
      e.printStackTrace();
    }       
  } // printVariablesToFile

  public SolutionSet getSolutionSetFromFile(String FilePath){
	  SolutionSet solutionList = new SolutionSet();
	  		try {
				// Open the file
				FileInputStream fis = new FileInputStream(FilePath);
				InputStreamReader isr = new InputStreamReader(fis);
				BufferedReader br = new BufferedReader(isr);

				int numberOfObjectives = 0;
				int i = 0;
				int j = 0;
				String aux = br.readLine();
				while (aux != null) {
					StringTokenizer st = new StringTokenizer(aux);
					j = 0;
					numberOfObjectives = st.countTokens();
					Solution solution = new Solution(numberOfObjectives);
					while (st.hasMoreTokens()) {
						double value = (new Double(st.nextToken()))
								.doubleValue();
						solution.setObjective(j, value);
						// System.out.println("lambda["+i+","+j+"] = " + value)
						// ;
						j++;
					}
					solutionList.add(solution);
					aux = br.readLine();
					i++;
				}
				br.close();
			} catch (Exception e) {
				System.out
						.println("Failed in reading the File");
				e.printStackTrace();
			}
			return solutionList; 
  }
} // QualityIndicator
