/*
  Copyright 2025 Matthias-Sebastian Schröder <matthias.schroeder@dolanghub.de>

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#pragma once

#include "dobase/string.hpp"
#include <cstddef>

__NAMESPACE_DO_START

class Variant;
class Array;
class VmStack;
class Object;
struct object_ptr_shared_data_st;

struct object_ptr_st
{
  object_ptr_shared_data_st* data;
  Object* object;
};


template<typename __TObject>
class DOBASE_EXPORT object_ptr : public object_ptr_st
{
public:
  object_ptr() : object_ptr_st{} {}
  object_ptr(__TObject* object) : object_ptr_st{ object->share, object } {
    reinterpret_cast<object_ptr<Object>*>(this)->init_internal(
      reinterpret_cast<Object*>(object)
    );
  }
  object_ptr(const object_ptr& from) : object_ptr_st(from) {
    reinterpret_cast<object_ptr<Object>*>(this)->add_ref_internal();
  }
  ~object_ptr() {
    reinterpret_cast<object_ptr<Object>*>(this)->release_internal(nullptr);
  }
  __TObject* operator->() {
    return reinterpret_cast<__TObject*>(
      reinterpret_cast<object_ptr<Object>*>(this)->get_internal()
      );
  }
  operator __TObject* () {
    return reinterpret_cast<__TObject*>(
      reinterpret_cast<object_ptr<Object>*>(this)->get_internal()
      );
  }
  object_ptr& operator =(const object_ptr& a) {
    reinterpret_cast<object_ptr<Object>*>(this)->init_internal(
      *reinterpret_cast<const object_ptr<Object>*>(&a)
    );
    return *this;
  }
  void release(VmStack* stack) {
    reinterpret_cast<object_ptr<Object>*>(this)->release_internal(stack);
  }
  __TObject* get() {
    return reinterpret_cast<__TObject*>(
      reinterpret_cast<object_ptr<Object>*>(this)->get_internal()
      );
  }

  void init_internal(Object* object);
  void init_internal(const object_ptr<Object>& object);
  void release_internal(VmStack* stack);
  void add_ref_internal();
  Object* get_internal();
};

using ObjectPointer = object_ptr<Object>;

// Assing Variant to Variant
DOBASE_EXPORT void VarSetVariant(Variant* to, const Variant* var);
DOBASE_EXPORT void VarSetBool(Variant* to, bool boolval);
DOBASE_EXPORT void VarSetTrue(Variant* to);
DOBASE_EXPORT void VarSetFalse(Variant* to);
DOBASE_EXPORT void VarSetNull(Variant* to);
DOBASE_EXPORT void VarSetInt(Variant* to, int iVal);
DOBASE_EXPORT void VarSetDouble(Variant* to, double dbl);
DOBASE_EXPORT void VarSetString(Variant* to, const String& string);
DOBASE_EXPORT void VarSetUtf8(Variant* to, const char* u8string);
DOBASE_EXPORT void VarSetUtf8Len(Variant* to, const char* u8string, size_t size);

// Cast Variant to int with runtime type check
DOBASE_EXPORT int VarGetInt(const Variant* variant);
DOBASE_EXPORT int32_t VarGetInt32(const Variant* variant);
DOBASE_EXPORT int64_t VarGetInt64(const Variant* variant);
DOBASE_EXPORT String VarGetString(const Variant* variant);
DOBASE_EXPORT const Array* VarGetArray(const Variant* variant);
DOBASE_EXPORT Array* VarGetArray(Variant* variant);

// Get readonly pointer for DO Variant String. Asking for
// a readonly pointer does not cause heap memory operations.
DOBASE_EXPORT const char* VarReadString(const Variant* variant, size_t *out_size);
DOBASE_EXPORT char* VarWriteString(Variant* variant, size_t* out_size);

// Releases a memvar, can throw
DOBASE_EXPORT void ReleaseVar(VmStack* stack, Variant* variant);

DOBASE_EXPORT Variant* WriteArrayItem(VmStack* stack, Array* array, size_t item);
DOBASE_EXPORT const Variant* ReadArrayItem(VmStack* stack, const Array* array, size_t item);

DOBASE_EXPORT Variant* WriteArrayItem(VmStack* stack, Array* array, size_t row, size_t column);
DOBASE_EXPORT const Variant* ReadArrayItem(const Array* array, size_t row, size_t column);

DOBASE_EXPORT Array* VarDimArray(VmStack* stack, Variant* variant, size_t num_elements);
DOBASE_EXPORT Array* VarDimArray(VmStack* stack, Variant* variant, size_t num_rows, size_t num_columns);
DOBASE_EXPORT size_t ArrayNumElements(const Array* array);
DOBASE_EXPORT size_t ArrayNumRows(const Array* array);
DOBASE_EXPORT size_t ArrayNumColumns(const Array* array);

// Creates a instance of className
DOBASE_EXPORT ObjectPointer CreateObject(VmStack* stack,
  const String& class_name, const Variant* p, size_t c);

__NAMESPACE_END
