#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

#include <stdio.h>
#include <string.h>
#include <assert.h>
//#include <stdlib.h>
#include <iostream>
//#include <fstream.h>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <time.h>
#include <math.h>

#include "common.h"
#include "buffer.h"
#include "ec_storage.h"
#include "fk_tree.h"

using namespace std;


#define LINT sizeof(int)
#define KFLEN 1000


stack* list;

int* order_item;   // given order i, order_item[i] gives the original itemname, corresponding to table
int* item_order;   // given item i, item_order[i] gives its new order, corresponding to order

int* item_support;
int* item_support_new;
int* in_map; //array to facilliate array intersection
int* in_map1;
//int* in_map2;

int* fullItem=NULL;     // the items with full support, maybe item, maybe the index.
int  fullNum=0;

ec_storage *ECstorage;

int TRANSACTION_NO=0;
int OLD_TRAN_NO=0;
int NEW_TRAN_NO=0;
int DEC_TRAN_NO=0;
//int POSITIVE_NO=0;
int OLD_ITEM_NO;
int VALID_ITEM_NO; //net_item_no - fullNum
int OLD_VALID_ITEM_NO;
int ITEM_NO=0;
int NET_ITEM_NO;
//int MAX_ITEM=0;
int MAX_TRAN_LEN = 0; //max incremental transaction length

int THRESHOLD;
//int INC_THRESHOLD;

int UPDATE_VERSION=0;
//int INV_GEN = 0; //for statistical studies

memory* buf;
memory* fp_buf;

//for debug
int nodeCount=0;

