
/*---------------------------------------------------------------------------*/
/* language.cpp                                                              */
/* copyright (c) innovaphone 2017                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

#include <platform.h>
#include "../lib/language.h"

int Language::GetLanguageId(const char * lang, LanguageTableEntry languages[], int numLangs, int defaultLang)
{
    if (!lang) return defaultLang;
    bool checkIso = strlen(lang) > 2;
    for (int i = 0; i < numLangs; i++) {
        if (checkIso && !strcmp(languages[i].langIso639_2, lang)) return i;
        else if (!checkIso && !strcmp(languages[i].lang, lang)) return i;
    }
    return defaultLang;
}

size_t Language::ReplaceArgs(const char * translatedString, char * buffer, size_t bufferLen, ...)
{
    ASSERT(bufferLen > 0, "Language::ReplaceArgs please hand a buffer with len ...");
    bufferLen--;
    va_list ap;
    size_t len = 0;
    size_t copyLen = 0;
    int index = 0;
    char * dollar = NULL;
    char * str = (char *)translatedString;
    char * tmp = buffer;
    char * indexEnd = NULL;
    bool tooShort = false;
    while ((dollar = strchr(str, '$')) != NULL) {           // find the first/next occurence of a dollar sign
        copyLen = dollar - str;
        if (copyLen > bufferLen - len) {                   // buffer too short?
            copyLen = bufferLen - len;
            tooShort = true;
        }
        memcpy(tmp, str, copyLen);                          // copy until dollar sign
        tmp += copyLen;
        str += copyLen;
        len += copyLen;
        if (tooShort) break;
        ++dollar;                                           // go to next char after $
        if (*dollar >= '0' && *dollar <= '9') {             // is there a number?
            index = strtoul(dollar, &indexEnd, 10);
            char buf[32];
            const char *ptr = buf;
            copyLen = 0;
            uint32_t type = 0;
            va_start(ap, bufferLen);
            do {
                index--;
                type = va_arg(ap, uint32_t);                // get parameter type
                switch ((language_param_type_t)type) {      // then get the parameter itself
                case LANGUAGE_PARAM_TYPE_STRING: 
                {
                    const char * arg = va_arg(ap, const char *);
                    if (index == 0 && arg != nullptr) {
                        ptr = arg;
						copyLen = strlen(arg);
                    }
                }   break;
                case LANGUAGE_PARAM_TYPE_UINT32:
                {
                    uint32_t arg = va_arg(ap, uint32_t);
                    if (index == 0) {
                        copyLen = _sprintf(buf, "%u", arg);
                    }
                }   break;
                case LANGUAGE_PARAM_TYPE_INT32: 
                {
                    int arg = va_arg(ap, int);
                    if (index == 0) {
                        copyLen = _sprintf(buf, "%i", arg);
                    }
                }   break;
                case LANGUAGE_PARAM_TYPE_UINT64: 
                {
                    ulong64 arg = va_arg(ap, ulong64);
                    if (index == 0) {
                        copyLen = _sprintf(buf, "%llu", (unsigned long long)arg);
                    }
                }   break;
                case LANGUAGE_PARAM_TYPE_INT64: 
                {
                    long64 arg = va_arg(ap, long64);
                    if (index == 0) {
                        copyLen = _sprintf(buf, "%lli", (long long)arg);
                    }
                }   break;
                case LANGUAGE_PARAM_TYPE_DOUBLE:
                {
                    uint32_t precision = va_arg(ap, uint32_t);
                    char delimiter = va_arg(ap, int);   // event if char is a single byte, the compiler complains and wants an int here
                    double arg = va_arg(ap, double);
                    if (index == 0) {
                        copyLen = _sprintf(buf, "%.*f", precision, arg);    // this always prints a DOT . as delimiter
                        if(delimiter != '\0') {
                            char * dot = strchr(buf, '.');
                            if (dot) *dot = delimiter;
                        }
                    }
                }   break;
                default: 
                    ASSERT(false, "Language::ReplaceArgs invalid parameter type handed");
                    break;
                }
            } while (index > 0);
            va_end(ap);
			if (copyLen > 0) {
				if (copyLen > bufferLen - len) {
					copyLen = bufferLen - len;
				}
				memcpy(tmp, ptr, copyLen);
				tmp += copyLen;
				len += copyLen;
				if (len == bufferLen) {               // buffer too short :(
					break;
				}
			}
            str = indexEnd;                             // set str to end of integer index
        }
        else {                                          // no index given after the dollar sign
            if (len == bufferLen) break;
            *tmp = '$';                                 // copy the dollar sign too
            tmp++;
            str++;
            len++;
        }
    }
    if (len < bufferLen) {                        // copy the rest of the string
        copyLen = strlen(str);
        if (copyLen > bufferLen - len) {               // buffer too short?
            copyLen = bufferLen - len;
        }
        memcpy(tmp, str, copyLen);
        tmp += copyLen;
        len += copyLen;
    }
    *tmp = '\0';
    return len;
}