// ten-foulds cross validation with equal class distribution in testing and training

#include<iostream>
#include<vector>

#define maxlen 10000
#define maxins 10000

#define infile "fa.in"
#define oufile "fa.ou"
#define refile "fa.fin"
#define clfile "classifier2"
#define top 30
#define thres_file "threshold.txt"

#define writef "writef"

using namespace std;
vector<int> ans;
int numtr;
int maxitem=1000;
int topk=-1;

void removeEOL(char *s){
    int i;
    if (s[strlen(s)-1]=='\n') s[strlen(s)-1]=0;
}

int numClass=0;
int baseClass=10;

int clas[maxins];
char trans[maxins][maxlen];
int numIns;
int clasCnt[maxins];
int clasCnt2[maxins];
int choosen[maxins];
    
void print(FILE *f,char *a,int error){
    char *stk=strtok(a," \t");

    while(stk!=NULL){
        if (rand()%100>=error) fprintf(f,"%s ",stk);
        else fprintf(f,"%ld ",rand()%maxitem);
        
        stk=strtok(NULL," \t");        
    } 
    fprintf(f,"\n");
}

// read dataset and divide it randomly
void readDb2(char *fname,int k,int error1,int error2,char ch,int top_k){
    int i;

    srand(time(NULL));
       
    numClass=0;
    for (i=0;i<numIns;i++)
        if (clas[i]>numClass) numClass=clas[i];

    for (i=0;i<=numClass;i++) clasCnt[i]=0;
    for (i=0;i<=numClass;i++) clasCnt2[i]=0;

    for (i=0;i<numIns;i++) clasCnt[clas[i]]++;
    int testing=numIns/k;

    for (i=0;i<numIns;i++) choosen[i]=0;

    for (i=0;i<testing;i++){
        int x;
        do{
           x=rand()%numIns;
        }while(choosen[x]);

        clasCnt2[clas[x]]++;
        choosen[x]=1;
    }

    FILE *f1,*f2;
    f1=fopen(infile,"w");
    f2=fopen(oufile,"w");

    numtr=0;
    for (i=0;i<numIns;i++)
        if (!choosen[i]){
            fprintf(f1,"%i ",clas[i]);
            print(f1,trans[i],error1);
            numtr++;
        }else{
            ans.push_back(clas[i]);
            fprintf(f2,"%c %i ",ch,top_k);
            print(f2,trans[i],error2);
        }

    fclose(f1);
    fclose(f2);
}

// read dataset and divide it equally
void readDb10(char *fname,int k,int error1,int error2,char ch,int top_k){
    int i;

    srand(time(NULL));
    
    numClass=0;
    for (i=0;i<numIns;i++)
        if (clas[i]>numClass) numClass=clas[i];

    for (i=0;i<=numClass;i++) clasCnt[i]=0;
    for (i=0;i<=numClass;i++) clasCnt2[i]=0;

    for (i=0;i<numIns;i++) clasCnt[clas[i]]++;
    int testing=numIns/k;

    for (i=0;i<numIns;i++) choosen[i]=0;

    for (i=0;i<testing;i++){
        int x;
        do{
            x=rand()%numIns;
        }while(choosen[x]||clasCnt2[clas[x]]>clasCnt[clas[x]]/k);

        clasCnt2[clas[x]]++;
        choosen[x]=1;
    }

    FILE *f1,*f2;
    f1=fopen(infile,"w");
    f2=fopen(oufile,"w");

    numtr=0;
    for (i=0;i<numIns;i++)
        if (!choosen[i]){
            fprintf(f1,"%i ",clas[i]);
            print(f1,trans[i],error1);
            numtr++;
        }else{
            ans.push_back(clas[i]);
            fprintf(f2,"%c %i ",ch,top_k);
            print(f2,trans[i],error2);
        }

    fclose(f1);
    fclose(f2);
}

