// added support and confidence

#include<iostream>
#include <vector>
#include <cstring>

#define maxlen 10000
#define oddfile_de "fpmax"
#define tempfile "temp2"
#define writef "writef"
#define def_k 10
#define maxsize 10000

using namespace std;

vector<vector<int> > fcls1;
vector<double> supc1,supg1;
vector<int> clas1;
vector<vector<int> > fcls2;

vector<vector<int> > fgen1;
vector<double> supc2,supg2;
vector<vector<int> > fgen2;
vector<int> clas2;

char oddfile[maxlen]=oddfile_de; 

int m,n,delta;

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

void parse(char *s,int &x,int &y){
    char *stk=strtok(s,",()");
    
    sscanf(stk,"%i",&x);
    stk=strtok(NULL,",()");
    
    sscanf(stk,"%i",&y);
}

void sort(vector<int> &a){
    int i,j,tg;
    for (i=0;i<a.size();i++)
        for (j=i+1;j<a.size();j++)
            if (a[i]>a[j]){
                tg=a[i];a[i]=a[j];a[j]=tg;
            }
}

// how many generators ?
int add(char *p1,char *p3,vector<vector<int> > &fcls,vector<vector<int> > &fgen){
    char *stk;

                stk=strtok(p1,";");

                while(stk!=NULL){
                    char *kkk=strtok(stk," \t");
                    vector<int> a;

                    while(kkk!=NULL){
                        int x;
                        sscanf(kkk,"%i",&x);
                        a.push_back(x);

                        kkk=strtok(NULL," \t");
                    }
                    sort(a);
                    fcls.push_back(a);
                    
                    stk=strtok(NULL,";");
                }
                
                stk=strtok(p3,";");
                int dd=0;

                while(stk!=NULL){
                    char *kkk=strtok(stk," \t");
                    vector<int> a;

                    while(kkk!=NULL){
                        int x;
                        sscanf(kkk,"%i",&x);
                        a.push_back(x);
                        
                        kkk=strtok(NULL," \t");                        
                    }
                    
                    sort(a);
                    fgen.push_back(a);

                    stk=strtok(NULL,";");
                    dd++;                    
                }       
    
    return dd;
}

double weight(int x,int y){
    return (double)(y*y)/(x+y);
}

void read(char *fname){
    int i,j;

    FILE *f;
    f=fopen(fname,"r");

    char ss[maxlen];

    int nn=0;
    
    while(fgets(ss,maxlen,f)!=NULL){
        removeEOF(ss);

        char *stk=strtok(ss,"()");
        char p1[maxlen];
        char p2[maxlen];
        char p3[maxlen];

        strcpy(p1,stk);
        stk=strtok(NULL,"()");

        strcpy(p2,stk);
        stk=strtok(NULL,"()");

        strcpy(p3,stk);

        int x,y;
        parse(p2,x,y);
        int equ_cnt=0;
        
        if (x<=delta || y<=delta){
            if (x<=delta){
                int dd=add(p1,p3,fcls2,fgen2);

                    supc2.push_back(weight(x,y));
                    while(dd--){
                        supg2.push_back(weight(x,y));
                        clas2.push_back(nn);
                    }

            }else{
                int dd=add(p1,p3,fcls1,fgen1);
                
                    supc1.push_back(weight(y,x));
                    while(dd--) {
                        supg1.push_back(weight(y,x));
                        clas1.push_back(nn);
                    }
            }
            nn++;
        }
    }
    cout<<nn<<endl;    
    fclose(f);
}

typedef struct{
    int x,y;
} Pair;

