#ifndef _HYBRID_H
#define	_HYBRID_H

#include <time.h>
#include "scproblem.h"
#include "scploader.h"
#include "greedy.h"
#include "lagrange.h"
#include "genetic.h"
#include "siman_solver.h"
#include "lce.h"


#define HYBRID_OK 0
#define HYBRID_NOTSOLVABLE -1
#define HYBRID_IMPLICIT -2

#ifdef	__cplusplus
extern "C" {
#endif

/** \defgroup Hybrid Hybrid algorithm for solving SCP
 *   Hybrid algorithm is a combination of: \m
 *   -# Greedy algorithm (approximate)
 *   -# Lagrangean heuristics (approximate)
 *   -# Non-binary genethic algorithm or simulated annealing (approximate)
 *   -# L-class enumeration (exact, also includes lagrangean heuristics)
 *   
 * @{
 */

typedef struct _Hybrid Hybrid;

/** \brief Hybrid algorithm for SCP*/
struct _Hybrid {

    /** \brief Greedy algorithm*/
    GreedySolver* gdSolver;
    /** \brief LCE algorithm*/
    LCE* lceSolver;
    /** \brief NBGA*/
    NBGA*   nbgaSolver;
    /** \brief Lagrangean heuristic*/
    LagrangeSolver* lagrangeSolver;

    /** \brief Simulated annealing*/
    SimanSolver* simanSolver;

    /** \brief Problem*/
    SCProblem* problem;

    /** \brief Supplementary column mask 1*/
    unsigned char* columnMask1;

    /** \brief Pointer to the column mask that is solution*/
    unsigned char* masterSolution;
    
    /** \brief Cost of the solution*/
    int masterSolutionCost;

    /** \brief Parametric setting - maximum iterations of NBGA*/
    int parmNBGAMaxIterations;
    /** \brief Parametric setting - NBGA mutation probability*/
    double parmNBGAMutationProbability;
    /** \brief Parametric setting - NBGA population size*/
    int parmNBGAPopulationSize;
    /** \brief Parametric setting - Initial lagrangean heuristic type (1-5)*/
    int parmInitialLagrangeanHeuristicType;
    /** \brief Parametric setting - LCE internal lagrangean heuristic type (1-5)*/
    int parmLCELagrangeanHeuristicType;

    /** \brief Parametric setting; Indicates whether LCE uses Lagrangean heuristic*/
    int parmLCEUseLagrange;

    /** \brief Parametric setting: Use SA instead of NBGA*/
    int parmSAInsteadOfNBGA;
    /** \brief Parametric setting: SA starting temperature*/
    double parmSATemp;
    /** \brief Parametric setting: SA cooling constant*/
    double parmSAConstant;
    /** \brief Parametric setting: SA iterations at one temperature*/
    int parmSAIterations;
    /** \brief Parametric setting: SA termination temperature*/
    double parmSAFrozenTemp;



    unsigned char stNbgaRunFlag;
    unsigned char stLceRunFlag;
    unsigned char stSimanRunFlag;
    
    int stInitialLagrangeCost;
    int stInitialGreedyCost;
    int stBeforeLCECost;
    int stNBGACost;
    int stSACost;
    int stLagrangeanZMAX;
    int stFixedCost;

    double stInitialGreedyTime;
    double stInitialLagrangeTime;
    double stNBGATime;
    double stLCETime;
    double stSATime;
    double stTotalTime;


};

/** \brief Create new Hybrid algorithm*/
Hybrid* hybrid_new(SCProblem* problem);


/** \brief Set parametric settings of Hybrid algorithm
    \param nbgaMaxIterations Maximum iterations of NBGA
    \param nbgaMutationProbablity NBGA mutation probability
 *  \param nbgaPopulationSize Population size
 *  \param initialLGHType Type of initial lagrangean heuristic
 *  \param LCELGHType Type of lagrangean heuristic used by LCE algorithm
 *  \param LCEUseLGH Indicates whether to use lagrangean heuristic to accelerate LCE
 */

void hybrid_set_parameters(Hybrid* h,int nbgaMaxIterations,double nbgaMutationProbability,int nbgaPopulationSize,int initialLGHType,int LCELGHType,int LCEUseLGH);


/** \brief Set Simulated annealing parameters
 *  \param temp Starting temperature
 *  \param frozenTemp Ending temperature
 *  \param constant Cooling constant - T=T*constant
 *  \param iterations Iterations per one temperature
 */
void hybrid_set_sa_parameters(Hybrid* h,int saPerform,double temp,double frozenTemp,double constant,int iterations);

/** \brief Solve SCP using hybrid algorithm
 *  \return always HYBRID_OK or HYBRID_NOTSOLVABLE
 */
int hybrid_solve(Hybrid* h,int removeDominance);

/** \brief Return solution in form of mask of columns. Returned mask
 *  is related to the columns of the original problem and must be
 *  freed by caller
 *  \param cost There will be returned cost of the solution. Must point
 *   to allocated or stacked memory
 */
unsigned char* hybrid_get_solution(Hybrid* h,int* cost);

void hybrid_make_master_solution(Hybrid *h,unsigned char* mask,SCPView* view,IList* fixedList,SCPView* masterView);

void hybrid_map_solution_to_parent(SCPView* problemView,unsigned char* inMask,unsigned char* retMask);


/** \brief Supplementary function that calculates CPU time*/
double hybrid_calc_time(clock_t begin,clock_t end);

/** \brief Print statistics*/
void hybrid_print_statistics(Hybrid* h);

/** \brief Perform Greedy phase of hybrid algorithm
 *  \param view View to the underlying problem
 *  \param solPtr Pointer to space where the solution will be placed
 *  \param solCost Pointer to space where cost of the solution will be returned
 */
void hybrid_phase_greedy(Hybrid* h,SCPView* view,unsigned char* solPtr,int* solCost);

/** \brief Perform Lagrange phase of hybrid algorithm
 *  \param view View to the underlying problem
 *  \param solPtr Pointer to space where the solution will be placed
 *  \param solCost Pointer to space where cost of the solution will be returned
 *  \param lgZMAX Pointer to space where lower bound will be returned
 */
void hybrid_phase_lagrange(Hybrid* h,SCPView* view,unsigned char* solPtr,int* solCost,int* lgZMAX);

/** \brief Perform NBGA phase of hybrid algorithm
 *  \param view View to the underlying problem
 *  \param solPtr Pointer to space where the solution will be placed
 *  \param solCost Pointer to space where cost of the solution will be returned
 *  \param lb Best lower bound found
 *  \param ub Best upper bound found (unused)
 */
void hybrid_phase_nbga(Hybrid* h,SCPView* view,unsigned char* solPtr,int* solCost,int lb,int ub);

/** \brief Perform SA phase of hybrid algorithm
 *  \param view View to the underlying problem
 *  \param solPtr Pointer to space where the solution will be placed
 *  \param solCost Pointer to space where cost of the solution will be returned
 *  \param baseSolution Base feasible solution for SA
 */
void hybrid_phase_sa(Hybrid* h,SCPView* view,unsigned char* solPtr,int* solCost,unsigned char* baseSolution);

/** \brief Perform LCE phase of hybrid algorithm
 *  \param view View to the underlying problem
 *  \param solPtr Pointer to space where the solution will be placed
 *  \param solCost Pointer to space where cost of the solution will be returned
 *  \param classCount Pointer to space where number of integer L-classes is returned
 */
void hybrid_phase_lce(Hybrid* h,SCPView* view,unsigned char* solPtr,int* solCost,int* classCount,int record);

/** \brief Print results in form of CSV using specified FILE descriptor
 *  \param resultFile file descriptor
 *  \param fname Name of input file (matrix)
 *  \param resultPrintHeader Indicates whether to print row with column headers
 *  \param dateStart Date when solver was started
 *  \param dateEnd Date when solver was ended
 */
void hybrid_print_csv(Hybrid* h,FILE* resultFile,const char* fname,int resultPrintHeader,char* dateStart,char* dateEnd);

/** \brief Print state of hybrid algorithm, unused*/
void hybrid_print(Hybrid* h);

/** \brief Delete Hybrid algorithm*/
void hybrid_delete(Hybrid* h);


/**@}*/

#ifdef	__cplusplus
}
#endif

#endif	/* _HYBRID_H */

