#ifndef STATE_H
#define STATE_H

#include "symbol.h"
#include <functional>

class State
{
public :

    State();

    void ShowHelp() const;

    void                    ParseLine(const Frost::s_str& sLine);
    Frost::s_refptr<Symbol> ParseSymbol(const Frost::s_str& n, Frost::s_str sv, Frost::s_str& sError, Frost::s_bool bAllowUndefined = false);

    Frost::s_refptr<Symbol> CreateEmptySymbol(const Frost::s_str& sType, const Frost::s_str& sName) const;
    Frost::s_bool           TypeExists(const Frost::s_str& t) const;
    Frost::s_bool           CheckName(const Frost::s_str& n, Frost::s_str& e) const;
    Frost::s_bool           IsExpression(const Frost::s_str& s) const;
    Frost::s_bool           IsOperator(Frost::s_str::const_iterator iter, const Frost::s_str& s, Frost::s_str& o) const;
    Frost::s_bool           IsOperator(const Frost::s_str& s) const;
    Frost::s_uint           GetOperatorWeight(const Frost::s_str& s) const;
    Frost::s_refptr<Symbol> BinaryOperator(const Frost::s_str& o, Frost::s_refptr<Symbol> a, Frost::s_refptr<Symbol> b, Frost::s_str& e) const;
    Frost::s_refptr<Symbol> LeftUnaryOperator(const Frost::s_str& o, Frost::s_refptr<Symbol> a, Frost::s_str& e) const;
    Frost::s_refptr<Symbol> RightUnaryOperator(const Frost::s_str& o, Frost::s_refptr<Symbol> a, Frost::s_str& e) const;

    typedef std::function<Frost::s_bool(Frost::s_str::const_iterator, const Frost::s_str&, Frost::s_str&)> CutFunction_t;
    Frost::s_bool           CutExpression(Frost::s_ctnr<Frost::s_str>& exp, const Frost::s_str& sv, CutFunction_t mCutIf, Frost::s_str& sError, Frost::s_bool bKeepCut = true) const;

    template<class T>
    static Frost::s_refptr<Symbol> CreateEmptySymbol(const Frost::s_str& sName)
    {
        return Frost::s_refptr<Symbol>(new T(sName));
    }

    template<class T>
    void RegisterSymbolType()
    {
        lTypeArray[T::TYPE] = &(State::CreateEmptySymbol<T>);
    }

    typedef std::function<Frost::s_refptr<Symbol>(Frost::s_refptr<Symbol>,Frost::s_refptr<Symbol>,Frost::s_str&)> BinaryOperator_t;
    template<class T1, class T2>
    void RegisterBinaryOperator(const Frost::s_str& o, BinaryOperator_t f)
    {
        lBinaryOperatorArray[o][T1::TYPE][T2::TYPE] = f;
    }

    typedef std::function<Frost::s_refptr<Symbol>(Frost::s_refptr<Symbol>,Frost::s_str&)> UnaryOperator_t;
    template<class T>
    void RegisterLeftUnaryOperator(const Frost::s_str& o, UnaryOperator_t f)
    {
        lRightUnaryOperatorArray[o][T::TYPE] = f;
    }

    template<class T>
    void RegisterRightUnaryOperator(const Frost::s_str& o, UnaryOperator_t f)
    {
        lRightUnaryOperatorArray[o][T::TYPE] = f;
    }

    typedef std::function<Frost::s_bool(const Frost::s_str&)> ConstructorMatch_t;
    typedef std::function<Frost::s_refptr<Symbol>(State&,const Frost::s_str&,const Frost::s_str&,Frost::s_str&)> Constructor_t;
    template<class T>
    void RegisterConstructor(ConstructorMatch_t f1, Constructor_t f2)
    {
        lConstructorMatchArray[T::TYPE] = f1;
        lConstructorArray[T::TYPE] = f2;
    }

    void RegisterOperatorList(const Frost::s_map<Frost::s_str, Frost::s_uint>& lList);

private :

    void SetLastResult(Frost::s_refptr<Symbol> s);

    Frost::s_map<Frost::s_str, Frost::s_refptr<Symbol>> g;
    Frost::s_map<Frost::s_str, std::function<Frost::s_refptr<Symbol>(const Frost::s_str&)>> lTypeArray;
    Frost::s_map<Frost::s_str, Frost::s_map<Frost::s_str, Frost::s_map<Frost::s_str, BinaryOperator_t>>> lBinaryOperatorArray;
    Frost::s_map<Frost::s_str, Frost::s_map<Frost::s_str, UnaryOperator_t>> lLeftUnaryOperatorArray;
    Frost::s_map<Frost::s_str, Frost::s_map<Frost::s_str, UnaryOperator_t>> lRightUnaryOperatorArray;
    Frost::s_map<Frost::s_str, Frost::s_uint> lOperatorList;

    Frost::s_map<Frost::s_str, ConstructorMatch_t> lConstructorMatchArray;
    Frost::s_map<Frost::s_str, Constructor_t> lConstructorArray;
};

#endif
