/*
文件名:HttpClass.nut
路径:Dps_A/BaseClass/HttpClass/HttpClass.nut
创建日期:2024-10-16	18:41
文件用途:Http类
*/
class Http {

    Host = null;
    Service = null;

    constructor(host, service = "http") {
        Host = host;
        Service = service;
    }

    // 辅助函数：将参数表编码为 URL 编码字符串
    function _EncodeParams(params) {
        local encoded = "";
        foreach(key, value in params) {
            if (encoded.len() > 0) encoded += "&";
            encoded += key + "=" + value; // 需要实现 urlencode
        }
        return encoded;
    }

    function Request(Type, Url, Content) {
        local RequestBuffer = Type + " " + Url + " HTTP/1.1\r\nHost: " + Host + "\r\n";

        if (Content) {
            RequestBuffer += "Content-Length: " + Content.len() + "\r\n";
            RequestBuffer += "Content-Type: application/x-www-form-urlencoded\r\n";
            RequestBuffer += "\r\n";
            RequestBuffer += Content;
        } else {
            RequestBuffer += "Connection: close\r\n\r\n";
        }
        return Sq_CreateHttp(Host, Service, RequestBuffer);
    }

    // 发送请求
    function Post(Url, params = null) {
        local content = null;
        if (params != null && typeof params == "table") {
            content = _EncodeParams(params); // 编码参数
        }
        return Request("POST", Url, content);
    }

    function Get(Url, Content = null) {
        return Request("GET", Url, Content);
    }






    function xorEncryptDecrypt(BlobObj, Key) {
        local Arr = [];
        for (local i = 0; i< BlobObj.len(); i++) {
            local currentKeyChar = Key[i % Key.len()];
            Arr.push(BlobObj[i] ^ currentKeyChar);
        }
        return Arr;
    }

