
#ifndef PORYGONLANG_USERDATAVALUE_HPP
#define PORYGONLANG_USERDATAVALUE_HPP

#include <utility>
#include "../Evaluator/EvalValues/EvalValue.hpp"
#include "UserData.hpp"
#include "UserDataStorage.hpp"

namespace Porygon::UserData {
    class UserDataValue : public Evaluation::EvalValue {
        const UserData* _userData;
        void *_obj;
    public:
        UserDataValue(const UserData* userData, void *obj)
                : _userData(userData) {
            _obj = obj;
        }

        UserDataValue(uint32_t userDataId, void *obj)
                : _userData(UserDataStorage::GetUserDataType(userDataId)) {
            _obj = obj;
        }

        [[nodiscard]]
        inline TypeClass GetTypeClass() const final {
            return TypeClass::UserData;
        }

        bool operator==(const EvalValue *b) const final {
            if (b->GetTypeClass() != TypeClass::UserData)
                return false;
            return _obj == ((UserDataValue *) b)->_obj;
        }

        [[nodiscard]]
        inline Evaluation::EvalValue* Clone() const final {
            return new UserDataValue(_userData, _obj);
        }

        [[nodiscard]]
        inline std::size_t GetHashCode() const final {
            return reinterpret_cast<intptr_t>(_obj);
        }

        const Evaluation::EvalValue* IndexValue(const EvalValue *val) const final {
            auto fieldId = val->GetHashCode();
            auto field = _userData->GetField(fieldId);
            return field->Get(_obj);
        }

        [[nodiscard]]
        inline const EvalValue* IndexValue(uint32_t hash) const final {
            auto field = _userData->GetField(hash);
            return field->Get(_obj);
        }

        void SetIndexValue(const EvalValue *key, const EvalValue* value) const final {
            auto fieldId = key->GetHashCode();
            auto field = _userData->GetField(fieldId);
            field->Set(_obj, value);
            delete value;
        }

        inline void* GetObjectPointer(){
            return _obj;
        }
    };
}

#endif //PORYGONLANG_USERDATAVALUE_HPP
