/**
 * Main routine, RandomForest. 
 * This program is based on C4.5 Release 5 by J.R. Quinlan.
 *
 * @author Baoxun Xu (Programmer)
 * @version $Revision: 1.0 $
 */


#include "defns.h"
#include "types.h"



/*  The definition of global variables  */

long	*SampleAttr=NULL,UnSampleMaxAtt,
        MaxAtt, MaxClass, MaxDiscrVal = 2;
long	SampleAttNum;

long	*OOBData = NULL;
long	OOBDataLength=0;

ItemNo	TDMaxItem;
Description	*TDItem = NULL;

ItemNo	UnSampleMaxItem,
        MaxItem;

Description	*UnSampleItem = NULL,*Item= NULL;

DiscrValue	*UnSampleMaxAttVal= NULL,*MaxAttVal= NULL;

char		*UnSampleSpecialStatus= NULL,*SpecialStatus= NULL;

float   **Q;

long *OOBDataVoteResult;
long *TestDataVoteResult;

String	*ClassName=NULL,
		*UnSampleAttName= NULL,*AttName= NULL,
		**UnSampleAttValName,**AttValName,
		FileName = "DF";//The name of data file

long **OOBTable,
     **TDResult;


//////Output file definition//////
FILE *Pn;
char outFile[100];
//////////////////////////////////

long	VERBOSITY = 0;

//The number of Building tree
long	TreeNum = 1;

//Weight Type:1.Breiman, 2.Chisquare, 3.Information gain ratio
short   WeightMethodType = 1;

// Subspace size
long   SampleAttribute = 1;

long   randomSeed;

float RFstrength,Correlation,ErrorBound,TestError,OOBError;

long   *AttFlag=NULL;


Boolean		GAINRATIO  = true,
		SUBSET     = false,
		UNSEENS    = false;

ItemNo		MINOBJS   = 2;

Boolean		AllKnown = true;


    main(Argc, Argv)