void readDPM(char *fname){
    FILE *gen,*cls,*pair;
    
    char f1[maxlen];
    char f2[maxlen];
    char f3[maxlen];
    
    strcpy(f1,fname);
    strcpy(f2,fname);
    strcpy(f3,fname);
    
    strncat(f1,".key",maxlen);
    strncat(f2,".closed",maxlen);
    strncat(f3,".pair",maxlen);
    
    gen=fopen(f1,"r");
    cls=fopen(f2,"r");
    pair=fopen(f3,"r");
    
    int x,y;
    char s[maxlen];

    vector<Pair> set;

    while(fgets(s,maxlen,cls)!=NULL){
        char *stk=strtok(s," ");
        vector<int> a;
        stk=strtok(NULL," ");
        
        while(stk!=NULL){
            int x;
            sscanf(stk,"%i",&x);
            a.push_back(x);
            stk=strtok(NULL," ");
        }
        
        int y=a.back();a.pop_back();
        int x=a.back();a.pop_back();

        if (x<=delta){
            fcls2.push_back(a);
            supc2.push_back(weight(x,y));
        }else{
            fcls1.push_back(a);
            supc1.push_back(weight(x,y));
        }
        
        Pair pp;
        pp.x=x;pp.y=y;
        set.push_back(pp);
    }

    while(fgets(s,maxlen,gen)!=NULL){
        char *stk=strtok(s," ");
        vector<int> a;
        stk=strtok(NULL," ");

        while(stk!=NULL){
            int x;
            sscanf(stk,"%i",&x);
            a.push_back(x);
            stk=strtok(NULL," ");
        }

        int y=a.back();a.pop_back();
        int x=a.back();a.pop_back();

        if (x<=delta){
            fgen2.push_back(a);
            supg2.push_back(weight(x,y));
        }else{
            fgen1.push_back(a);
            supg1.push_back(weight(x,y));
        }
    }
    
    fclose(gen);
    fclose(cls);
    fclose(pair);
}

void issort(int l,int r,vector<double> &sup,vector<vector<int> > &f,vector<int> &clas){
    if (l>=r) return;
    int i=l,j=r;
    double w=sup[(i+j)/2];
    int w2=clas[(i+j)/2];    
    double tg;
    int tg2;
    vector<int> ttgg;
    
    do{
        while (sup[i]>w||(sup[i]==w&&clas[i]>w2)) i++;
        while (sup[j]<w||(sup[j]==w&&clas[j]<w2)) j--;
        
        if (i<=j){
            tg=sup[i];sup[i]=sup[j];sup[j]=tg;
            tg2=clas[i];clas[i]=clas[j];clas[j]=tg2;
            ttgg=f[i];f[i]=f[j];f[j]=ttgg;
            i++;j--;
        }
    }while(i<j);
    
    if (i<r) issort(i,r,sup,f,clas);
    if (l<j) issort(l,j,sup,f,clas);
}

void issort(int l,int r,vector<double> &sup,vector<vector<int> > &f){
    if (l>=r) return;
    int i=l,j=r;
    double w=sup[(i+j)/2];
    double tg;
    int tg2;
    vector<int> ttgg;
    
    do{
        while (sup[i]>w) i++;
        while (sup[j]<w) j--;
        
        if (i<=j){
            tg=sup[i];sup[i]=sup[j];sup[j]=tg;
            ttgg=f[i];f[i]=f[j];f[j]=ttgg;
            i++;j--;
        }
    }while(i<j);
    
    if (i<r) issort(i,r,sup,f);
    if (l<j) issort(l,j,sup,f);
}

// check if a is inside b ?
int inside(vector<int> a,vector<int> b){
    int i,j=0;
    for (i=0;i<a.size();i++){
        while(j<b.size()&&b[j]<a[i]) j++;
        if (j<b.size()&&b[j]==a[i]) j++;
        else return 0;
    }        
    return 1;
}

int check_redundant(vector<int> a,vector<vector<int> > sav){
    int i;

    for (i=0;i<sav.size();i++)
        if (inside(sav[i],a)) return 0;
    return 1;
}

double score_nonredundant(vector<int> a,int k,vector<double> sup,vector<vector<int> >fgen){
    int i;
    double sum1=0;
        
    for (i=0;i<min((int)sup.size(),k);i++) sum1+=sup[i];

    double sum2=0;
    vector<vector<int> > sav;
    
    for (i=0;i<sup.size();i++)
        if (inside(fgen[i],a)&&check_redundant(fgen[i],sav)){
            sum2+=sup[i];
            k--;
            sav.push_back(fgen[i]);
            if (k==0) break;
        }

//    if (sum1==0) return 0;
    return sum2/sum1;    
}

