#pragma warning(disable: 4312 4311)

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include "defs.h"

#include "pla.h"

using namespace std;

uint PLA::get_histogram(PLA_Input_Var_Histogram& hst)
{
	uint i;
	PLA_Input_Var_Histogram::iterator iter;
	PLA_Input_Var_Histogram hst2;

	hst.clear();

	for (i=0; i<i_num; i++)
		hst.push_back(PLA_Input_Var_Histogram_Item(i,0));

	for (uint r=0; r<rows.size(); r++)
	{
		for (iter=hst.begin(), i=0; i<i_num; i++,iter++)
		{
			if ((rows[r].inputs[i] != TERM_X) && (rows[r].outputs[0] != TERM_0))
				iter->num = iter->num+1;
		}
	}

	sort(hst.begin(),hst.end());

	for (iter=hst.begin(); iter!=hst.end(); iter++)
	{
		vector<uint> ngh;
		for (i=0; i<i_num; i++)
			ngh.push_back(0);

		for (uint r=0; r<rows.size(); r++)
		{
			uint cnt=iter->id+1;
			while ((cnt < i_num) && (rows[r].inputs[cnt] == TERM_X)) 
				cnt++;

			if (cnt < i_num)
				ngh[cnt]++;
		}
		//sort(nbg.begin(),nbg.end());

		uint v=0,c=0;
		for (uint i=0; i<ngh.size(); i++)
		{
			if (ngh[i] > c)
			{
				c = ngh[i];
				v=i;
			}
		}
		iter->bngb = v;
	}


	return 0;
}

uint PLA::print_histogram(PLA_Input_Var_Histogram& hst)
{
	PLA_Input_Var_Histogram::iterator iter;

	for (iter=hst.begin(); iter!=hst.end(); iter++)
		cout << "id: " << iter->id << "; num: " << iter->num << "; nbg: " << iter->bngb << endl; 

return 0;
}

uint PLA::get_stats(PLA_Stats& s)
{
	s.lit_num=0;
	
	s.lit_num = 0;
	s.x_term_num = 0;
	s.term_num = 0;

	for (uint r=0; r<rows.size(); r++)
	{
		for (uint i=0; i<i_num; i++)
		{
			if (rows[r].inputs[i] != TERM_X)
				s.lit_num++;
		}
	}

	s.term_num = (uint) rows.size();
	
	for (uint r=0; r<rows.size(); r++)
	{
		if (rows[r].outputs[0] == TERM_X)
			s.x_term_num++;
	}

 return 0;
}

uint PLA::save(char* filename)
{
	string s;

	s  = ".i " + to_string(i_num) + "\n";
	s += ".o " + to_string(o_num) + "\n";
	s += ".p " + to_string((uint)rows.size()) + "\n";

	for (uint r=0; r<rows.size(); r++)
	{
		for (uint i=0; i<rows[r].inputs.size(); i++)
		{
			if (rows[r].inputs[i] == TERM_X)
				s+="-";
			else if (rows[r].inputs[i] == TERM_1)
				s+="1";
			else if (rows[r].inputs[i] == TERM_0)
				s+="0";
		}

		s += " " + to_string((uint)rows[r].outputs[0]) + "\n";

	}
	s += ".e";

	fstream f(filename, ios::out);
	f<<s;
	f.close();

 return 0;
}


uint PLA::load(char* filename)
{
	uint ret;
	string s;
	uint r=0;
	PLA_Row row;

	fstream f(filename, ios::in);

	if (NULL == f)
	{
		ret = PLA_TABLE_ERROR___CANT_OPEN_FILE;
		goto PLA_LOAD_ERROR;
	}

	i_num = o_num = 0;

	while(!f.eof()) 
	{
		getline(f,s);

		if (0 == s.size())
			continue;

		if (s[0] == '#')
		{
			continue;
		}
		else
		if (s[0] == '.')
		{
			if (s[1] == 'i')
			{
				if (s[2] == ' ')
					i_num = atoi(s.data()+2);
				//if (i_num > 31)
				//{
				//	ret = PLA_TABLE_ERROR___TOO_MANY_VARS;
				//	goto PLA_LOAD_ERROR;
				//}
			}
			else if (s[1] == 'o')
			{
				if (s[2] == ' ')
					o_num = atoi(s.data()+2);
			}
			else if (s[1] == 't' && s[2] == 'y' && s[3] == 'p' && s[4] == 'e')
			{
				uint i = 5;
				while (s[i] == ' ') i++;

				if (s[i]=='f' && s[i+1]=='r')
				{
					ret = PLA_TABLE_ERROR___UNSUPPORTED_FORMAT;
					goto PLA_LOAD_ERROR;
				}
			}
		}
		else
		{
			if (!(i_num && o_num))
			{
				ret = PLA_TABLE_ERROR___INCORRECT_DATA;
				goto PLA_LOAD_ERROR;
			}

			row.inputs.clear();
			row.outputs.clear();

			uint i;

			for (i=0; i<i_num; i++)
			{
				if (s[i] == '0')
					row.inputs.push_back(TERM_0);
				else if (s[i] == '1')
					row.inputs.push_back(TERM_1);
				else if (s[i] == '-')
					row.inputs.push_back(TERM_X);
				else
				{
					ret = PLA_TABLE_ERROR___INCORRECT_DATA;
					goto PLA_LOAD_ERROR;
				}
			}

			while ((s[i] == ' ') || (s[i] == '\t') || (s[i] == '|')) i++;

			for (uint n=0; n<o_num; n++)
			{
				if (s[i+n] == '0')
					row.outputs.push_back(TERM_0);
				else if (s[i+n] == '1')
					row.outputs.push_back(TERM_1);
				else if ((s[i+n] == '-') || (s[i+n] == '~') || (s[i+n] == '2'))
					row.outputs.push_back(TERM_X);
				else
				{
					ret = PLA_TABLE_ERROR___INCORRECT_DATA;
					goto PLA_LOAD_ERROR;
				}
			}
			
			rows.push_back(row);
		}
	}	

	ret = PLA_TABLE_ERROR___OK;

PLA_LOAD_ERROR:;

	if (f != NULL)
		f.close();

 return ret;
}


void PLA::or_pla(PLA& pla)
{
	if ((pla.i_num != i_num) || (pla.o_num != o_num))
		return;

	for (uint i=0; i<pla.rows.size(); i++)
		rows.push_back(pla.rows[i]);
}
void PLA::and_var(uint var, uint val)
{
	if (val >= i_num)
		return;

	for (uint i=0; i<rows.size(); i++)
		rows[i].inputs[var] = val;
}