/*
   Copyright (c) 2019 by The ThreadDB Project
   All Rights Reserved.

   ThreadDB undergoes the BSD License 2.0. You should have received a copy along with this program; if not, write to the ThreadDB Project.
   To obtain a full unlimited version contact thethreaddbproject(at)gmail.com.

   threaddbC.h - C Interface to the ThreadDB memory container database
*/

#pragma once

/**
   \file
   \brief         List of interface methods to the database.
   \details       This module contains the list of available methods provided. The interface is provided as a C header which allows
                  to integrate the threadDB implementation as dynamic library (dll).
*/

#include "threaddbTypes.h"

#if defined(__cplusplus) || defined(__MINGW32__) || defined(__MINGW64__)
extern "C"
{
#endif

    /**
    *  @brief Interface for creating a new database object.
    *
    *  @details
    *   Creates a new database object and returns the related handle.
    *   The operation initializes the internal data structures and starts the thread for package buffer flushing.
    *   The @p PackageSize_p is the size of the memory block allocated for interim
    *   buffering of the stored data items. The @p PackageCacheLimit_p defines an upper
    *   limit of parallel held item buffers of size @p PackageSize_p. If the number of packages exceeds this limit
    *   the flush threads starts to withdraw package buffers from memory. This treatment requires additional
    *   thread synchronization taking place and could reduce the throughput significantly.
    *   The major part of consumed memory at a time is given by the number of packages times the package buffer size.
    *   Prior storing items in the database, it is important to create at least one worker thread using @ref ThreadDB_NewThread.
    *
    *  @param pThreadDB_p Handle to the created database object.
    *  @param PackageSize_p Record size for buffering the data items.
    *  @param PackageCacheLimit_p Maximum number of package buffers held in memory at one point of time.
	*  @param pPackagesFolder_p Directory path to store the package header information
	*  @return Error code.
    */

    DLLEXPORT_ threadDB_ReturnCode ThreadDB_Create(void** pThreadDB_p, size_t PackageSize_p, size_t PackageCacheLimit_p, const char* pPackagesFolder_p);

    /**
    *  @brief Interface for creating a new database object based on a database index file.
    *
    *  @details
    *   Creates a new database object based on a previously saved database. The operation initializes the internal data structures, starts the thread for
    *   package buffer flushing and builds up the internal package table. The @p PackageSize_p is the size of the memory block allocated for interim
    *   buffering of the stored package items. The @p pIndexFileUTF8_p needs to specify the full path to the location of the database index file.
    *   The @p pIndexFileUTF8_p path characters have to be provided in UTF8 representation. Threads registered on an imported database will create new
    *   temporary database files and the imported database files are kept mainly untouched.
    *
    *  @param pThreadDB_p Handle to the created database object.
    *  @param pIndexFileUTF8_p Record size for buffering the data items.
    *  @param PackageCacheLimit_p Maximum number of package buffers held in memory at one point of time.
    *  @return Error code.
    */

    DLLEXPORT_ threadDB_ReturnCode ThreadDB_Import(void** pThreadDB_p, const char* pIndexFileUTF8_p, size_t PackageCacheLimit_p);

    /**
    *  @brief Interface to destroy an existing database object.
    *
    *  @details
    *   Destroys an existing database object, removes the related temporary database files and stops all
    *   running threads.
    *
    *  @param pThreadDB_p Handle to the database object.
    */

    DLLEXPORT_ void ThreadDB_Destroy(void* pThreadDB_p);

    /**
    *  @brief Interface for retrieving the package version info.
    *
    *  @details
    *   Provides the current version of the ThreadDB project.
    *
    *  @param pThreadDB_p Handle to the database object.
    *  @return Version information string.
    */

    DLLEXPORT_ const char* ThreadDB_GetVersionInfo(void* pThreadDB_p);

    /**
    *  @brief Interface to save the stored data.
    *
    *  @details
    *   Saves the database control structures to the given database index file. The related temporary
    *   database files are removed from the purging process executed during the database destruction phase.
    *
    *  @param pIndexFileUTF8_p Full path to the database index file location in UTF8 representation.
    *  @param pThreadDB_p Handle to the database object.
    *  @return Error code.
    */

    DLLEXPORT_ threadDB_ReturnCode ThreadDB_Save(const char* pIndexFileUTF8_p, void* pThreadDB_p);

    /**
    *  @brief Interface to create and register a new worker thread.
    *
    *  @details
    *   Creates a new worker thread receiving and managing the stored item data. Each worker thread
    *   gets a temporary database file assigned to. It is possible to define multiple worker threads and
    *   define temporary folders on different discs. The created files have the format threaddb.XXXXXX
    *   with XXXXX reflecting an unique identifying number.
    *   A basic prinicple of storing data itmes is, that the data is directed to the first available
    *   thread registered. This leads to a priority to which thread/temporary file the data is written.
    *   It is therefore sensible to specify folders on discs with faster write speed (e.g. SSD discs) first.
    *
    *  @param pFileName_p Full path to the created temporary database file in ASCII character representation.
    *  @param pFolder_p Path to the temporary database file folder in ASCII character representation.
    *  @param MaxFileSize_p Maximum size in bytes a database file is allowed to grow. Exceeding this limit
              a new temporary file will be created.
    *  @param pThreadDB_p Handle to the database object.
    *  @return Error code.
    */

    DLLEXPORT_ threadDB_ReturnCode ThreadDB_NewThread(const char** pFileName_p, const char* pFolder_p, size_t MaxFileSize_p, void* pThreadDB_p);

    /**
    *  @brief Registers a new data item package.
    *
    *  @details
    *   Creates a new package to receive the stored data items. Each package definition is held in memory and consumes
    *   an amount of about 180 Bytes. Storing data items within a package synchronization of threads takes place.
    *
    *  @param pPackageID_p Generated package ID.
    *  @param pThreadDB_p Handle to the database object.
    *  @return Unique package id used for the store operation.
    */

    DLLEXPORT_ threadDB_ReturnCode ThreadDB_NewPackage(uint64_t* pPackageID_p, void* pThreadDB_p);

    /**
    *  @brief Returns the number of currently running threads.
    *
    *  @details
    *   Returns the number of currently running threads.
    *
    *  @param pThreadDB_p Handle to the database object.
    *  @return Number of executing threads.
    */

    DLLEXPORT_ size_t ThreadDB_GetThreadCount(void* pThreadDB_p);

    /**
    *  @brief Returns the number of currently registered packages.
    *
    *  @details
    *   Returns the number of currently registered packages.
    *
    *  @param pThreadDB_p Handle to the database object.
    *  @return Number of registered packages.
    */

    DLLEXPORT_ size_t ThreadDB_GetPackageCount(void* pThreadDB_p);

    /**
    *  @brief Returns the number of currently registered temporary database files.
    *
    *  @details
    *   Returns the number of currently registered temporary database files.
    *
    *  @param pThreadDB_p Handle to the database object.
    *  @return Number of registered database files.
    */

    DLLEXPORT_ size_t ThreadDB_GetFileCount(void* pThreadDB_p);

    /**
    *  @brief Returns the package buffer size.
    *
    *  @details
    *   Returns the size used to allocate internal package buffer blocks.
    *
    *  @param pThreadDB_p Handle to the database object.
    *  @return Size of the internal package buffers.
    */

    DLLEXPORT_ size_t ThreadDB_GetPackageSize(void* pThreadDB_p);

    /**
    *  @brief Returns the filename of a currently registered temporary database files.
    *
    *  @details
    *   Returns the filename of the registered temporary database files with index @p FileIndex_p. During execution of this command registering of
    *   new packages using @ref ThreadDB_GetDatabaseFileName is synchronized.
    *
    *  @param FileIndex_p Index of the temporary database file.
    *  @param pThreadDB_p Handle to the database object.
    *  @return Filename of the temporary database file.
    */

    DLLEXPORT_ const char* ThreadDB_GetDatabaseFileName(size_t FileIndex_p, void* pThreadDB_p);

    /**
    *  @brief Renames and copies/moves a temporary database file to a different location or disk.
    *
    *  @details
    *   The function allows to rename or copy/move a database file to a different location or disk. The command is synchronized and available
    *   also while store or read operations are in progress.
    *
    *  @param FileID_p the file index of the temporary database file to be renamed/moved.
    *  @param pFilePathUTF8_p full path to the destination to which the database file should be moved.
    *  @param RelocationType_p type of action copy/move to take place.
    *  @param pThreadDB_p Handle to the database object.
    *  @return Error code.
    */

    DLLEXPORT_ threadDB_ReturnCode ThreadDB_RelocateFileTo(size_t FileID_p, const char* pFilePathUTF8_p, threadDB_RelocationType RelocationType_p, void* pThreadDB_p);

    /**
    *  @brief Stores database package items in the specified package.
    *
    *  @details
    *   The function allows to append a new data item to the package @ Package_p. The item is asynchronously copied and appended to the given package.
    *   The parameter @p pItemHandle_p handle can be omitted by specifying a NULL pointer. If available, the stored index entry of the item
    *   is provided. A @p pItemHandle_p allows random access of individual package items. The @p pItemHandle_p has to be allocated and managed separately
    *   and provided by the caller. The item handles are registered in the database and updated during the @ref ThreadDB_Synchronize operation.
    *   Please note, that the item handle is usually invalid until the @ref ThreadDB_Synchronize operation is executed.
    *   The @p Size_p parameter specifies the size of data to be transferred. The size of the data item is NOT stored in the database and has to be
    *   managed separately. It needs to be provided during the @ref ThreadDB_RecoverContinous and @ref ThreadDB_RecoverRandom operations. The maximum size specified
    *   by the @p Size_p parameter. Data items exceeding the specified @p PackageSize_p need are split into multiple records and stored performing several
    *   @ ref ThreadDB_Store calls. Please note that each data item requires to be temporary duplicated to allow asynchronous storage.
    *   A special form of the ThreadDB_Store call is to flush specific packages to disk. This can be achieved by calling the function with a @p Size_p of zero.
    *   In this case only the buffer of the selected @p Package_p is synchronized while other packages stay open for writing and are not prematurely flushed.
    *   This allows to start reading of package information while writing to other packages is still in progress.
    *
    *  @param Package_p package index to which the data item should be appended.
    *  @param Size_p size of the package item to be stored.
    *  @param pData_p pointer to the data for being stored.
    *  @param pItemHandle_p optional parameter for random data item access.
    *  @param pThreadDB_p Handle to the database object.
    *  @return Error code.
    */

    DLLEXPORT_ threadDB_ReturnCode ThreadDB_Store(uint64_t Package_p, size_t Size_p, const char pData_p[], threadDB_ItemInfo* pItemHandle_p, void* pThreadDB_p);

    /**
    *  @brief Synchronizes the internal package buffers with the temporary database files.
    *
    *  @details
    *   Synchronizes the selected package by writing its contents to the database files. This operation also updates and validates the registered
    *   item handle specified during the @ref ThreadDB_Store operation. Synchronization is required prior calling @ref ThreadDB_RecoverContinous or
    *   operation. This operation also releases the internal package buffer.
    *
    *  @param Package_p package index to which should be synchronized.
    *  @param pThreadDB_p Handle to the database object.
    *  @return Error code.
    */
    DLLEXPORT_ threadDB_ReturnCode ThreadDB_SynchronizePackage(uint64_t Package_p, void* pThreadDB_p);

    /**
    *  @brief Synchronizes the internal package buffers with the temporary database files.
    *
    *  @details
    *   Synchronizes the package buffers by writing their contents to the database files. This operation also updates and validates the registered
    *   item handles specified during the @ref ThreadDB_Store operation. Synchronization is required prior calling @ref ThreadDB_RecoverContinous
    *   operation. This operation also releases the internal package buffers.
    *
    *  @param pThreadDB_p Handle to the database object.
    *  @return Error code.
    */

    DLLEXPORT_ threadDB_ReturnCode ThreadDB_Synchronize(void* pThreadDB_p);

    /**
    *  @brief This operation opens a package for stream reading.
    *
    *  @details
    *   This operation opens a package for stream reading the package contents. Stream reading is sensible for continious
    *   reading through the stored data items of the given package.
    *
    *  @param pReadInfo_p Generated ReadInfo handle.
    *  @param Package_p index of the package whose contents should be recovered.
    *  @param pThreadDB_p Handle to the database object.
    *  @return Error code.
    */

    DLLEXPORT_ threadDB_ReturnCode ThreadDB_Open(threadDB_ReadInfo** pReadInfo_p, uint64_t Package_p, void* pThreadDB_p);

    /**
    *  @brief This operation opens a package for stream reading at the given item cursor.
    *
    *  @details
    *   This operation opens a package for stream reading at the given stored item position.
    *
    *  @param pReadInfo_p Generated ReadInfo handle.
    *  @param pItemHandle_p handle to the stored item.
    *  @param pThreadDB_p Handle to the database object.
    *  @return Error code.
    */

    DLLEXPORT_ threadDB_ReturnCode ThreadDB_OpenItem(threadDB_ReadInfo** pReadInfo_p, const threadDB_ItemInfo* pItemHandle_p, void* pThreadDB_p);

    /**
    *  @brief This operation closes a package after stream reading has finished.
    *
    *  @details
    *   This operation is required to close a package and remove the @p pReadInfo_p after stream reading has finished.
    *
    *  @param pReadInfo_p Read handle created during the @ref ThreadDB_Open operation.
    *  @param pThreadDB_p Handle to the database object.
    *  @return Error code.
    */

    DLLEXPORT_ threadDB_ReturnCode ThreadDB_Close(threadDB_ReadInfo** pReadInfo_p, void* pThreadDB_p);

    /**
    *  @brief Stream reading operation through the data items stored in a package.
    *
    *  @details
    *   This function allows to continiously read through the stored data items. The calling process has to preallocate
    *   the @p pData_p transfer buffer and provide the size of data to be read through the @p Size_p parameter. It is possible
    *   to read amongst several data items at once.
    *
    *  @param pReadBytes_p Number of read data bytes.
    *  @param Size_p number of bytes to be read from the selected package.
    *  @param pData_p preallocated transfer buffer, requires to be preallocated and embrace at least Size_p bytes.
    *  @param pReadInfo_p read handle created during the @ref ThreadDB_Open operation.
    *  @param pThreadDB_p Handle to the database object.
    *  @return Error code.
    */

    DLLEXPORT_ threadDB_ReturnCode ThreadDB_RecoverContinous(size_t* pReadBytes_p, size_t Size_p, char pData_p[], threadDB_ReadInfo* pReadInfo_p, void* pThreadDB_p);

    /**
    *  @brief Random access operation to the data items stored in a package.
    *
    *  @details
    *   This function allows to read stored data items individually. The calling process has to preallocate
    *   the @p pData_p transfer buffer and provide the size of data to be read through the @p Size_p parameter. This function reads
    *   only the selected item. Since this method reads also from internal buffers, synchronization is not required.
    *   Since this operation requires to individually seek for the entry on disk, streaming throughput es in general less in comparison to
    *   continous reading.
    *
    *  @param Size_p number of bytes to be read from the selected package.
    *  @param pData_p preallocated transfer buffer, requires to embrace at least Size_p bytes.
    *  @param pItemHandle_p handle to the stored item.
    *  @param Package_p package identifier the selected item belongs to.
    *  @param pThreadDB_p Handle to the database object.
    *  @return Error code.
    */

    DLLEXPORT_ threadDB_ReturnCode ThreadDB_RecoverRandom(uint32_t Size_p, char pData_p[], const threadDB_ItemInfo* pItemHandle_p, uint64_t Package_p, void* pThreadDB_p);

    /**
    *  @brief Random access operation to the data items stored in a package.
    *
    *  @details
    *   This function allows to read stored data items individually. The calling process has to preallocate
    *   the @p pData_p transfer buffer and provide the size of data to be read through the @p Size_p parameter. It is possible
    *   to read amongst several data items at once. The parameter @p pItemHandle_p points to the selected data item. During
    *   read the handle is moved on to the following item entry. This allows to read through a series of elements continously.
    *   Since this operation requires to individually seek for the specific entry on disk, streaming throughput is in general less
    *   in comparison to continous reading.
    *
    *  @param Size_p number of bytes to be read from the selected package.
    *  @param pData_p preallocated transfer buffer, requires to embrace at least Size_p bytes.
    *  @param pItemHandle_p handle to the stored item.
    *  @param pThreadDB_p Handle to the database object.
    *  @return Error code.
    */

    DLLEXPORT_ threadDB_ReturnCode ThreadDB_RecoverRandomContinous(size_t Size_p, char pData_p[], threadDB_ItemInfo* pItemHandle_p, void* pThreadDB_p);

    /**
    *  @brief Stream reading operation through the data items stored in a package.
    *
    *  @details
    *   This function provides information if the package end has been reached.
    *
    *  @param pReadInfo_p read handle created during the @ref ThreadDB_Open operation.
    *  @param pThreadDB_p Handle to the database object.
    *  @return End of package flag.
    */

    DLLEXPORT_ bool ThreadDB_PackageEnd(threadDB_ReadInfo* pReadInfo_p, void* pThreadDB_p);

    /**
    *  @brief Replace operation to modify the contents of a stored data item.
    *
    *  @details
    *   This function allows to modify existing data item entries in the database. It replaces the given @p Size_p of bytes by the
    *   data provided in the @p pData_p transfer buffer. The Size_p parameter has to match the size of the previously stored data item.
    *
    *  @param Size_p number of bytes to be replaced.
    *  @param pData_p preallocated transfer buffer, requires to be embrace at least Size_p bytes.
    *  @param pItemHandle_p handle to the stored item to be replaced.
    *  @param pThreadDB_p Handle to the database object.
    *  @return Error code.
    */

    DLLEXPORT_ threadDB_ReturnCode ThreadDB_Replace(size_t Size_p, const char pData_p[], const threadDB_ItemInfo* pItemHandle_p, void* pThreadDB_p);

    /**
    *  @brief Information on error state.
    *
    *  @details
    *   This function returns information on current error state of the database.
    *
    *  @param pThreadDB_p Handle to the database object.
    *  return Information on the occured error.
    */

    DLLEXPORT_ const char* ThreadDB_GetErrorMessage(void* pThreadDB_p);

#if defined(__cplusplus)
}
#endif
