#ifndef PORYGONLANG_EVALVALUEPOINTER_HPP
#define PORYGONLANG_EVALVALUEPOINTER_HPP


#include "EvalValues/EvalValue.hpp"

namespace Porygon::Evaluation {
    class EvalValuePointer {
        const EvalValue *_ptr;
    public:
        EvalValuePointer(const EvalValue* p) :_ptr(p){};
        EvalValuePointer(const EvalValuePointer& b){
            if (b._ptr == nullptr){
                _ptr = nullptr;
            } else{
                _ptr = b._ptr->Clone();
            }
        };
        EvalValuePointer(){
            _ptr = nullptr;
        };

        ~EvalValuePointer(){
            delete _ptr;
        }

        [[nodiscard]]
        inline const EvalValue* Get() const{
            return _ptr;
        }

        [[nodiscard]]
        inline const EvalValue* Clone() const{
            if (_ptr == nullptr){
                return nullptr;
            }
            return _ptr->Clone();
        }

        inline const EvalValue* Take(){
            auto p = _ptr;
            _ptr = nullptr;
            return p;
        }

        inline void ClearAssign(const EvalValue* n){
            delete _ptr;
            _ptr = n;
        }

        inline const bool HasValue() const{
            return _ptr == nullptr;
        }

        inline const EvalValue* operator ->() const{
            return Get();
        }
        inline bool operator == (const EvalValuePointer& b) const{
            if (!_ptr){
                return !b._ptr;
            }
            if (!b._ptr) return false;
            return _ptr->operator==(b._ptr);
        }

        inline bool operator != (const EvalValuePointer& b) const{
            if (!_ptr){
                return b._ptr;
            }
            if (!b._ptr) return false;
            return _ptr->operator!=(b._ptr);
        }

        EvalValuePointer& operator =(const EvalValuePointer& a){
            if (a._ptr == nullptr){
                _ptr = nullptr;
            } else{
                _ptr = a._ptr->Clone();
            }
            return *this;
        };
    };
}

#endif //PORYGONLANG_EVALVALUEPOINTER_HPP
