/** \mainpage 
 *  Command line interface to hybridscp library
 *
 *  \defgroup CLI Command line interface
 *  @{
 */

#include <stdio.h>
#include <stdlib.h>

#include <hybrid.h>

/*Prototypes*/
void parse_parameters(int argc,char* argv[],Hybrid* h);
void print_usage();
void tester();

/*Results output stream*/
#define FSPEC_MAX_LEN 1023


static FILE* resultFile=NULL;
static char* resultFilespec=NULL;
static int resultPrintHeader=0;



/*Entry point*/
int main(int argc, char* argv[]) {

    SCProblem* problem;
    Hybrid* hybrid;
    char* ch=NULL;
    int l=0;
    int i=0;
    unsigned char* master=NULL;
    int result=0;
    int cost=0;

    time_t tmbg;
    time_t tmen;

    char stdt[1000];
    char endt[1000];

    /*Check parameters*/
    if (argc==1) {
        print_usage();
        return (EXIT_SUCCESS);
    }

    memset(stdt,0,1000);
    memset(endt,0,1000);
   
    /*Create problem and fill it*/
    printf("Hybrid and modified hybrid algorithm for SCP, loading problem\n");
    problem = scploader_load_scp(argv[1]);

    if (problem==NULL) {
        printf("Problem specified in file :%s is malformed or I/O error occured\n",argv[1]);
        return (EXIT_FAILURE);
    }

    printf("Problem succesfully loaded from: %s\n",argv[1]);


    
    /*Create hybrid algorithm and set its parameters*/
    hybrid = hybrid_new(problem);
    parse_parameters(argc,argv,hybrid);

    /*Setting output*/
    if (resultFilespec==NULL) {
        ch=getenv("HYBRID_SCP_OUTPUT");
        if (ch!=NULL && (l=strlen(ch)<FSPEC_MAX_LEN)) {
            resultFilespec=(char*)malloc(l+1);
            assert(resultFilespec!=NULL);
            strcpy(resultFilespec,ch);
        }
    }

    if(resultFilespec!=NULL) {
        printf("Output to (append): %s\n",resultFilespec);
        resultFile=fopen(resultFilespec,"at");
        if (resultFile==NULL) {
            printf("I/O Error occured when opening output file. Aborting\n");
            goto f_end;
        }
    }

    /*Solve problem using hybrid algorithm*/
    time(&tmbg);
    result=hybrid_solve(hybrid,1);
    time(&tmen);

    ch=ctime(&tmbg);
    strcpy(stdt,ch);
    ch=ctime(&tmen);
    strcpy(endt,ch);

    for(i=0;i<999;i++) {
        if (stdt[i]==13 || stdt[i]==10) stdt[i]=0;
        if (endt[i]==13 || endt[i]==10) endt[i]=0;
    }

    /*Print statistics if it has sense*/
    if (result==HYBRID_OK) {
        hybrid_print_statistics(hybrid);
        if (resultFile!=NULL) hybrid_print_csv(hybrid,resultFile,argv[1],resultPrintHeader,stdt,endt);
    }

    master=hybrid_get_solution(hybrid,&cost);
    for(i=0;i<problem->columns;i++) printf("%d",master[i]);
    printf("\nCOST:%d\n",cost);
    free(master);

    /*Delete hybrid algorithm*/
    hybrid_delete(hybrid);

    /*Delete problem*/
    scproblem_delete(problem);

    f_end:
    
    if (resultFilespec!=NULL) free(resultFilespec);
    if (resultFile!=NULL) fclose(resultFile);

    /*Done*/
    return (EXIT_SUCCESS);
}


void print_usage() {
    printf("scphybrid usage:\n");
    printf("scphybrid <inputfile> [output=<filespec>] [OPTION1] [OPTION2] ...\n");
    printf("\n");
    printf("scphybrid solves set covering problem using hybrid and modified hybrid algorithm\n");
    printf("Hybrid algorithm incorporates various greedy heuristics, five versions of\n");
    printf("lagrangean heuristic, non-binary genetic algorithm, l-class enumeration.\n");
    printf("Modified version replaces NBGA by simulated annealing with morphing\n");
}

int find_parm(const char* parm,int argc,char* argv[]) {
    int i=0;
    for (i=2;i<argc;i++) {
        if (strstr(argv[i],parm)!=NULL) return i;
    }
    return -1;
}

