/**************** Gleb Osipov http://glebosipov.com/latex-svg/  */

$.global.hasOwnProperty('restix') || (function (HOST, SELF) {
    HOST[SELF] = SELF;

    /****************
    * PRIVATE
    */
    var INNER = {};
    INNER.version = "2022-03-29-1.33";


    /** Returns if the operating system is windows 
    * @return {String} true | false
    */
    INNER.isWindows = function () {
        return ($.os.indexOf("Windows") > -1);
    }

    /** Check the request information object and construct a full URL
    * @param {request} Request information object
    * @returns{request} Request information object or throws an error
    */
    INNER.checkRequest = function (request) {
        if (request.url == undefined || request.url == "") throw Error("No property [url] found/set");
        if (request.url.toString().slice(-1) == "/") request.url = request.url.toString().slice(0, -1);

        if (request.command == undefined) request.command = "";
        if (request.command.toString()[0] == "/") request.command = request.command.toString().substr(1);

        if (request.port == undefined) request.port = "";
        if (isNaN(request.port)) throw Error("[port] is Not a Number");

        // Add port
        if (request.port != "") {
            request.fullURL = request.url + ":" + request.port;
        }
        else {
            request.fullURL = request.url;
        }

        // Add command 
        if (request.command != "") {
            request.fullURL = request.fullURL + request.command;
        }

        // not encoded, we need to encode;
        if (decodeURI(request.fullURL) == request.fullURL) {
            request.fullURL = encodeURI(request.fullURL);
        }

        if (request.method == undefined || request.method == "") request.method = "GET";
        if (!(request.method == "GET" || request.method == "POST" || request.method == "PUT" || request.method == "PATCH" || request.method == "DELETE" || request.method == "HEAD")) throw Error("Method " + request.method + " is not supported");  // Missing HEAD 

        if (request.method == "POST" && (request.binaryFilePath == undefined || request.binaryFilePath == "")) request.binaryFilePath = false;

        if (request.headers == undefined) request.headers = [];
        if (!(request.headers instanceof Array)) throw Error("Provide [headers] as Array of {name:'',value''} objects");
        if (request.body == undefined || request.body == "") request.body = false;

        if (request.body && request.binaryFilePath) throw Error("You must not provide [body] and [binaryFilePath]");

        if (request.unsafe == undefined) request.unsafe = false;

        if (request.proxy == undefined) request.proxy = false;

        return request;
    }

    /** The main connection function. Need to be slashed
    * @return {response} Response result object 
    */
    INNER.processRequest = function (request, outFile) {
        var response = {
            error: false,
            errorMsg: "",
            body: "",
            httpStatus: 900
        };

        var scriptCommands = [];
        var result = "";

        if (INNER.isWindows()) {
            // Since Win10 Update Feb 2019 msxml3 does not work anymore...
            scriptCommands.push('Dim xHttp : Set xHttp = CreateObject("MSXML2.ServerXMLHTTP.6.0")');
            // Konstanten für ADODB.Stream
            scriptCommands.push('Const adTypeBinary = 1');
            scriptCommands.push('Const adSaveCreateOverWrite = 2');
            scriptCommands.push('Const adModeReadWrite = 3');

            scriptCommands.push('Dim res');
            scriptCommands.push('On Error Resume Next');
            scriptCommands.push('xHttp.Open "' + request.method + '", "' + request.fullURL + '", False');

            if (request.proxy != false) {
                // xHttp.SetProxy 1
                scriptCommands.push('xHttp.setProxy 2, "' + request.proxy + '"');
            }

            for (var i = 0; i < request.headers.length; i++) {
                scriptCommands.push('xHttp.setRequestHeader "' + request.headers[i].name + '","' + request.headers[i].value.replace(/"/g, '""') + '"');
            }
            if (request.unsafe) {
                //~ ' 2 stands for SXH_OPTION_IGNORE_SERVER_SSL_CERT_ERROR_FLAGS
                //~ ' 13056 means ignore all server side cert error
                scriptCommands.push('xHttp.setOption 2, 13056');
            }

            if (request.body) {
                scriptCommands.push('xHttp.Send "' + request.body.replace(/"/g, '""').replace(/\n|\r/g, '') + '"');
            }
            else if ((request.method == "POST" || request.method == "PUT") && request.binaryFilePath) {
                // http://www.vbforums.com/showthread.php?418570-RESOLVED-HTTP-POST-a-zip-file
                scriptCommands.push('    Dim sFile');
                scriptCommands.push('    sFile = "' + request.binaryFilePath + '"');


                scriptCommands.push('    Set objStream = CreateObject("ADODB.Stream")');
                scriptCommands.push('    objStream.Type = adTypeBinary');
                scriptCommands.push('    objStream.Mode = adModeReadWrite');
                scriptCommands.push('    objStream.Open');
                scriptCommands.push('    objStream.LoadFromFile(sFile)');

                scriptCommands.push('    xHttp.SetRequestHeader "Content-Length", objStream.Size');
                scriptCommands.push('    xHttp.Send objStream.Read(objStream.Size)');
                scriptCommands.push('    Set objStream= Nothing');
            }
            else {
                scriptCommands.push('xHttp.Send');
            }

            scriptCommands.push('If err.Number = 0 Then');

            if (outFile) {
                scriptCommands.push('    Set objStream = CreateObject("ADODB.Stream")');
                scriptCommands.push('    objStream.Type = adTypeBinary');
                scriptCommands.push('    objStream.Mode = adModeReadWrite');
                scriptCommands.push('    objStream.Open');
                scriptCommands.push('    objStream.Write xHttp.responseBody');
                scriptCommands.push('    objStream.SaveToFile "' + outFile.fsName + '" , adSaveCreateOverWrite');
                scriptCommands.push('    objStream.Close');
                scriptCommands.push('    Set objStream= Nothing');
                /*  
                     ADODB.Stream let's you also save text data and let's you specify charset (codepage) for text-to-binary data conversion (against of Scripting.TextStream object). 
                    Const adTypeText = 2
                    Const adSaveCreateOverWrite = 2
                  
                    'Create Stream object
                    Dim BinaryStream
                    Set BinaryStream = CreateObject("ADODB.Stream")
                  
                    'Specify stream type - we want To save text/string data.
                    BinaryStream.Type = adTypeText
                  
                    'Specify charset For the source text (unicode) data.
                    If Len(CharSet) > 0 Then
                        BinaryStream.CharSet = CharSet
                    End If
                  
                    'Open the stream And write binary data To the object
                    BinaryStream.Open
                    BinaryStream.WriteText Text
                  
                    'Save binary data To disk
                    BinaryStream.SaveToFile FileName, adSaveCreateOverWrite
                End Function
                    */
                scriptCommands.push('   res = "outFile" &  vbCr & "-----http-----" & xHttp.getAllResponseHeaders &  vbCr & "-----http-----" &  xHttp.status');
            }
            else {
                scriptCommands.push('   res = xHttp.responseText  &  vbCr & "-----http-----" & xHttp.getAllResponseHeaders &  vbCr & "-----http-----" &  xHttp.status');
            }

            scriptCommands.push('Else');
            scriptCommands.push('   res =  "xHttpError "  & Err.Description &  " " & Err.Number');
            scriptCommands.push('End If');

            scriptCommands.push('Set xHttp = Nothing');
            scriptCommands.push('returnValue = res');

            scriptCommands = scriptCommands.join("\r\n");

            try {
                result = app.doScript(scriptCommands, ScriptLanguage.VISUAL_BASIC);
            }
            catch (e) {
                result = "doScriptError: " + e.message + " #" + e.number;
            }

        }
        else { // Mac
            // -L follow redirects 
            var curlString = 'curl --silent --max-time 30 --show-error -g -L ';
            for (var i = 0; i < request.headers.length; i++) {
                curlString += (' -H \'' + request.headers[i].name + ': ' + request.headers[i].value + '\'');
            }
            if (request.unsafe) {
                // Es gab einen Fall wo am Mac mit -k es nicht funktioniert hat curl: (35) Server aborted the SSL handshake
                curlString += ' -k ';
            }

            if (request.proxy != false) {
                curlString += ' --proxy ' + request.proxy
            }

            if (request.method == "HEAD") {
                curlString += ' -I --head ';
            }
            else {
                curlString += ' -X ' + request.method;
            }
            if (request.body) {
                curlString += ' -d \'' + request.body.replace(/"/g, '\\"').replace(/\n|\r/g, '') + '\'';
            }
            else if ((request.method == "POST" || request.method == "PUT") && request.binaryFilePath) {
                curlString += ' --data-binary \'@' + request.binaryFilePath + '\'';
            }

            if (outFile) {
                curlString += ' -w \'outFile\n-----http-----%{http_code}\'';
                curlString += ' -o \'' + outFile.fsName + '\''
            }
            else {
                curlString += ' -w \'\n-----http-----%{http_code}\'';
            }
            curlString += ' \'' + request.fullURL + '\'';
            // log.info(curlString);
            try {
                result = app.doScript('do shell script "' + curlString + '"', ScriptLanguage.APPLESCRIPT_LANGUAGE);
            }
            catch (e) {
                result = "doScriptError: " + e.message + " #" + e.number;
            }
        }

        // Fill response 
        if (typeof result == 'undefined') {
            throw Error("No result value. Probably System Script could not run?");
        }
        if (result.match(/^xHttpError|^curl: \(\d+\)|^doScriptError:/)) {
            response.error = true;
            response.errorMsg = result;
        }
        else {
            if (INNER.isWindows()) {
                var resArray = result.split("\r-----http-----");
                if (resArray.length == 3) {
                    response.body = resArray[0];
                    response.head = resArray[1];
                    response.httpStatus = resArray[2] * 1;
                }
                else {
                    throw Error("Wrong result value: [" + result + "]");
                }
            }
            else {
                var resArray = result.split("\r-----http-----");
                if (resArray.length == 2) {
                    if (request.method == "HEAD") {
                        response.head = resArray[0];
                        response.body = "";
                    }
                    else {
                        response.head = "";
                        response.body = resArray[0];
                    }
                    response.httpStatus = resArray[1] * 1;
                }
                else {
                    throw Error("Wrong result value: [" + result + "]");
                }
            }


            var headSplit = response.head.split(/\n|\r/);
            response.head = {}
            for (var h = 0; h < headSplit.length; h++) {
                var headProperty = headSplit[h];
                if (headProperty.replace(/\s/g, '') == "") continue;
                var colonIndex = headProperty.indexOf(":");
                response.head[headProperty.substring(0, colonIndex).toLowerCase()] = headProperty.substring(colonIndex + 1).replace(/^ +/, "");
            }
        }

        return response;
    }


    /****************
    * API 
    */
    /** Process an HTTP Request 
    * @param {request} Request object with connection Information
    * @return {response} Response object {error:error, errorMsg:errorMsg, body:body, httpStatus:httpStatus}
    */
    SELF.fetch = function (request) {
        request = INNER.checkRequest(request);
        return INNER.processRequest(request, false);
    }

    /** Process an HTTP Request and writes the result to a give File
    * @param {request} Request Object with connection Information
    * @param {outFile} File to write to
    * @return {response} Response object {error:error, errorMsg:errorMsg, body:body, httpStatus:httpStatus}
    */
    SELF.fetchFile = function (request, outFile) {
        if (outFile == undefined) throw Error("No file provided");
        if (outFile instanceof String) outFile = File(outFile);

        request = INNER.checkRequest(request);
        var response = INNER.processRequest(request, outFile);
        if (outFile.length == 0) {
            outFile.remove();
        }
        if (!outFile.exists) {
            response.error = true;
            response.errorMsg = "File was not created\n" + response.errorMsg;
        }
        return response;
    }

})($.global, { toString: function () { return 'restix'; } });

//////////////////////////////////////


        var doc = app.activeDocument;
        var page = doc.pages[doc.pages.length - 1]; // Get the active page

var dialog = new Window("dialog", "Latex Text Math Generator to SVG");
dialog.orientation = "column";
dialog.alignChildren = "fill";

// Label
var label = dialog.add("statictext", undefined, "Enter Latex Code:");
label.alignment = ["left", "top"];

// Text Area
var textArea = dialog.add('edittext', undefined, '', { multiline: true, enterKeySignalsOnChange: false });
textArea.characters = 32;
textArea.preferredSize.height = 80;


// Button Group
var buttonGroup = dialog.add("group");
buttonGroup.orientation = "row";

// Generate SVG Button
var generateButton = buttonGroup.add("button", undefined, "Generate SVG");
generateButton.onClick = function() {
    var latexCode = textArea.text;
    if (!latexCode) {
        alert("Please enter Latex code.");
        return;
    }

    // Make request to get SVG
    var request = {
        url: 'http://latex.codecogs.com/svg.latex?' + latexCode,
        method: 'GET'
    };

    var response = restix.fetch(request);

    if (response.httpStatus === 200) {
        //alert("Connected to latex.codecogs.com");

        var svgCode = response.body;

        // Create folder next to the document
        var folderName = app.activeDocument.fullName.path + "/LateX_" + app.activeDocument.name;
        var folder = new Folder(folderName);
        if (!folder.exists) {
            folder.create();
        }

        // Save SVG code as SVG file
        var svgFileName = latexCode.replace("/[^\w\d]/g", '');
        var svgFile = new File(folder + "/" + svgFileName + ".svg");
        svgFile.encoding = 'UTF-8';
        svgFile.open('w');
        svgFile.write(svgCode);
        svgFile.close();

        // Save SVG code as TXT file
        var txtFile = new File(folder + "/" + svgFileName + ".txt");
        txtFile.encoding = 'UTF-8';
        txtFile.open('w');
        txtFile.write(latexCode);
        txtFile.close();
        
        textArea.text = folderName + '/' + svgFileName + '.svg';
        label.text = 'Generated';

        alert("SVG code saved as " + svgFileName + ".svg and .txt in the LateX folder.");



    } else {
        alert("Failed to connect to latex.codecogs.com.");
    }
};



// Close Button
var closeButton = buttonGroup.add("button", undefined, "Close");
closeButton.onClick = function() {

    dialog.close();
};

dialog.show();

if(label.text == 'Generated')
    var placedItem = page.place(File(textArea.text));
