/*
 * ExpressionSerializer2.cpp
 *
 *  Created on: 9 февр. 2016
 *      Author: pgess
 */

#include "expressionserializer2.h"

using namespace std;

namespace xreate {

typedef size_t ElementId;
struct Element{
	string name;
	unsigned char degree;
	ElementId terminal = 0;
	std::list<ElementId> childs;

	bool operator< (const Element& other) {
		int cmp = name.compare(other.name);
		if (cmp !=0) return (cmp < 0);
		return (degree < other.degree);
	}

	bool operator== (const Element& other) {
		int cmp = name.compare(other.name);
		if (cmp != 0) return false;
		return degree == other.degree;
	}

	Element(string nameElement, unsigned int degreeElement)
		: name(nameElement), degree(degreeElement) {}
};

const Element End{"", 0};

class ExpressionSerializerStrategyB {
	vector<Element> __registry;

	ElementId push(const Element& e, ElementId rootId){
		typedef list<ElementId>::iterator ElementIt;

		list<ElementId>& elements =  __registry[rootId].childs;
		list<ElementId>::iterator pos = std::__lower_bound(elements.begin(), elements.end(), e,
				[this](const ElementIt& testIt, const Element& value){return __registry[*testIt] < value;});

		if (!(__registry[*pos] == e)) {
			__registry.push_back(e);
			ElementId result = __registry.size()-1;
			elements.insert(pos, result);
			return result;
		}

		return *pos;
	}

	ElementId registerExpression(const Expression& e, ElementId rootId) {
		switch(e.op){
			case Operator::NONE: {
				switch (e.__state) {
					case Expression::STRING:
					case Expression::IDENT: {
						const string& name = e.getValueString();
						Element element(name, 0);
						ElementId rootId = push(element, rootId);
						return rootId;
					}

					default: {
						break;
					}
				}
			break;
			}

			case Operator::CALL: {
				const string& name = e.getValueString();
				Element element(name, e.operands.size());
				ElementId rootId = push(element, rootId);

				for (const Expression& op: e.operands){
					Element element(op.getValueString(), op.operands.size());
					rootId = push(element, rootId);
				}

				return rootId;
			}

			default: break;
		}

		assert(false && "Expression too complicate for serialization");
	}
};

} /* namespace xreate */