void readDb(char *fname,int k,int error1,int error2,char ch,int top_k){
    
    FILE *f;
    f=fopen(fname,"r");
    
    srand(time(NULL));
    char s[maxlen];
    
    FILE *f1,*f2;
    f1=fopen(infile,"w");
    f2=fopen(oufile,"w");

    numtr=0;
    maxitem=0;

    while(fgets(s,maxlen,f)!=NULL){
        removeEOL(s);

        if (rand()%k!=0){
            char *stk=strtok(s," \t");
           
            fprintf(f1," %s",stk);
            int x;
            sscanf(stk,"%i",&x);
            
            if (x>numClass) numClass=x;
            if (x<baseClass) baseClass=x;
            
            stk=strtok(NULL," \t");

            while(stk!=NULL){
                int x;
                sscanf(stk,"%i",&x);
                if (x>maxitem) maxitem=x;

                if (error1==0) fprintf(f1," %s",stk);
                else if (error1>0){
                    if (rand()%100>=error1) fprintf(f1," %s",stk);
                }else{
                    if (rand()%100>=-error1) fprintf(f1," %s",stk);
                    else fprintf(f1," %i",rand()%maxitem);
                }

                stk=strtok(NULL," \t");
            }
            fprintf(f1,"\n");
            numtr++;                        
        }                                           
        else{
            char *stk=strtok(s," \t");

            int x;
            sscanf(stk,"%i",&x);
            
            stk=strtok(NULL," \t");
            ans.push_back(x);
            
            fprintf(f2,"%c %i ",ch,top_k);
            while(stk!=NULL){
                int x;
                sscanf(stk,"%i",&x);
                if (x>maxitem) maxitem=x;

                if (error2<=0||rand()%100>=error2){
                    fprintf(f2," %s",stk);
                }
                stk=strtok(NULL," \t");
            }
            fprintf(f2,"\n");                        
        }
    }

    fclose(f);   
    fclose(f1);    
    fclose(f2);
}

    int ddg=0,ddc=0;
    int dd1=0; // count draw
    int dd2=0; // count 0
    double fp=0,fn=0,tp=0,tn=0;

char evaluate(int error,char ch,int cla){
    FILE *f;

    f=fopen(refile,"r");

    char s[maxlen];
    while(fgets(s,maxlen,f)){
        removeEOL(s);
        if (strcmp(s,"#")==0) break;
    }

    for (int i=0;i<ans.size();i++){
        double x,y,z,t;

        fscanf(f,"%lf %lf",&x,&y);

//        int inc=0;
        
        if (x>y){
            if (ans[i]==cla){
                ddg++;
                tp++;
            }else fp++;
        }else if (x<y){
            if (ans[i]!=cla){
                ddg++;
                tn++;
            }else fn++;
        }else dd1++;

        if (x*y==0) dd2++;
    }

    return ch;

    fclose(f);
}

int iffloat(char *s){
    int i;
    for (i=0;i<strlen(s);i++)
        if (s[i]=='.') return 1;
    return 0;
}

char s[maxlen];

double read_thres(char fname[]){
    FILE *f;

    f=fopen(thres_file,"r");

    while (fscanf(f,"%s",s)){
        if (strcmp(s,fname)==0) break;
    }
    
    double dd;
    fscanf(f,"%lf",&dd);
    fscanf(f,"%i",&topk);
    
    fclose(f);
    return dd;
}

