//Copyright 2022, FOSS-VG Developers and Contributers
//
//This program is free software: you can redistribute it and/or modify it
//under the terms of the GNU Affero General Public License as published
//by the Free Software Foundation, version 3.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied
//warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//See the GNU Affero General Public License for more details.
//
//You should have received a copy of the GNU Affero General Public License
//version 3 along with this program.
//If not, see https://www.gnu.org/licenses/agpl-3.0.en.html

#pragma once

#include <tinyutf8/tinyutf8.h>
#include <string>
#include "error.hpp"
#include "../../.endianness"

#ifdef FOSSVG_ENDIAN_BIG_WORD
    #error "Honeywell-316-style endianness is not supported. If you feel like it should, feel free to participate in the project to maintain it."
#endif
#ifdef FOSSVG_ENDIAN_LITTLE_WORD
    #error "PDP-11-style endianness is not supported. If you feel like it should, feel free to participate in the project to maintain it."
#endif
#ifdef FOSSVG_ENDIAN_UNKNOWN
    #error "The endianness of your system could not be determined. Please set it manually. FOSS-VG is currently implemented using some endian-specific functions."
#endif

namespace JavaCompat {
    ErrorOr<tiny_utf8::string> importJavaString(uint8_t data[], uint16_t size) {
        std::string stdString;
        uint16_t encodedSize = static_cast<uint16_t>(data[0])<<8 | static_cast<uint16_t>(data[1]);

        if(encodedSize != size){
            return ErrorOr<tiny_utf8::string>(true, ErrorCodes::MISMATCHEDSIZE);
        }

        for(uint16_t i=2; i<size+2; i++){
            if(i != 0){
                if(data[i] == 0x80 && data[i-1] == 0xc0){
                    stdString[stdString.length() - 1] = '\0';
                    continue;
                }
            }
            stdString.push_back((char) data[i]);
        }
        return ErrorOr<tiny_utf8::string>(tiny_utf8::string(stdString));
    }

    ErrorOr<std::vector<uint8_t>> exportJavaString(tiny_utf8::string data) {
        uint16_t* size = new uint16_t;
        uint8_t* sizeBytes = reinterpret_cast<uint8_t*>(size);
        std::vector<uint8_t> output = std::vector<uint8_t>();
        std::string stdString = data.cpp_str();

        if(stdString.size() > 0xFFFF){
            return ErrorOr<std::vector<uint8_t>>(true, ErrorCodes::OVERRUN);
        }

        *size = (uint16_t) stdString.size();

        //placeholder size bytes
        output.push_back(0x00);
        output.push_back(0x00);
        for(uint16_t i=0; i<stdString.size(); i++){
            if((uint8_t) stdString[i] == 0x00){
                *size += 1;
                output.push_back(0xc0);
                output.push_back(0x80);
                continue;
            }
            output.push_back(stdString[i]);
        }

        //FIXME: endian-dependent implementation
        #ifdef FOSSVG_BIG_ENDIAN
            output[0] = *sizeBytes;
            output[1] = *(sizeBytes+1);
        #else
            #ifdef FOSSVG_LITTLE_ENDIAN
                output[0] = *(sizeBytes+1);
                output[1] = *sizeBytes;
            #else
                #error "JavaCompat::exportJavaString: An implementation for your endianness is unavailable."
            #endif
        #endif

        return ErrorOr(output);
    }

}