/*  ----  */
    int Argc;
    char *Argv[];
{
    long o;
    long i,j,s,y,ii;
    extern char *optarg;
    extern int optind;
    Boolean FirstTime=true;
    long Best, BestTree();

    randomSeed=1;// random seed of sample (attribute and data)
    PrintHeader("decision trees generator");

    /*  Process options  */

	while ( (o = getopt(Argc, Argv, "f:uv:gsm:k:a:r:d:")) != EOF )
    {
	if ( FirstTime )
	{
	    printf("\n   Options:\n");
	    FirstTime = false;
	}

	switch (o)
	{
	case 'f':   FileName = optarg;
		    printf("\tFile stem <%s>\n", FileName);
		    break;
	case 'u':   UNSEENS = true;
		    printf("\tTrees evaluated on unseen cases\n");
		    break;
	case 'v':   VERBOSITY = atoi(optarg);
		    printf("\tVerbosity level %d\n", VERBOSITY);
		    break;
	case 'g':   GAINRATIO = false;
		    printf("\tGain criterion used\n");
		    break;
	case 's':   SUBSET = true;
		    printf("\tTests on discrete attribute groups\n");
		    break;
	case 'm':   MINOBJS = atoi(optarg);
		    printf("\tSensible test requires 2 branches with >=%d cases\n",
			    MINOBJS);
		    Check(MINOBJS, 1, 1000000);
		    break;
	case 'k':   TreeNum = atoi(optarg);
            printf("\tTree Number <%d>\n", TreeNum);
		    Check(TreeNum, 1, 10000);
		    break;

	case 'a':   WeightMethodType = atoi(optarg);
			printf("\tWeightMethodType  <%d>\n", WeightMethodType);
			Check(WeightMethodType, 1, 10000);
			break;

	case 'r':   randomSeed = atoi(optarg);
            printf("\tRandomSeed Number <%d>\n", randomSeed);
		    Check(randomSeed, 1, 2000000000);
		    break;

	case 'd':   SampleAttribute = atoi(optarg);
			printf("\tSampleAttribute  <%d>\n", SampleAttribute);
			Check(SampleAttribute, 1, 10000);
			break;

	case '?':   printf("unrecognised option\n");
		    exit(1);
	}
    }

    /*  Initialise  */


	//Get trainning data and testing data

    GetNames();

	GetData(".data");

	if(UNSEENS)
	{
		GetTestData(".test");
	}

	printf("\n**OriginTrainDataSize=%d,TestDataSize=%d**\n",UnSampleMaxItem+1,TDMaxItem+1);


    //The number of sampled attribute
	SampleAttNum = SampleAttribute-1;

	OOBTable = (long **) calloc(TreeNum, sizeof(long *));
	TDResult = (long **) calloc(TreeNum, sizeof(long *));


	for(i=0;i<TreeNum;i++)
	{
		printf("\n********Build NO %d tree!*****",i+1);

		//dynamic alloc column space
		OOBTable[i] = (long *) calloc(UnSampleMaxItem+1, sizeof(long));
		OOBData = (long *) calloc(UnSampleMaxItem+1,sizeof(long));

		GetMatrixNames();
		GetSampleData();

        //build tree
		OneTree();

		//Free Memory
		for(ii=0;ii<= MaxItem;ii++)
		{
			free(Item[ii]);
            Item[ii]=NULL;
		}
		free(Item);
		Item = NULL;

		GetMatrixData();

		EvaluateMatrix(i);

		if ( UNSEENS )
		{
			TDResult[i] = (long *) calloc(TDMaxItem+1, sizeof(long));
			EvaluateTestDataMatrix(i);
		}

		//Free Memory
		for(ii=0;ii<= MaxItem;ii++)
		{
			free(Item[ii]);
            Item[ii]=NULL;
		}
		free(Item);
		Item = NULL;

		free(AttName);
		AttName =NULL;

		free(MaxAttVal);
		MaxAttVal =NULL;

	    free(SpecialStatus);
		SpecialStatus =NULL;

		for(ii=0;ii< 100;ii++)
		{
			free(AttValName[ii]);
			AttValName[ii] =NULL;
		}
		free(AttValName);
		AttValName=NULL;

		free(OOBData);
		OOBData = NULL;

	}//The end of building trees


	GetMatrixData();
	GetStrength();

	GetOOBVoteResult();
	EvaluateOOBRFResult();

	if ( UNSEENS )
	{
		GetVoteResult();
		EvaluateRFResult();
	}

	//Free Memory
	for(i=0;i<= MaxItem;i++)
    {
		free(Item[i]);
		Item[i]=NULL;
	}
	free(Item);
	Item = NULL;

	for(i=0;i<TreeNum;i++)
	{
		free(OOBTable[i]);
		free(TDResult[i]);
		OOBTable[i] = NULL;
		TDResult[i] = NULL;
	}
    free(OOBTable);
    OOBTable = NULL;
	free(TDResult);
	TDResult=NULL;

	for(i=0;i<=UnSampleMaxItem;i++)
    {
		free(Q[i]);
		Q[i]=NULL;
	}
	free(Q);
	Q = NULL;

	free(OOBDataVoteResult);
	OOBDataVoteResult = NULL;

	free(TestDataVoteResult);
	TestDataVoteResult = NULL;


	printf("\nSubspaceSize:%d\t",SampleAttNum+1);
	printf("TreeNumber:%d\n",TreeNum);
	printf("Strength=%f\n",RFstrength);
	printf("Correlation=%f\n",Correlation);
	printf("ErrorBound=%f\n",ErrorBound);
	printf("Accuracy=%f\n",1.0000-TestError);


	//  Open output file/
	strcpy(outFile, FileName);
	strcat(outFile, ".out");

	if ( ! ( Pn = fopen(outFile, "ab+") ) )  Error(0, Pn, "");

	if( WeightMethodType ==1)
	{
		fprintf(Pn,"\n Breiman Method\n");
	}
	else if( WeightMethodType ==2)
	{
		fprintf(Pn,"\n Weight Method--CS \n");
	}
	else if( WeightMethodType ==3)
	{
		fprintf(Pn,"\n Weight Method--IGR\n");
	}
	else{}

	fprintf(Pn,"\n%d\t",SampleAttNum+1);
	fprintf(Pn,"%d\t",TreeNum);
	fprintf(Pn,"%f\t",RFstrength);
	fprintf(Pn,"%f\t",Correlation);
	fprintf(Pn,"%f\t",ErrorBound);
	fprintf(Pn,"%f\n",TestError);

	fclose(Pn);

  //  getchar();
    exit(0);

}