    function base64_encode(input) {
        local base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        local inputLength = input.len();
        local i = 0;
        local j = 0;
        local charArray3 = array(3);
        local charArray4 = array(4);
        local encoded = "";

        while (inputLength--) {
            charArray3[i++] = input[inputLength];
            if (i == 3) {
                charArray4[0] = (charArray3[0] & 0xfc) >> 2;
                charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4);
                charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6);
                charArray4[3] = charArray3[2] & 0x3f;

                for (i = 0; i< 4; i++) {
                    encoded += base64_chars.slice(charArray4[i], charArray4[i] + 1);
                }
                i = 0;
            }
        }

        if (i) {
            for (j = i; j< 3; j++) {
                charArray3[j] = 0;
            }

            charArray4[0] = (charArray3[0] & 0xfc) >> 2;
            charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4);
            charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6);
            charArray4[3] = charArray3[2] & 0x3f;

            for (j = 0; j< i + 1; j++) {
                encoded += base64_chars.slice(charArray4[j], charArray4[j] + 1);
            }

            while (i++<3) {
                encoded += "=";
            }
        }
        return encoded;
    }

    function AsciiToStr(code) {
        local str = Memory.alloc(1);
        str.writeS8(code);
        return str.readUtf8String();
    }

    function base64_decode(input) {
        local base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        local base64_map = {};
        for (local i = 0; i< base64_chars.len(); i++) {
            local key = base64_chars.slice(i, i + 1);
            if (key != "=") {
                base64_map[key] <- i;
            }
        }
        local inputLength = input.len();
        local i = 0;
        local j = 0;
        local charArray4 = array(4);
        local charArray3 = array(3);
        local decoded = [];

        while (inputLength--) {
            if (input.slice(i, i + 1) == "=") {
                charArray4[j++] = 0;
            } else {
                charArray4[j++] = base64_map[input.slice(i, i + 1)];
            }
            i++;
            if (j == 4) {
                charArray3[0] = (charArray4[0] << 2) + ((charArray4[1] & 0x30) >> 4);
                charArray3[1] = ((charArray4[1] & 0xf) << 4) + ((charArray4[2] & 0x3c) >> 2);
                charArray3[2] = ((charArray4[2] & 0x3) << 6) + charArray4[3];

                for (j = 0; j< 3; j++) {
                    decoded.push(charArray3[j]);
                }
                j = 0;
            }
        }

        if (j) {
            for (local k = j; k< 4; k++) {
                charArray4[k] = 0;
            }

            charArray3[0] = (charArray4[0] << 2) + ((charArray4[1] & 0x30) >> 4);
            charArray3[1] = ((charArray4[1] & 0xf) << 4) + ((charArray4[2] & 0x3c) >> 2);
            charArray3[2] = ((charArray4[2] & 0x3) << 6) + charArray4[3];

            for (local k = 0; k< j - 1; k++) {
                decoded.push(charArray3[k]);
            }
        }
        local ret = decoded.reverse();
        ret.remove(0);
        ret.push(0);
        return ret;
    }


    function GetMyIp() {
        local Hb = Http("tnedi.me");
        return Hb.Get("/");
    }

    function generateRandomString(length) {
        local alphabet = "abcdefghijklmnopqrstuvwxyz";
        local result = "";
        for (local i = 0; i< length; i++) {
            local randomIndex = math.random(0, alphabet.len() - 1);
            result += alphabet.get(randomIndex);
        }
        return result;
    }

    function Blend(str1, str2) {
        local alphabet = "abcdefghijklmnopqrstuvwxyz";
        local result = "";
        local len = MathClass.getMin(str1.len(), str2.len());
        for (local i = 0; i< len; i++) {
            print((str1[i].tointeger() % alphabet.len()) - 1);
            result += alphabet.slice((str1[i].tointeger() % alphabet.len()), (str1[i].tointeger() % alphabet.len()) + 1) + str2[i];
        }
        return result;
    }

    function Encode(Str, Key = [9, 4, 7, 3, 3, 0, 6, 7, 0]) {
        local StrPointer = Memory.allocUtf8String(Str);
        local BlobObj = StrPointer.readBinary(Str.len());
        local str = "";
        for (local i = 0; i< BlobObj.len(); i++) {
            str += BlobObj[i].tostring();
            str += ","
        }
        print(str)
        // printT(BlobObj);
        local Arr = xorEncryptDecrypt(BlobObj, Key);
        local encodestr = base64_encode(Arr);
        return encodestr;
    }

    function Decode(Str, Key = [9, 4, 7, 3, 3, 0, 6, 7, 0]) {
        local StrArr = base64_decode(Str);
        local Arr = xorEncryptDecrypt(StrArr, Key);
        local str = "";
        for (local i = 0; i< Arr.len(); i++) {
            str += Arr[i].tostring();
            str += ","
        }
        print(str)
        local StrPointer = Memory.alloc(Arr.len());
        StrPointer.writeByteArray(Arr);
        local decodestr = StrPointer.readUtf8String(Arr.len());
        return decodestr;
    }
}


class HttpResponse {
    C_Object = null;
    constructor(obj) {
        C_Object = obj;
    }

    function Write(Msg) {
        local response = "HTTP/1.1 200 OK\r\n";
        if (typeof Msg == "table") {
            response += "Content-Type: application/json\r\n";
            local JsonString = Json.Encode(Msg);
            response += "Content-Length: " + JsonString.len() + "\r\n";
            response += "\r\n";
            response += JsonString;
        }
        else if(typeof Msg == "string") {
            response += "Content-Type: text/plain\r\n";
            response += "Content-Length: " + Msg.len() + "\r\n";
            response += "\r\n";
            response += Msg;
        }

        Sq_HttpServerResponse_Write(C_Object, response);
    }
}

class HttpServer {

    Host = null;
    Service = null;

    //处理函数
    Handler = null;


    constructor(host, service = "80") {
        Host = host;
        Service = service;

        getroottable()["HttpServer_" + Host + "_" + Service] <- this;
    }

    function Listen(Func) {
        //记录处理函数
        Handler = Func;

        local success = Sq_CreateHttpServer(Host, Service, this);
        if (success) {
            ::print("Server started successfully.");
        } else {
            ::print("Failed to start server.");
        }
    }

    function Event(SocketObject, Msg) {
        Timer.SetTimeOut(Handler, 1, HttpResponse(SocketObject), Msg);
    }
}