int parse_int_parm(char* parm,int* rp,int lo,int hi) {
    char* npt;
    int tmpi;

    npt=strstr(parm,"=");
    if (npt==NULL) return 0;

    npt++;
    if (sscanf(npt,"%d",&tmpi)>0 && tmpi>=lo && tmpi<=hi) {*rp=tmpi;return 1;}
    return 0;
}

int parse_flt_parm(char* parm,double* rp,double lo,double hi) {

    char* npt;
    float tmpd=0.0f;

    npt=strstr(parm,"=");
    if (npt==NULL) return 0;
    
    npt++;

    if (sscanf(npt,"%f",&tmpd)>0 && tmpd>=lo && tmpd<=hi) {*rp=tmpd;return 1;}
    return 0;
}

int parse_str_parm(char* parm,char** rp,int max) {

    char* npt;
    int l=0;
    
    npt=strstr(parm,"=");
    if (npt==NULL) return 0;

    npt++;

    l=strlen(npt);
    if (l<1 || l>max) return 0;

    *rp=malloc(l+1);
    assert(*rp!=NULL);
    strcpy(*rp,npt);
    return 1;
}


void parse_parameters(int argc,char* argv[],Hybrid* h) {


    int pnf=0;
    int tmpi=0;
    double tmpd=0.0;
  
    int xite=1000;
    float xprob=0.2;
    int xpop=100;
    int lg1=1;
    int lg2=1;
    int saInst=0;
    double saTemp=1000.0;
    double saFrzt=3.0;
    double saCool=0.75;
    int saIters=1000;
    int lceLGH=1;

    /*Initial LG. heuristic type*/
    if ( (pnf=find_parm("ilgt=",argc,argv))!=-1 && parse_int_parm(argv[pnf],&tmpi,1,5)) lg1=tmpi;

    /*NBGA params*/
    if ( (pnf=find_parm("gapop=",argc,argv))!=-1 && parse_int_parm(argv[pnf],&tmpi,1,5000)) xpop=tmpi;
    if ( (pnf=find_parm("gaitr=",argc,argv))!=-1 && parse_int_parm(argv[pnf],&tmpi,1,10000)) xite=tmpi;
    if ( (pnf=find_parm("gampb=",argc,argv))!=-1 && parse_flt_parm(argv[pnf],&tmpd,0.001,1.0)) xprob=tmpd;

    /*LCE Params*/
    if ( (pnf=find_parm("lcelgt=",argc,argv))!=-1 && parse_int_parm(argv[pnf],&tmpi,1,5)) lg2=tmpi;
    if ( (pnf=find_parm("lceulg=",argc,argv))!=-1 && parse_int_parm(argv[pnf],&tmpi,0,1)) lceLGH=tmpi;

    /*Simulated annealing params*/
    if ( (pnf=find_parm("sapfm=",argc,argv))!=-1 && parse_int_parm(argv[pnf],&tmpi,0,1)) saInst=tmpi;
    if ( (pnf=find_parm("satemp=",argc,argv))!=-1 && parse_flt_parm(argv[pnf],&tmpd,0.00001,100000.0)) saTemp=tmpd;
    if ( (pnf=find_parm("safrzt=",argc,argv))!=-1 && parse_flt_parm(argv[pnf],&tmpd,0.00001,100000.0)) saFrzt=tmpd;
    if ( (pnf=find_parm("sacool=",argc,argv))!=-1 && parse_flt_parm(argv[pnf],&tmpd,0.00001,1.0)) saCool=tmpd;
    if ( (pnf=find_parm("saiters=",argc,argv))!=-1 && parse_int_parm(argv[pnf],&tmpi,0,1000)) saIters=tmpi;

    /*Setting parameters*/
    hybrid_set_parameters(h,xite,xprob,xpop,lg1,lg2,lceLGH);
    hybrid_set_sa_parameters(h,saInst,saTemp,saFrzt,saCool,saIters);

    /*Output file*/
    if ( (pnf=find_parm("output=",argc,argv))!=-1) parse_str_parm(argv[pnf],&resultFilespec,FSPEC_MAX_LEN);

    /*Whether to print header*/
    if ( (pnf=find_parm("outhdr=",argc,argv))!=-1) parse_int_parm(argv[pnf],&resultPrintHeader,0,1);
    
}   

/**@}*/