double score(vector<int> a,int k,vector<double> sup,vector<vector<int> >fgen){
    int i;
    double sum1=0;

    for (i=0;i<min((int)sup.size(),k);i++) sum1+=sup[i];

    double sum2=0;
    
    for (i=0;i<sup.size();i++)
        if (inside(fgen[i],a)){

            sum2+=sup[i];
            k--;
            if (k==0) break;
        }
        
    if (sum1==0) return 0;
    
    return sum2/sum1;
}

void writefile(int k,int h){
    FILE *f;

    f=fopen(writef,"a");

    fprintf(f,"%i %i\n",k,h);
    fclose(f);
}

double score_MMR(vector<int> a,int k,vector<double> sup,vector<vector<int> >fgen,vector<int> clas){
    int i;
    double sum1=0;

    for (i=0;i<min((int)sup.size(),k);i++) sum1+=sup[i];
    
    double sum2=0;
    int sav=-1;
    int cnt=0;
    int h=0;
    
    for (i=0;i<sup.size();i++)
        if (inside(fgen[i],a)){
            if (sav==-1||!inside(fgen[sav],fgen[i])) cnt++;
            sav=i;
            if (cnt>1) break;
            sum2+=sup[i];
            k--;h++;
            if (k==0) break;
        }

    writefile(cnt,h);
    if (sum1==0) return 0;
    return sum2/sum1;
}

double score_represent(vector<int> a,int k,vector<double> sup,vector<vector<int> >fgen,vector<int> clas){
    int i;
    double sum1=0;

    for (i=0;i<min((int)sup.size(),k);i++) sum1+=sup[i];

    double sum2=0;
    int sav=-1;

    for (i=0;i<sup.size();i++)
        if (inside(fgen[i],a)&&clas[i]!=sav){
            sum2+=sup[i];
            k--;
            sav=clas[i];
            if (k==0) break;
        }
    
    return sum2/sum1;
}

void classify_gen(vector<int> a,int k){
    int i;
    
    double sc1=score(a,k,supg1,fgen1);
    double sc2=score(a,k,supg2,fgen2);
    
    cout<<sc1<<endl;
    cout<<sc2<<endl;
}

void classify_cls(vector<int> a,int k){
    int i;
    
    double sc1=score(a,k,supc1,fcls1);
    double sc2=score(a,k,supc2,fcls2);
    
    cout<<sc1<<endl;
    cout<<sc2<<endl;
}

void classify_gen_nonredundant(vector<int> a,int k){
    int i;
    
    double sc1=score_nonredundant(a,k,supg1,fgen1);
    double sc2=score_nonredundant(a,k,supg2,fgen2);
    
    cout<<sc1<<endl;
    cout<<sc2<<endl;
}

void classify_MMR(vector<int> a,int k,vector<int> clas1,vector<int> clas2){

    double sc1=score_MMR(a,k,supg1,fgen1,clas1);
    double sc2=score_MMR(a,k,supg2,fgen2,clas2);

    cout<<sc1<<endl;
    cout<<sc2<<endl;
}

void classify_gen_represent(vector<int> a,int k,vector<int> clas1,vector<int> clas2){
    int i;
    
    double sc1=score_represent(a,k,supg1,fgen1,clas1);
    double sc2=score_represent(a,k,supg2,fgen2,clas2);

    cout<<sc1<<endl;
    cout<<sc2<<endl;
}

/*
void classify_gen_represent(vector<int> a,int k,vector<int> clas1,vector<int> clas2){
    int i;

    double sc1=score_represent(a,k,supg1,fgen1,clas1);
    double sc2=score_represent(a,k,supg2,fgen2,clas2);

    cout<<sc1<<endl;
    cout<<sc2<<endl;
}*/

void classify_neg(vector<int> a,int k,vector<int> clas1,vector<int> clas2){
    
}
    
double score2(vector<int> a,int k,vector<double> sup,vector<vector<int> >fgen){
    int i;
    double sum1=0;
        
    double sum2=0;
    
    for (i=0;i<sup.size();i++)
        if (inside(fgen[i],a)){
            sum2+=sup[i];
            k--;
            if (k==0) break;
        }
    
    return sum2;
}

