//
// Created by kikab on 04.06.2018.
//

#ifndef LOTRO_DAT_LIBRARY_DATOPERATIONRESULT_H
#define LOTRO_DAT_LIBRARY_DATOPERATIONRESULT_H

#include <string>
#include <memory>
#include <utility>
#include <BinaryData.h>
#include <EasyLogging++/easylogging++.h>

extern "C++"
{
namespace LOTRO_DAT {
    enum DAT_OPERATION_RESULT {
        SUCCESS = 1,
        ERROR = 0
    };

    template<typename... OutputData>
    class DatOperationResult {
        typedef DAT_OPERATION_RESULT RESULT;
    };

    class __DatOperationResult_base {
    public:
        typedef DAT_OPERATION_RESULT RESULT;

        __DatOperationResult_base() : result(SUCCESS), msg("No message") {}

        __DatOperationResult_base(const __DatOperationResult_base &other) = default;

        __DatOperationResult_base(__DatOperationResult_base &&other) noexcept = default;

        __DatOperationResult_base(RESULT result_, std::string msg_) : result(result_), msg(std::move(msg_)) {
            if (result_ == ERROR)
                LOG(ERROR) << msg;
        }

        __DatOperationResult_base &operator=(const __DatOperationResult_base &other) = default;

        __DatOperationResult_base &operator=(__DatOperationResult_base &&other) = default;

        RESULT result;
        std::string msg;
    };

    template<>
    class DatOperationResult<> : public __DatOperationResult_base {
    public:

        DatOperationResult() : __DatOperationResult_base() {}

        explicit DatOperationResult(RESULT result_) : __DatOperationResult_base(result_, "No message") {}

        DatOperationResult(RESULT result_, std::string msg_) : __DatOperationResult_base(result_, std::move(msg_)) {}
    };


    template<typename Output>
    class DatOperationResult<Output> : public __DatOperationResult_base {
    public:
        typedef DAT_OPERATION_RESULT RESULT;

        DatOperationResult() = delete;

        DatOperationResult(const DatOperationResult<Output> &other) : __DatOperationResult_base(), value(other.value) {}

        DatOperationResult(DatOperationResult<Output> &&other) noexcept
                : __DatOperationResult_base(), value(std::move(other.value)) {}

        DatOperationResult(Output &&output_, RESULT result_, const std::string &msg_ = std::string("No message provided")) : __DatOperationResult_base(
                result_, msg_), value(output_) {}

        DatOperationResult(const Output &output_, RESULT result_, const std::string &msg_ = std::string("No message provided")) : __DatOperationResult_base(
                result_, msg_), value(output_) {}

        Output value;
    };

}
}

#endif //LOTRO_DAT_LIBRARY_DATOPERATIONRESULT_H