void chooseClass(char *ss,int delta,char *arg7,double error1,char ch2){
    int cla;
    char ch;

    if (numClass-baseClass<2) numClass=baseClass;

    for (cla=baseClass;cla<=numClass;cla++){

        char comm[maxlen];

        sprintf(comm,"%s %s %s %s %i %s %i > %s",clfile,infile,oufile,ss,delta,arg7,cla,refile);

        time_t seconds,current;
        seconds = time (NULL);
        system(comm);
        current = time (NULL);

        ch=evaluate((int)error1,ch2,cla);
    }
//    cout<<ch<<endl;
/*    if (ch=='T'||ch=='t') cout<<(double)ddg/ans.size()*(numClass+1)<<" "<<(double)ddc/(ans.size()*(numClass+1))<<endl;
    else if (ch=='G'||ch=='g'||ch=='A'||ch=='a') cout<<(double)ddg/(ans.size()*(numClass+1))<<" "<<(double)dd1/(ans.size()*(numClass+1))<<endl;
        else cout<<(double)ddc/(ans.size()*(numClass+1))<<" "<<(double)dd1/(ans.size()*(numClass+1))<<endl;*/

    int to=ans.size()*(numClass-baseClass+1);
    int to2=to-dd1;
//    cout<<to<<" "<<to2<<endl;
    if (to2==0) cout<<0.5<<" "<<0.5<<" "<<0.5<<" "<<0.5<<" "<<0.5<<" "<<(double)dd1/to<<" "<<(double)dd2/to<<endl;
    else cout<<(double)ddg/to2<<" "<<tp/to2<<" "<<fp/to2<<" "<<fn/to2<<" "<<tn/to2<<" "<<(double)dd1/to<<" "<<(double)dd2/to<<endl;
}


void writefile(char *s){
    FILE *f;

    f=fopen(writef,"a");

    fprintf(f,"%s\n",s);
    fclose(f);
}

// error is percentage
// facade fname threshold percent delta error_train error_test miner top_k type(gen or cls) <1 for new,0 for old>
//    0    1        2       3       4       5           6         7   8           9                 10
int main(int argc,char *arg[]){   

    time_t seconds=time(NULL);
    
    int i,j;
    int k;

    if (argc<11){
        cout<<"facade fname threshold percent delta error_train error_test miner top_k type(gen or cls) <1 for new,0 for old>"<<endl;
        return 0;
    }

    writefile(arg[1]);
    
    sscanf(arg[3],"%i",&k);

    double error1=0;
    double error2=0;

    int delta=0;
    sscanf(arg[4],"%i",&delta);

    sscanf(arg[5],"%lf",&error1);
    sscanf(arg[6],"%lf",&error2);
    error1*=100;

    error2*=100;

    char ch=arg[9][0];
    int top_k;
    sscanf(arg[8],"%i",&top_k);
    // if arg[10]==0, dont need to creat new test cases
    read_thres(arg[1]);
    if (topk!=-1) top_k=topk;

    if (strcmp(arg[10],"1")==0) readDb(arg[1],k,(int)error1,(int)error2,ch,top_k);

    // if arg[10]==2, dont need to run
    if (strcmp(arg[10],"2")==0) return 0;

    char ss[maxlen];

    // transform the threshold into absolute
        int thre=0;
        if (iffloat(arg[2])){
            double x;
            sscanf(arg[2],"%lf",&x);
            thre=(int)(x*numtr);
        }else sscanf(arg[2],"%i",&thre);        
    ////////////////////////////////////////

    thre=(int)(read_thres(arg[1])*numtr);

    sprintf(ss,"%i",thre);

//        sprintf(comm,"%s %s %s %s %i %s %i> %s",clfile,infile,oufile,ss,delta,arg[7],cla,refile);    
    chooseClass(ss,delta,arg[7],error1,ch);

  time_t current=time(NULL);
    cout<<current-seconds<<endl;
    
    cout<<"*input "<<arg[1]<<endl;
    cout<<"*threshold "<<arg[2]<<endl;
    cout<<"*run "<<arg[3]<<endl;
    cout<<"*delta "<<arg[4]<<endl;
    cout<<"*missing_train "<<arg[5]<<endl;
    cout<<"*missing_test "<<arg[6]<<endl;
    cout<<"*miner "<<arg[7]<<endl;
    cout<<"*ktop "<<arg[8]<<endl;
    cout<<"*type "<<arg[9]<<endl;
    cout<<"*xxx "<<arg[10]<<endl;
    
}
