#include <string.h>
#include <iostream.h>
#include <fstream.h>
#include <stdlib.h>

#include "FStatus.h"
#include "FNet.h"
#include "FPat.h"
#include "misc.h"

/////////////////////////// MAIN PROGRAM ///////////////////////////
int main(void)
{
	char ER[]="ERROR";

	const StrMaxLen=1024;

	char FTASK[]="stats.tsk";
	ifstream tsk;
	char StrBuf[StrMaxLen];
	int str1,str2;
	
	char RES[]="RESULT=";
	char ParamRES[StrMaxLen];
	ofstream fres;
	
	char PATB[]="PAT_BEGIN=";
	char ParamPATB[StrMaxLen];
	char XPATB[StrMaxLen];

	char PATE[]="PAT_END=";
	char ParamPATE[StrMaxLen];
	char XPATE[StrMaxLen];

	char PATEXT[]=".pat";
	char PATX[]="out";

	char PAT_PATH[]="PATS\\";
	
	char NET[]="neural.net";
	
	unsigned int nP, nPB, nPE, xPB, xPE;
	unsigned int nM, nMAX;
	unsigned int nS, nSHIFT;

	unsigned int ln1, ln2;
	
	const LoopMax=16;
	unsigned int lp;

	CFStatus FStatus("stats.out");
	
	char sta[StrMaxLen], stb[StrMaxLen];
	char st2[StrMaxLen], st3[StrMaxLen];

	int ret, sts;

	unsigned int i;

	float learn;
	unsigned char rec;

	bool z1,z2;
	
	//*********** Program ******************************************
	cout << "Fursin Program - 'Statistics for recovering (Hopfield Network)'  (C)  V1.0\n";

	//reading file with task
	tsk.open(FTASK,ios::nocreate|ios::in);
	if (tsk==NULL)
	{
		FStatus.Set(ER,"Can't find file with task",true);
		return 1;
	}		

	//loop for sub-tasks
	do
	{
		// Getting "PAT_BEGIN="
		str1=Rd(tsk, StrBuf, StrMaxLen);
		str2=GetParam(StrBuf, PATB, ParamPATB, StrMaxLen);
		if (str2!=0)
		{
err_quit:
			if (str2==-1) 
			{
				FStatus.Set(ER,"Empty line in file with task",true);
				return 1;
			}
			else if (str2==-2)
			{
				FStatus.Set(ER,"Line is too short in file with task",true);
				return 1;
			}
			else if (str2==-3)
			{
				FStatus.Set(ER,"Can't find reserved words in file with task",true);
				return 1;
			}
			return 1;
		}

		// Getting "PAT_END="
		str1=Rd(tsk, StrBuf, StrMaxLen);
		str2=GetParam(StrBuf, PATE, ParamPATE, StrMaxLen);
		if (str2!=0) goto err_quit;

		// Getting file (output file with results of statistics
		// "RESULT="
		str1=Rd(tsk, StrBuf, StrMaxLen);
		str2=GetParam(StrBuf, RES, ParamRES, StrMaxLen);
		if (str2!=0) goto err_quit;
		
		// Starting recovering
		ln1=strlen(ParamPATB);
		if (strlen(ParamPATE)!=ln1) 
		{
			FStatus.Set(ER,"Length of PAT_BEGIN<>length of PAT_END",true);
			return 1;
		}
		
		nPB=hextoint(ParamPATB);
		nPE=hextoint(ParamPATE);
	
		if (nPB>nPE) 
		{
			FStatus.Set(ER,"PAT_BEGIN > PAT_END",true);	
			return 1;
		}

		nMAX=nPE-nPB+1;
		
		//General loop
		fres.open(ParamRES,ios::out | ios::unitbuf);
		if (fres==NULL)
		{
			FStatus.Set(ER,"Can't open output file",true);
			return 1;
		}		
		
		cout.setf(ios::unitbuf);
		
		fres << "Fursin Program - 'Statistics for recovering (Hopfield Network)'  (C)  V1.0\n";
		fres << "\n";			cout << "\n";

		fres << "  1|";			cout << "  1|";
		fres.width(nMAX);		cout.width(nMAX);
		fres.fill(' ');			cout.fill(' ');
		fres << "2";			cout << "2";
		fres.width();			cout.width();
		fres.fill(' ');			cout.fill(' ');
		fres << "|    3\n";		cout << "|    3\n";

		fres << "---|";			cout << "---|";
		fres.width(nMAX);		cout.width(nMAX);
		fres.fill('-');			cout.fill('-');
		fres << "";				cout << "";
		fres.width();			cout.width();
		fres.fill(' ');			cout.fill(' ');
		fres << "|-----\n";		cout << "|-----\n";
		
		for (nM=1; nM<=nMAX; nM++)
		{
			//Loop for shifts of patterns
			nSHIFT=nMAX-nM+1;
			learn=0;
					
			for (nS=1; nS<=nSHIFT; nS++)
			{
				if (nS==1)
				{
					fres.width(3);		cout.width(3);
					fres.fill(' ');		cout.fill(' ');
					fres << nM;			cout << nM;
					fres << "|";		cout << "|";
				}
				else
				{
					fres.width(3);		cout.width(3);
					fres.fill(' ');		cout.fill(' ');
					fres << "";			cout << "";
					fres << "|";		cout << "|";
				}
				
				//Ready to start learning
				CFNet *pFNet = new CFNet(NET, "", StrMaxLen);

				xPB=nPB+nS-1;
				xPE=xPB+nM-1;
										
				strcpy(XPATB,"");
				itoa(xPB, st2, 16);
				strupr(st2);
				ln2=strlen(st2);
				if (ln2<ln1)
				{
					strcpy(st3,"12345678901234567890123456789012");
					strnset(st3,'0',ln1-ln2);
					st3[ln1-ln2]='\0';
					strcat(XPATB,st3);
				}
				strcat(XPATB,st2);

				strcpy(XPATE,"");
				itoa(xPE, st2, 16);
				strupr(st2);
				ln2=strlen(st2);
				if (ln2<ln1)
				{
					strcpy(st3,"12345678901234567890123456789012");
					strnset(st3,'0',ln1-ln2);
					st3[ln1-ln2]='\0';
					strcat(XPATE,st3);
				}
				strcat(XPATE,st2);
	
				sts=pFNet->Learn(XPATB, XPATE, PATEXT, PAT_PATH, true);
				delete pFNet;

				if (sts!=0)
				{
					if (sts==-1)
					{
						FStatus.Set(ER,"Length of PAT_BEGIN<>length of PAT_END",true);
						return 1;
					}
					else if (sts==-2)
					{
						FStatus.Set(ER,"PAT_BEGIN > PAT_END",true);
						return 1;
					}
					else if (sts==-3)
					{
						FStatus.Set(ER,"Dimensions of patterns for neural network are different",true);
						return 1;
					}
					else if (sts==-4)
					{
						FStatus.Set(ER,"Can't save neural network",true);
						return 1;
					}
					else if (sts==-11)
					{
						FStatus.Set(ER,"Can't open file with pattern",true);
						return 1;
					}
					else if (sts==-12)
					{
						FStatus.Set(ER,"Unexpected end of file with pattern",true);
						return 1;
					}
					else if (sts==-13)
					{
						FStatus.Set(ER,"Unknown character in pattern",true);
						return 1;
					}

					return 1;
					
				}

				//Loop for patterns (RECOVERING)
				for (i=1; i<nS; i++)
				{
					fres << " ";		cout << " ";
				}
				
				//Loading Network
				CFNet *pNet = new CFNet(NET, "", StrMaxLen);
				ret=pNet->Load();
				if (ret==-1)
				{
					FStatus.Set(ER,"Can't open file with neural network",true);
					return 1;
				}
				else if (ret==-2)
				{
					FStatus.Set(ER,"Unexpected end of file with neural network",true);
					return 1;
				}
				
				for (nP=nS; nP<nS+nM; nP++)
				{
					xPB=nPB+nP-1;
															
					strcpy(XPATB,"");
					itoa(xPB, st2, 16);
					strupr(st2);
					ln2=strlen(st2);
					if (ln2<ln1)
					{
						strcpy(st3,"12345678901234567890123456789012");
						strnset(st3,'0',ln1-ln2);
						st3[ln1-ln2]='\0';
						strcat(XPATB,st3);
					}
					strcat(XPATB,st2);
					strcpy(sta,PAT_PATH);
					strcat(sta,XPATB);
					strcat(sta,PATEXT);

					//Loading input pattern (sta or XPATB)
					CFPat *pPatInp=new CFPat('.','O');
					ret=pPatInp->Load(sta);
					if (ret==-1)
					{
						FStatus.Set(ER,"Can't open file with pattern",true);
						return 1;
					}
					else if (ret==-2)
					{
						FStatus.Set(ER,"Unexpected end of file with pattern",true);
						return 1;
					}
					else if (ret==-3)
					{
						FStatus.Set(ER,"Unknown character in pattern",true);
						return 1;
					}
				
					strcpy(sta, PAT_PATH);
					strcat(sta, XPATB);
					strcat(sta,PATEXT);

					strcpy(stb, PAT_PATH);
					strcat(stb, PATX);
					strcat(stb,PATEXT);

					//Recovering -----------------------------------------
					for (lp=1; lp<=LoopMax; lp++)
					{
						//Making first pattern in RAM
						CFPat *pPatX=new CFPat('.','O');
						ret=pPatX->Load(sta); //Errors were checked in the previous attempt
											
						//Making output pattern in RAM
						CFPat *pPatOut=new CFPat('.','O');
						ret=pPatOut->Create(pPatX->DimX(),pPatX->DimY());

						//Recovering from sta to stb
						ret=pNet->Recover(pPatX, pPatOut);	
						if (ret==-1)
						{
							FStatus.Set(ER,"Dimensions of patterns are different",true);
							return 1;
						}
			
						//Saving output pattern (PATX)
						ret=pPatOut->Save(stb);
						if (ret==-1)
						{
							FStatus.Set(ER,"Can't save output file with pattern",true);
							return 1;
						}

						//Comparing XPATB and PATX
						z1=pNet->Compare(pPatX, pPatOut);
						z2=pNet->Compare(pPatInp, pPatOut);
						delete pPatX, pPatOut;

						if (z1) break; //If equal then quit from loop
				
						//Not Equal
						strcpy(sta,stb);
					}
					delete pPatInp;
					
					if (z2) rec=1; // if Input pattern is equal
								   // to Recoverd pattern!
					else rec=0;

					if (rec==1) 
					{
						fres << "1";		cout << "1";
					}
					else
					{
						fres << "0";		cout << "0";
					}

					learn+=rec;
				}
			
				delete pNet;
				
				for (i=nS+nM; i<=nMAX; i++)
				{
					fres << " ";		cout << " ";
				}

				if (nS==nSHIFT)
				{
					learn=learn/(nMAX-nM+1);

					fres << "|";				cout << "|";
					fres.setf(ios::fixed);		cout.setf(ios::fixed);
					fres.precision(1);			cout.precision(1);
					fres.fill(' ');				cout.fill(' ');
					fres.width(5);				cout.width(5);
					fres << learn;				cout << learn;
					fres.width();				cout.width();
				}
				else
				{
					fres << "|   ";			cout << "|   ";
				}
				fres << "\n";			cout << "\n";
			}
			
			fres << "---|";			cout << "---|";
			fres.width(nMAX);		cout.width(nMAX);
			fres.fill('-');			cout.fill('-');
			fres << "";				cout << "";
			fres.width();			cout.width();
			fres.fill(' ');			cout.fill(' ');
			fres << "|-----\n";		cout << "|-----\n";
		
		}
		fres.close();
	
		//Read empty line or find EOF
		str1=Rd(tsk, StrBuf, StrMaxLen); 
	}
	while(str1>0);
		
	tsk.close();
	
	if (str1==-1)
	{
		FStatus.Set(ER,"String is too long in file with task",true);
		return 1;
	}
		
	FStatus.Set("OK","",false);

	return 0;
}
