/*
  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/compiler.hpp"
#include <cstdint>
#include <cstddef>

__NAMESPACE_DO_START

class VmStack;
class Variant;
class Runtime;
class Class;
class Object;

typedef void(*declspec_do_func)(VmStack* stack, size_t pcount, Variant* ret);
typedef void(*declspec_dovoid_func)(VmStack* stack, size_t pcount);
typedef Object*(*object_factory)(VmStack* stack, Class* from);
typedef void(*object_destructor)(VmStack* stack, Object *what);
typedef void(*load_module_func)(Runtime *runtime);
typedef void(*unload_module_func)(Runtime *runtime);

// Type analysis functions are required for do runtime
// for estimating the size of index keys from index
// key expressions.
typedef void(*type_analysis_func)(size_t c, compiler_type_info_st* ti,
  Variant* cv, compiler_type_info_st* out);

struct declspec_do_func_def_st
{
  const char* name;
  const char* signature;
  declspec_do_func fnptr;
  const char* type;
  int shortcut;
};

struct type_analysis_func_def_st
{
  const char* name;
  type_analysis_func fnptr;
};

struct declspec_void_func_def_st
{
  const char* name;
  const char* signature;
  declspec_dovoid_func fnptr;
};

struct sysvar_definition_st
{
  const char* name;
  const char* access;
  declspec_do_func access_func;
  const char* retval;
  const char* assign;
  declspec_dovoid_func assign_func;
};

enum class MemberAccess : int
{
  PUBLIC = 1,
  PROTECTED = 2,
  PRIVATE = 4
};

__forceinline
MemberAccess operator | (MemberAccess a, MemberAccess b)
{
  return static_cast<MemberAccess>(static_cast<int>(a) | static_cast<int>(b));
}

__forceinline
MemberAccess operator & (MemberAccess a, MemberAccess b)
{
  return static_cast<MemberAccess>(static_cast<int>(a) & static_cast<int>(b));
}

struct class_member_st
{
  const char* name;
  MemberAccess access = MemberAccess::PUBLIC;
  declspec_do_func access_method;
  declspec_dovoid_func assign_method;
  declspec_do_func call_method;
};

class ClassPropertyDef : public class_member_st
{
public:
  ClassPropertyDef(const char* name, declspec_do_func access_method, declspec_dovoid_func assign_method = nullptr,
    MemberAccess access = MemberAccess::PUBLIC) : class_member_st{ name, access, access_method, assign_method }
  {
  }
};

class ClassFunctionDef : public class_member_st
{
public:
  ClassFunctionDef(const char* name, declspec_do_func call_method,
    MemberAccess access = MemberAccess::PUBLIC) : class_member_st{ name, access, nullptr, nullptr, call_method }
  {
  }
};

struct class_def_st
{
  const char* name;
  object_factory create;
  const class_member_st* members;
};

struct do1_module_descriptor_st
{
  // Function call after loading the module into memory
  load_module_func load_module;  
  // Function called before removing module from memory
  unload_module_func unload_module;
  const declspec_do_func_def_st* functions;
  const declspec_void_func_def_st* void_functions;
  const class_def_st* classes;
  const type_analysis_func_def_st* analysis_functions;  
  const sysvar_definition_st* sysvars;
};

typedef void(*do1_describe_module_func)(
  do1_module_descriptor_st* descriptor);

__NAMESPACE_END