int main(int argc, char **argv)
{	
	char* inFileName=NULL;
	char* inFileName1=NULL;
	char* inFileName2 = NULL;
	char* outFileName=NULL;
	double threshold=0;
	int    nFull=0;
	int i=0;
	int blprint = 0; //default
	int updTranNum=0;
	int decTranNum=0;
	char tempFileName[128];

	if(argc<5)
	{
		cout << "usage: psm [options...]" <<endl;
		cout << "-e infile(existing)" <<endl;
		cout << "-i infile(incremental)" <<endl;
		cout << "-d infile(decremental)" <<endl;
		cout << "-s MINSUP" <<endl;
		cout << "-o outfile" <<endl;
		cout << "-iu incremental update size" <<endl;
		cout << "-du decremental update size" <<endl;
		cout << "-p print? 1 or 0"<<endl;
		exit(1);
	}
	//printf("%d\n", argc);
	while(i<argc)
	{
		//printf("%s\n", argv[i]);
		if(strcmp(argv[i],"-e")==0) //input file name
		{
			i++;
			inFileName = argv[i++];
			printf("inFileName: %s\n", inFileName);
			continue;
		}
		
		if(strcmp(argv[i],"-i")==0) //inc dataset
		{
			i++;
			inFileName1 = argv[i++];
			printf("inFileName1: %s\n", inFileName1);
			continue;
		}

		if(strcmp(argv[i],"-d")==0) //inc dataset
		{
			i++;
			inFileName2 = argv[i++];
			printf("inFileName2: %s\n", inFileName2);
			continue;
		}

		if(strcmp(argv[i],"-s")==0) //support threshold
		{
			i++;
			threshold = atof(argv[i++]);
			printf("ms: %f\n", threshold);
			continue;
		}

		if(strcmp(argv[i],"-o")==0) //output file
		{
			i++;
			outFileName = argv[i++];
			printf("outFileName: %s\n", outFileName);
			continue;
		}

		if(strcmp(argv[i],"-iu")==0) //update size
		{
			i++;
			updTranNum = atoi(argv[i++]);
			printf("incremental update num: %d\n", updTranNum);
			continue;
		}

		if(strcmp(argv[i],"-du")==0) //update size
		{
			i++;
			decTranNum = atoi(argv[i++]);
			printf("decremental update num: %d\n", decTranNum);
			continue;
		}

		if(strcmp(argv[i],"-p")==0) //print or not
		{
			i++;
			blprint = atoi(argv[i++]);
			printf("print: %d\n", blprint);
			continue;
		}

		i++;
	}

	NEW_TRAN_NO = updTranNum;
	DEC_TRAN_NO = decTranNum;

	buf=new memory(60, 4194304L, 8388608L, 2);
	fp_buf=new memory(60, 4194304L, 8388608L, 2);
	
	/****************** read in stats ***********************/
	strcpy_s(tempFileName,inFileName);
	strcat_s(tempFileName,".close");
	
	Data* fdatClose = new Data(tempFileName);
	
	if(!fdatClose->isOpen()) {
		cerr << inFileName << " could not be opened!" << endl;
		exit(2);
	}
	
	fdatClose->readStat();

	/****************** declare fk tree, read in existing tree n read in inc/dec dataset ***********************/
	FK_tree* glotree;
	glotree = (FK_tree*)fp_buf->newbuf(1, sizeof(FK_tree));
	
	//initial global tree
	glotree->init(-1, 0);
	glotree->fullSet = NULL; //exclude full items from the tree
	glotree->fullSize = 0;

	Data* fdat = NULL; //default case for support change maintenance

	if(inFileName1 && NEW_TRAN_NO) //for incrmental maintenance
	{
		fdat = new Data(inFileName1);

		if(!fdat->isOpen()) {
			cerr << inFileName1 << " could not be opened!" << endl;
			exit(2);
		}
	}
	

	//update item_support, TRANSACTION_NO, NET_ITEMNO, ITEM_NO, detect new items
	//inc dataset is stored in tranStore
	if(fdat)
		glotree->scan1_DB(fdat, threshold);

	//first scan of dec dataset
	Data* fdatDec = NULL;
	
	if(inFileName2 && DEC_TRAN_NO)
	{
		fdatDec = new Data(inFileName2);

		if(!fdatDec->isOpen()) {
			cerr << inFileName2 << " could not be opened!" << endl;
			exit(2);
		}
	}
	
	if(fdatDec)
		glotree->DecScan1_DB(fdatDec);

	//update support threshold
	if(threshold<1)
	{
		THRESHOLD=(int)ceil(threshold*TRANSACTION_NO);
		//INC_THRESHOLD = (int) ceil(threshold*NEW_TRAN_NO);
	}
	else
		THRESHOLD = threshold;

	//read in exisiting tree
	strcpy_s(tempFileName,inFileName);
	strcat_s(tempFileName,".tree");
	
	Data* fdatTree = new Data(tempFileName);
	
	if(!fdatTree->isOpen()) {
		cerr << inFileName << " could not be opened!" << endl;
		exit(2);
	}
	
	fdatTree->getGCtree(glotree);
	
	fdatTree->close();
	delete fdatTree;

	//declare intersectin maps
	in_map = (int*) buf->newbuf(NET_ITEM_NO, INTSIZE); //for key mapping
	in_map1 = (int*) buf->newbuf(NET_ITEM_NO, INTSIZE); //for branch mapping
	
	for(i=0;i<NET_ITEM_NO;i++)
	{
		in_map[i]=0;
		in_map1[i] = 0;
	}

	/****************** read in existing ecs ***********************/
	ECstorage = new ec_storage();
	ECstorage->init();
	ECstorage->fkTree = glotree;

	ECstorage->readOldEC(fdatClose);

	/****************** read in ngb ***********************/
	strcpy(tempFileName,inFileName);
	strcat(tempFileName,".neg");
	
	Data* fdatNGB = new Data(tempFileName);
	
	if(!fdatNGB->isOpen()) {
		cerr << inFileName << " could not be opened!" << endl;
		exit(2);
	}
	
	fdatNGB->readNGB();
	
	fdatClose->close();
	delete fdatClose;

	//include new items into ngb
	if(inFileName1 && NEW_TRAN_NO) //for incrmental maintenance
	{
		int* iset;

		for(i=OLD_VALID_ITEM_NO; i<VALID_ITEM_NO;i++)
		{
			iset = (int*)buf->newbuf(1, INTSIZE);
			iset[0] = i;
			//the key support will be updated together with existing keys
			ECstorage->insertNBG(iset, 1, 0); 
		}
	}
	
	
	/****************** update starts ***********************/
	clock_t startTime = clock();

	if(NEW_TRAN_NO) //incremental update
	{
		if(DEC_TRAN_NO && inFileName2) //decrmental update
		{

			ECstorage->DecUpdateEC(fdatDec);
			ECstorage->expandNGB();
		}

		ECstorage->updateEC(fdat);
		printf("%f\n", (clock()-startTime)*1.0/CLOCKS_PER_SEC);
		//printf("%d\n", INV_GEN);
	}
	else if(DEC_TRAN_NO && inFileName2) //decrmental update
	{

		ECstorage->DecUpdateEC(fdatDec);
		ECstorage->expandNGB();
		printf("%f\n", (clock()-startTime)*1.0/CLOCKS_PER_SEC);
	}
	else //threshold adjustment update
	{
		ECstorage->expandNGB();
		printf("%f\n", (clock()-startTime)*1.0/CLOCKS_PER_SEC);
	}

	/****************** output results ***********************/
	FSout* fout=NULL;
	FSout* fout1 = NULL;

	strcpy_s(tempFileName,outFileName);
	strcat_s(tempFileName,".re");
	fout = new FSout(tempFileName);

	fout->printTime("Maintenance time: ", (clock()-startTime)*1.0/CLOCKS_PER_SEC);

	fout->close();
	delete fout;

	if(fdat)
	{
		fdat->removeTS();

		fdat->close();
		delete fdat;
	}

	if(fdatDec)
	{
		fdatDec->removeTS();
		delete fdatDec;
	}
	
	if(blprint)
	{
		double closePatterns=0;
		double keyPatterns=0;

		//output tree
		strcpy_s(tempFileName,outFileName);
		strcat_s(tempFileName,".tree");
		fout = new FSout(tempFileName);
		
		glotree->outputTree(fout);
		
		fout->close();
		delete fout;

		//output ecs
		strcpy_s(tempFileName,outFileName);
		strcat_s(tempFileName,".close");
		fout = new FSout(tempFileName);
		
		fout->printDigit(TRANSACTION_NO);
		fout->printString(" ");
		
		fout->printDigit(NET_ITEM_NO);
		fout->printString(" ");
		
		fout->printDigit(ITEM_NO);
		fout->printString(" ");
		
		fout->printDigit(fullNum);
		
		fout->printString("\n");
		
		fout->printCount();
		
		fout->printOrderItem();

		if(fullNum)
			fout->printOrderSet(fullNum, fullItem, -1);

		fout->printString("\n");
		
		//output closed n key patterns
		ECstorage->outputEC(fout,closePatterns,keyPatterns);
		
		fout->close();
		delete fout;
		
		//output keys & ngb
		strcpy_s(tempFileName,outFileName);
		strcat_s(tempFileName,".key");
		fout = new FSout(tempFileName);

		strcpy(tempFileName,outFileName);
		strcat(tempFileName,".neg");
		fout1 = new FSout(tempFileName);
		
		ECstorage->outputKey(fout,fout1, keyPatterns);

		//for debug
		//ECstorage->outputNGB(fout1);
		
		fout->close();
		delete fout;
		
		fout1->close();
		delete fout1;

		printf("closed pattern: %0.f, key patterns: %0.f \n", closePatterns, keyPatterns);
	}

	
	delete ECstorage;
	delete buf;
	delete fp_buf;

	delete list;

	_CrtDumpMemoryLeaks();

	return 0;
}