//int cla1=0,cla0=0;
int clascnt[100];
vector<int> dbs[maxsize];
int clasinfo[maxsize];
int size;
// count the size of each class and read Database
void calSupport(char *fname,char *clas){
    FILE *f;
    
    f=fopen(fname,"r");
    char line[maxlen];
    
    clascnt[1]=0;clascnt[0]=0;
    size=0;
    
    while(fgets(line,maxlen,f)){
        char *s=strtok(line," ");
        if (strcmp(s,clas)==0){
            clascnt[1]++;clasinfo[size]=1;
        }else{
            clascnt[0]++;clasinfo[size]=0;
        }
        
        while(s!=NULL){
            int x;
            sscanf(s,"%i",&x);
            dbs[size].push_back(x);
            s=strtok(NULL," ");
        }
        size++;
    }
    
    fclose(f);
}

double score_nonredundant2(vector<int> a,int k,vector<double> sup,vector<vector<int> >fgen,int sum1){
    int i;

    double sum2=0;
    vector<vector<int> > sav;

    for (i=0;i<sup.size();i++)
        if (inside(fgen[i],a)&&check_redundant(fgen[i],sav)){
            sum2+=sup[i];
            k--;
            sav.push_back(fgen[i]);
            if (k==0) break;
        }
    
    return sum2/sum1;    
}

// new method, sum up the coverage
void classify_gen_nonredundant2(vector<int> a,int k){
    int i,j;
    
    double sc1=score_nonredundant2(a,k,supg1,fgen1,clascnt[1]);
    double sc2=score_nonredundant2(a,k,supg2,fgen2,clascnt[0]);
    
    cout<<sc1<<endl;
    cout<<sc2<<endl;
}

double score_represent2(vector<int> a,int k,vector<double> sup,vector<vector<int> >fgen,vector<int> clas,int sum1){
    int i;

    double sum2=0;
    int sav=-1;

    for (i=0;i<sup.size();i++)
        if (inside(fgen[i],a)&&clas[i]!=sav){
            sum2+=sup[i];
            k--;
            sav=clas[i];
            if (k==0) break;
        }
    
    return sum2/sum1;
}

void classify_gen_represent2(vector<int> a,int k,vector<int> clas1,vector<int> clas2){

    double sc1=score_represent2(a,k,supg1,fgen1,clas1,clascnt[1]);
    double sc2=score_represent2(a,k,supg2,fgen2,clas2,clascnt[0]);
    
    cout<<sc1<<endl;
    cout<<sc2<<endl;
}

int visit[maxsize];
void mark(vector<int> a,int cla){
    int i;
    for (i=0;i<size;i++)
        if (clasinfo[i]==cla&&!visit[i]&&inside(a,dbs[i])) visit[i]=1;
}

// sum up the coverage
double score_cover(vector<int> a,int k,vector<vector<int> >fgen,vector<int> clas,int cla){
    int i;

    double sum2=0;
    int sav=-1;
    vector<vector<int> > bsav;

    for (i=0;i<size;i++) visit[i]=0;
    
    for (i=0;i<fgen.size();i++)
        if (inside(fgen[i],a)&&clas[i]!=sav&&check_redundant(fgen[i],bsav)){
            mark(fgen[i],cla);
            
            k--;
            sav=clas[i];
            bsav.push_back(fgen[i]);
            
            if (k==0) break;
        }

    double re=0;
    for (i=0;i<size;i++)
        if (visit[i]) re++;

    return re/clascnt[cla];
}

void classify_gen_cover(vector<int> a,int k,vector<int> clas1,vector<int> clas2){
    
    double sc1=score_cover(a,k,fgen1,clas1,1);
    double sc2=score_cover(a,k,fgen2,clas2,0);
    
    cout<<sc1<<endl<<sc2<<endl;
}

double disfunc(vector<int> s1,vector<int> s2){
    return (double)s1.size()/s2.size();
}

double ePCL_score(vector<int> a,int k,vector<int> sup,vector<vector<int> >fgen){
    int i;

    double sum2=0;
    int h=k;

    for (i=0;i<sup.size();i++)
        if (inside(fgen[i],a)){
            sum2+=disfunc(fgen[i],a)*(double)sup[i];
            k--;
            if (k==0) break;
        }

    double sum1=0;

    for (i=0;i<min((int)sup.size(),h);i++) sum1+=sup[i];

    return sum2/sum1;
}

