#ifndef REFERENCE_H
#define REFERENCE_H

#include "symbol.h"

namespace Frost {

class State;

class Reference : public Symbol
{
public :

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

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

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

    s_str r;
    static const s_str TYPE;

private :

    s_refptr<Symbol> Dereference_() const;

    mutable s_ptr<State> s;
};

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

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

template<>
s_refptr<Symbol> Dereference(s_refptr<Symbol> s);

}

#endif // REFERENCE_H
