#include "stdafx.h"
#include <sstream>
#include "Impl.h"
#include "ImplList.h"
#include "Separator.h"
#include "func.h"

ImplList::ImplList( std::string l ) : std::list<Impl*>()
{
	BM length = l.length();
	if (!isPow2(length))
		throw 1;

	this->Nargs = 0;
	for (BM i=length; !(i&1); i>>=1)
		this->Nargs++;

	for (BM n = 0; n < length; n++)
	{
		char c = l[n];
		Impl *ex = 0;
		switch (c)
		{
		case '0':
			//Nothing to do
			break;
		case '1':
			ex = new Impl(n);
			break;
		case '-':
			ex = new Impl(n, true);
			break;
		default:
			throw 2;
		}
		if (ex)
			this->push_back(ex);
	}
}

#define FOREACH(o, i) for (ImplList::iterator i=o.begin(); i!=o.end(); i++)
#define TFOREACH(i) FOREACH((*this), i)

/* Const foreach */
#define CFOREACH(o, i) for (ImplList::const_iterator i=o.begin(); i!=o.end(); i++)
#define TCFOREACH(i) CFOREACH((*this), i)

ImplList::ImplList(ImplList &c) : std::list<Impl*>()
{
	this->Nargs = c.Nargs;
	CFOREACH(c, it)
		this->push_back(new Impl(**it));

}
ImplList::ImplList(ImplList &c, BM excl) : std::list<Impl*>()
{
	this->Nargs = c.Nargs;
	CFOREACH(c, it)
	{
		if (!(excl & 1))
			this->push_back(new Impl(**it));
		excl >>= 1;
	}
}

bool ImplList::getValue(BM num, BM excl) const
{
	TCFOREACH(it)
	{
		if (!(excl & 1) && ((*it)->getVal(num)))
		{
			return true;
		}
		excl >>=1;
	}
	return false;
}

std::string ImplList::getValuesLine( void ) const
{
	std::string r;
	for (BM n=0; n < (1UL << this->Nargs); n++)
	{
		bool val = getValue(n);
		r += val ? "1" : "0";
	}
	return r;
}

ImplList::~ImplList(void)
{
	TFOREACH(it)
		delete *it;
}

void ImplList::Normalize( void )
{
	this->sort(compIndex);
	this->unique(ImplEqual);
}
ImplList* ImplList::tryMinimize( void )
{
	Normalize();

	//Очищаем признаки склейки
	TFOREACH(it)
		(*it)->ClrFlg();

	ImplList *r = new ImplList(Nargs);

	TFOREACH(itA)
	{
		ImplList::iterator itB;
		itB = itA;
		itB++;
		for (; itB!=this->end(); itB++)
		{
			if ((*itA)->Ind == (*itB)->Ind) //Если одного порядка, то пока ждём
			{
				continue;
			}
			if ((*itA)->Ind + 1 < (*itB)->Ind)//Если разница порядков больше единицы - дальше не идём. Оно неубывает
				break;
			//А иначе пробуем склеить
			Impl *ni = (*itA)->tryGlue(**itB);
			if (ni)
				r->push_back(ni);
		}
	}
	if (!r->size())
	{
		delete r;
		return 0;
	}
	TFOREACH(it)
		if (!(*it)->Pw)
			r->push_back(new Impl(**it));
	r->Normalize();
	return r;
}

std::string ImplList::toString( void ) const
{
	std::ostringstream r;
	Separator sep(" + ");

	if (size()==0)
		return "0";
	TCFOREACH(it)
	{
		r << sep();
		r << (*it)->toString(this->Nargs);
	}
	return r.str();
}