void classify_ePCL(vector<int> a,int k,vector<int> clas1,vector<int> clas2){

    double sc1=ePCL_score(a,k,clas1,fgen1);
    double sc2=ePCL_score(a,k,clas2,fgen2);
    
    cout<<sc1<<endl<<sc2<<endl;
}

void readItems(char *fname){
    FILE *f;

    f=fopen(fname,"r");
    char s[maxlen];
    char ch;
    
    while(fgets(s,maxlen,f)!=NULL){
        removeEOF(s);
        int k;
        char *stk=strtok(s," \t");

        ch=stk[0];
        stk=strtok(NULL," \t");
        sscanf(stk,"%i",&k);
        
        if (k==0) k=def_k;

        vector<int> a;
        stk=strtok(NULL," \t");
        
        while(stk!=NULL){
            int x;
            sscanf(stk,"%i",&x);
            a.push_back(x);
            
            stk=strtok(NULL," \t");
        }

        sort(a);
        if (ch=='G'||ch=='g') classify_gen(a,k);
        else if (ch=='C'||ch=='c') classify_cls(a,k);
        else if (ch=='A'||ch=='a') classify_gen_nonredundant(a,k);
//        else if (ch=='B'||ch=='b') classify_cls_nonredundant(a,k);
        else if (ch=='R'||ch=='r') classify_gen_represent(a,k,clas1,clas2);
        else if (ch=='D'||ch=='d') classify_gen_nonredundant2(a,k);
        else if (ch=='E'||ch=='e') classify_gen_represent2(a,k,clas1,clas2);
        else if (ch=='F'||ch=='f') classify_gen_cover(a,k,clas1,clas2);
        else if (ch=='H'||ch=='h') classify_ePCL(a,k,clas1,clas2);
        else if (ch=='M'||ch=='m') classify_MMR(a,k,clas1,clas2);
        else{
            classify_gen(a,k);
            classify_cls(a,k);
        }
    }

    fclose(f);
}

void runOR(char *dbf,char *sup,char *cla){
    int i,j;

    char s1[maxlen];

    cout<<oddfile<<endl;
    if (strcmp(oddfile,"fpmax")==0){
        strcpy(s1,oddfile);        
        
        strncat(s1," -n ",maxlen);
        strncat(s1,cla,maxlen);
        strncat(s1," -r -1 ",maxlen);

        strncat(s1,dbf,maxlen);
        strncat(s1," ",maxlen);
        strncat(s1,sup,maxlen);

        strncat(s1," ",maxlen);
        strncat(s1,tempfile,maxlen);

        system(s1);
                
        strcpy(s1,tempfile);
        strncat(s1,".close",maxlen);

        read(s1);   // read the rules (frequent patterns)
    }else
    if (strcmp(oddfile,"DPM")==0){
        strcpy(s1,oddfile);
        strncat(s1," ",maxlen);
        strncat(s1,dbf,maxlen);
        strncat(s1," 2 ",maxlen);
        strncat(s1,sup,maxlen);
        
        char sdt[maxlen];

        // delta=0
        sprintf(sdt," ");
        strncat(s1,sdt,maxlen);
        strncat(s1,tempfile,maxlen);

        system(s1);

        readDPM(tempfile);
    }else{
    }

    issort(0,supg1.size()-1,supg1,fgen1,clas1);

    issort(0,supc1.size()-1,supc1,fcls1);

    issort(0,supg2.size()-1,supg2,fgen2,clas2);

    issort(0,supc2.size()-1,supc2,fcls2);
}

// classifier datafile infile threshold(absolute) delta miner(opt) main_lass
//    0          1      2          3              4       5          6
int main(int argc,char *arg[]){
    try{
        time_t seconds,current;
        seconds = time (NULL);

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

        if (argc>5) strcpy(oddfile,arg[5]);

        runOR(arg[1],arg[3],arg[6]);

        cout<<"Number of closed patterns 1:"<<supg1.size()<<endl;
        cout<<"Number of closed patterns 2:"<<supg2.size()<<endl;        
        cout<<"#"<<endl;

        calSupport(arg[1],arg[6]);
//        cout<<"class 1 - class 2: "<<clascnt[1]<<" "<<clascnt[0]<<endl;
        readItems(arg[2]);
        
        current = time (NULL);
//        cout<<"Time 2:"<<current-seconds<<endl;      
    }catch( ... ){
        
    }
}
