/*
  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/namespace.hpp"
#include "dobase/runtime.hpp"

__NAMESPACE_DO_START

// Table handle
using table_handle = void*;

enum class FieldinfoType : uint8_t
{
  Blob = 1,
  Char = 2,
  Integer = 3,
  Currency = 4,
  Date = 5,
  Datetime = 6,
  Double = 7,
  General = 8,
  Logical = 9,
  Memo = 10,
  Numeric = 11,
  Float = 12,
  Varbinary = 13,
  Varchar = 14,
};

enum class FieldinfoNull : uint8_t
{
  Unspecified = 0,
  Null = 1,
  NotNull = 2
};

struct fielddef_st
{
  FieldinfoType type;
  char name[88];
  bool prec_null;
  size_t prec;
  bool scale_null;
  size_t scale;
  FieldinfoNull null;
  bool auto_increment;
  bool binary;
  // Autoinc step and next value
  size_t autoStep;
  bool autoStep_defined;
  size_t autoNext;
  bool autoNext_defined;
};

enum class IndexExprComplexity : uint8_t
{
  Field, Expression
};

struct indexdef_st
{
  const char* tag;
  const char* expr;
  IndexExprComplexity complexity;
  const char* filter;
  const char* collate;
  bool unique;
  bool candidate;
  bool binary;
};

struct createopts_st
{
  size_t codepage;
  size_t memoBlockSize;
  bool temp;
  // Automatically replace invalid characters in field names
  // Automatically truncate field names (Make also sure they are unique)
  bool fixfieldnames;
  // Automaticalle truncate field widths if defined widths are too long
  bool fixfieldwidths;
  // Automatically replace invalid characters in tag names
  // Automatically truncate tag names (Make also sure they are unique)
  bool fixtagnames;
};

enum class KeyOpt : size_t
{
  UNDEFINED = 0,
  EXACT = 1,
  PREFIX = 2
};

enum class SeekDir : size_t
{
  UNDEFINED = 0,
  ASCENDING = 1,
  DESCENDING = 2,
};

enum class SeekRng : size_t
{
  UNDEFINED = 0,
  SAME = 1,
  AFTER = 2,
};
__forceinline
SeekRng operator | (SeekRng a, SeekRng b)
{
  return static_cast<SeekRng>(static_cast<int>(a) | static_cast<int>(b));
}
__forceinline
SeekRng operator & (SeekRng a, SeekRng b)
{
  return static_cast<SeekRng>(static_cast<int>(a) & static_cast<int>(b));
}

enum class LockState : int
{
  // Locked record is consistent
  CLEAN = 0,
  // Locked record is out of scope, filter or deleted
  OUT_OF_RANGE = 1
};

// UTF-8 encoded filename
DOBASE_EXPORT table_handle OpenTable(VmStack* stack, const String &filename);

DOBASE_EXPORT table_handle CreateTable(VmStack* stack, const String& filename, const createopts_st *opts,
  fielddef_st* fields, size_t num_fields, indexdef_st* indizes, size_t num_indizes);

DOBASE_EXPORT void DropTable(VmStack* stack, const String& filename);

DOBASE_EXPORT void RenameTable(VmStack* stack, const String& filename, const String& new_filename);

DOBASE_EXPORT const Charset* GetTableCharset(table_handle handle);

DOBASE_EXPORT void CloseTable(VmStack* stack, table_handle th);

DOBASE_EXPORT size_t GetFieldCount(table_handle handle);

DOBASE_EXPORT void GetFieldInfo(table_handle handle, size_t idx, fielddef_st* out_info);

DOBASE_EXPORT size_t GetFieldNum(table_handle handle, const String& find);

DOBASE_EXPORT size_t RecordCount(table_handle handle);

DOBASE_EXPORT size_t RecordNumber(table_handle handle);

DOBASE_EXPORT void GotoTop(VmStack* stack, table_handle handle);

DOBASE_EXPORT void GotoBottom(VmStack* stack, table_handle handle);

DOBASE_EXPORT void GotoRecord(VmStack* stack, table_handle handle, size_t recno);

DOBASE_EXPORT void GotoEof(table_handle handle);

enum class SkipDir { Forward, Backward };

DOBASE_EXPORT void Skip(VmStack* stack, table_handle handle, SkipDir dir, size_t num_recs);

DOBASE_EXPORT bool Bof(table_handle handle);

DOBASE_EXPORT bool Eof(table_handle handle);

DOBASE_EXPORT void EvalIndexKey(VmStack *stack, table_handle handle, char *out_key, size_t *size);

DOBASE_EXPORT void GetIndexKey(table_handle handle, char* buf, size_t* buf_size);

DOBASE_EXPORT void SelectIndex(VmStack* stack, table_handle handle, size_t index);

DOBASE_EXPORT void SetScope(VmStack* stack, table_handle handle,
  const char *key, size_t size, SeekDir dir, SeekRng rng);

DOBASE_EXPORT void ClearScope(VmStack* stack, table_handle handle);

DOBASE_EXPORT void UnselectIndex(table_handle handle);

DOBASE_EXPORT bool SeekRawKey(VmStack *stack, table_handle handle, const char *key,
  size_t size, SeekRng rng, SeekDir dir, bool near_on);

DOBASE_EXPORT double GetIndexPos(table_handle handle);

DOBASE_EXPORT bool IsFieldNull(table_handle handle, size_t idx);

DOBASE_EXPORT void GetFieldVariant(table_handle handle, size_t idx, Variant* to);

DOBASE_EXPORT void SetFieldNull(table_handle handle, size_t idx);

DOBASE_EXPORT void GetFieldBinary(table_handle handle, size_t idx, char* buf, size_t* size);

DOBASE_EXPORT void SetFieldBinary(table_handle handle, size_t idx, const char* buf,
  size_t size);

DOBASE_EXPORT void GetFieldText(table_handle handle, size_t idx, 
  char* buf, size_t *size, const Charset **out_cs);

DOBASE_EXPORT void SetFieldText(table_handle handle, size_t idx,
  const char* buf, size_t size, const Charset* cs);

DOBASE_EXPORT void GetFieldMoneyString(table_handle handle, size_t idx,
  char* buf, size_t* size);

DOBASE_EXPORT void SetFieldMoneyString(table_handle handle, size_t idx,
  char* buf, size_t size);

DOBASE_EXPORT int32_t GetFieldInt32(table_handle handle, size_t idx);

DOBASE_EXPORT void SetFieldInt32(table_handle handle, size_t idx, int32_t i32);

DOBASE_EXPORT size_t GetNextAutoInc(table_handle handle, size_t idx);

DOBASE_EXPORT size_t GetAutoIncStep(table_handle handle, size_t idx);

DOBASE_EXPORT void SetFieldReadonly(table_handle handle, size_t idx, bool yes);

DOBASE_EXPORT bool GetFieldLogical(table_handle handle, size_t idx);

DOBASE_EXPORT void SetFieldLogical(table_handle handle, size_t idx, bool val);

DOBASE_EXPORT double GetFieldDouble(table_handle handle, size_t idx);

DOBASE_EXPORT void SetFieldDouble(table_handle handle, size_t idx, double val);

DOBASE_EXPORT void GetFieldDateYMD(table_handle handle, size_t idx, size_t* y, size_t* m, size_t* d,
  bool* negative);

DOBASE_EXPORT void SetFieldDateYMD(table_handle handle, size_t idx, intptr_t y, size_t m, size_t d,
  bool negative);

DOBASE_EXPORT void GetFieldDateTimeYMDHIS(table_handle handle, size_t idx, size_t* y, size_t* m, size_t* d,
  size_t* h, size_t* i, size_t* s, bool* negative);

DOBASE_EXPORT void SetFieldDateTimeYMDHIS(table_handle handle, size_t idx, intptr_t y, size_t m, size_t d,
  size_t h, size_t i, size_t s);

DOBASE_EXPORT size_t GetMemoSize(table_handle handle, size_t idx);

DOBASE_EXPORT size_t GetIndexCount(table_handle handle);

DOBASE_EXPORT void BeginAppendRecord(table_handle handle, int options);

DOBASE_EXPORT void DeleteRecord(table_handle handle);

// Returns information about an index, must be freed
// with FreeIndexInfo
DOBASE_EXPORT indexdef_st* GetIndexInfo(table_handle handle, size_t idx);

DOBASE_EXPORT void FreeIndexInfo(indexdef_st* info);

DOBASE_EXPORT void SetDeleted(VmStack *stack, bool on);

DOBASE_EXPORT time_t TableLastModified(table_handle handle);

DOBASE_EXPORT time_t TableCreateTime(table_handle handle);

DOBASE_EXPORT size_t GetTableFileSize(table_handle handle);

DOBASE_EXPORT bool LockCurrentRecord(VmStack *stack, table_handle handle, LockState &ls);

DOBASE_EXPORT void UnlockCurrentRecord(table_handle handle);

DOBASE_EXPORT void UnlockAll(table_handle handle);

DOBASE_EXPORT bool IsCurrentRecordLocked(table_handle handle);

DOBASE_EXPORT void TableUpdate(VmStack* stack, table_handle handle, int options);

DOBASE_EXPORT void TableRevert(table_handle handle, int options);

DOBASE_EXPORT bool IsRecordDeleted(table_handle handle);

DOBASE_EXPORT bool IncreaseRawKey(char* key, size_t size);

DOBASE_EXPORT bool ShrinkRawKey(char* key, size_t size);

__NAMESPACE_END
