#ifndef REFERENCE_H
#define REFERENCE_H

#include "symbol.h"

class State;

class Reference : public Symbol
{
public :

    Reference(const Frost::s_str& sName) : Symbol(sName) {}
    Reference(const Frost::s_str& sName, Frost::s_ptr<State> pState, const Frost::s_refptr<Symbol>& pSymbol) : Symbol(sName), r(pSymbol->name), s(pState) {}
    Reference(const Frost::s_str& sName, Frost::s_ptr<State> pState, const Frost::s_str& sRefName) : Symbol(sName), r(sRefName), s(pState) {}

    Frost::s_refptr<Symbol> Dereference() const;
    virtual Frost::s_str PrintContent() const;
    virtual Frost::s_str GetType() const;
    virtual Frost::s_str GetTrueType() const;
    virtual Frost::s_refptr<Symbol> Clone() const;

    static Frost::s_bool           MatchesConstructor(const Frost::s_str& s);
    static Frost::s_refptr<Symbol> CreateFrom(State& mState, const Frost::s_str& n, const Frost::s_str& s, Frost::s_str& e);
    static void                    Register(State& mState);

    Frost::s_str r;
    static const Frost::s_str TYPE;

private :

    Frost::s_refptr<Symbol> Dereference_() const;

    mutable Frost::s_ptr<State> s;
};

template<class T>
Frost::s_refptr<T> Dereference(Frost::s_refptr<Symbol> s)
{
    Frost::s_refptr<Reference> rs = Frost::s_refptr<Reference>::DynamicCast(s);
    if (rs)
    {
        if (rs->r.IsEmpty())
            return Frost::nullptr;

        Frost::s_refptr<Symbol> r = rs->Dereference();
        if (r)
            return Frost::s_refptr<T>::DynamicCast(r);
        else
            return Frost::nullptr;
    }
    else
        return Frost::s_refptr<T>::DynamicCast(s);
}

#endif // REFERENCE_H
