#include "LDFFormat.h"

// Custom Classes
#include "GeneralUtils.h"

// C++
#include <sstream>
#include <vector>

//! Returns a pointer to a LDFData value based on string format
LDFBaseData * LDFBaseData::DataFromString(const std::string& format) {
    
    // First, check the format
    std::istringstream ssFormat(format);
    std::string token;
    
    std::vector<std::string> keyValueArray;
    while (std::getline(ssFormat, token, '=')) {
        keyValueArray.push_back(token);
    }
    
    if (keyValueArray.size() == 2) {
        std::u16string key = GeneralUtils::ASCIIToUTF16(keyValueArray[0]);
        
        std::vector<std::string> dataArray;
        std::istringstream ssData(keyValueArray[1]);
        while (std::getline(ssData, token, ':')) {
            dataArray.push_back(token);
        }

		if (dataArray.size() > 2) { // hacky fix for strings with colons in them
			std::vector<std::string> newDataArray;
			newDataArray.push_back(dataArray[0]);
			std::string value = "";
			for (size_t i = 1; i < dataArray.size(); ++i) {
				value += dataArray[i] + ':';
			}
			value.pop_back(); // remove last colon
			newDataArray.push_back(value);
			dataArray = newDataArray;
		}
        
        if ((dataArray[0] == "0" || dataArray[0] == "13") && dataArray.size() == 1) {
            dataArray.push_back("");
        }
        
        if (dataArray.size() == 2) {
            eLDFType type = static_cast<eLDFType>(stoi(dataArray[0]));
            
            switch (type) {
                case LDF_TYPE_UTF_16: {
                    std::u16string data = GeneralUtils::ASCIIToUTF16(dataArray[1]);
                    return new LDFData<std::u16string>(key, data);
                }
                    
                case LDF_TYPE_S32: {
                    int32_t data = static_cast<int32_t>(stol(dataArray[1]));
                    return new LDFData<int32_t>(key, data);
                }
                    
                case LDF_TYPE_FLOAT: {
                    float data = static_cast<float>(stof(dataArray[1]));
                    return new LDFData<float>(key, data);
                }
                    
                case LDF_TYPE_DOUBLE: {
                    double data = static_cast<float>(stod(dataArray[1]));
                    return new LDFData<double>(key, data);
                }
                    
                case LDF_TYPE_U32:
            	{
                    uint32_t data;
                	
                	if (dataArray[1] == "true")
                	{
                        data = 1;
                	}
                    else if (dataArray[1] == "false")
                    {
                        data = 0;
                    }
                    else
                    {
	                    data = static_cast<uint32_t>(stoul(dataArray[1]));
                    }
                	
                    return new LDFData<uint32_t>(key, data);
                }
                    
                case LDF_TYPE_BOOLEAN: {
                    bool data;
                	
                	if (dataArray[1] == "true")
                	{
                        data = true;
                	}
                    else if (dataArray[1] == "false")
                    {
                        data = false;
                    }
                    else
                    {
	                    data = static_cast<bool>(stoi(dataArray[1]));
                    }
                	
                    return new LDFData<bool>(key, data);
                }
                    
                case LDF_TYPE_U64: {
                    uint64_t data = static_cast<uint64_t>(stoull(dataArray[1]));
                    return new LDFData<uint64_t>(key, data);
                }
                    
                case LDF_TYPE_OBJID: {
                    LWOOBJID data = static_cast<LWOOBJID>(stoll(dataArray[1]));
                    return new LDFData<LWOOBJID>(key, data);
                }
                    
                case LDF_TYPE_UTF_8: {
                    std::string data = dataArray[1];
                    return new LDFData<std::string>(key, data);
                }
                    
                case LDF_TYPE_UNKNOWN: {
                    return nullptr;
                }
            }
        }
    }
    
    return nullptr;
    
}