<%@ language = "JavaScript" %>
<% /*
    $Revision$
    $Id$

    File:           topdesk.asp

    Description:    Conversie van xml naar json voor TOPdesk koppeling
    Parameters:
    Context:

    Notes:          Informatie m.b.t. Topdesk API : https://developers.topdesk.com/
*/
var JSON_Result = true;
ANONYMOUS_Allowed = 1;
%>
<!-- #include file="../Shared/common.inc" -->
<!-- #include file="../Shared/save2db.inc" -->
<!-- #include file="../Shared/xml_converter.inc" -->
<%
    var ll = getQParamInt("logging", 0);
    if (ll > 0)
        __Logging = ll; // Voor de rest van dit bestand

    function connectTopdesk(methode, actie, params)
    {
        var topdesk_aut = params.info.api_key;
        var topdesk_baseurl = params.info.base_url;
        var topdesk_url = "";
        var missing_id = false;
        var contenttype = "application/json";

        var topdesk_conn= { aut:         params.info.api_key
                          , baseurl:     params.info.base_url
                          , url:         ""
                          , contenttype: "application/json"
                          , methode:     methode
                          , actie:       actie
                          };

        switch (actie) // Gebruik hier de parameter uit de aanroep. Topdesk_conn.actie wordt gewijzigd in attachment-POST door incident-POST en change-POST als params.info.boundary bestaat.
        {
            case "incident":        topdesk_url = "/tas/api/incidents";
                                    switch (methode)
                                    {
                                        case "POST":    if (params.info.boundary) // Dus voor attachment.
                                                        {
                                                            missing_id = (params.info.get_id ? false : true);
                                                            topdesk_conn.url = topdesk_url + "/id/" + params.info.get_id + "/attachments";
                                                            topdesk_conn.methode = "POST";
                                                            topdesk_conn.actie = "attachment";
                                                            topdesk_conn.contenttype = "multipart/form-data;boundary=" + params.info.boundary;
                                                        }
                                                        else
                                                        {
                                                            topdesk_conn.url = topdesk_url;
                                                        }
                                                        break;
                                        case "PUT":
                                        case "PATCH":   if (params.info.get_id) topdesk_conn.url = topdesk_url + "/id/" + params.info.get_id;
                                                        if (params.info.get_number) topdesk_conn.url = topdesk_url + "/number/" + params.info.get_number;
                                                        break;
                                        case "GET":     topdesk_conn.url = topdesk_url + ( params.inc_id
                                                                                         ? "/id/" + params.info.get_id
                                                                                         : (params.start ? "?start="+params.start : "") // start is offset vanaf welk recordnr de volgende 10 records worden getoond.
                                                                                         );
                                                        break;
                                        default:        topdesk_conn.methode = "";
                                    }
                                    break;
            case "call_types":      topdesk_conn.url = "/tas/api/incidents/call_types";
                                    break;
            case "categories":      topdesk_conn.url = "/tas/api/incidents/categories";
                                    break;
            case "subcategories":   topdesk_conn.url = "/tas/api/incidents/subcategories";
                                    break;
            case "person":          topdesk_url = "/tas/api/persons?query=";
                                    switch (methode)
                                    {
                                        case "GET":     topdesk_conn.url = topdesk_url + ((params.lookup && params.lookup.qparams) ? params.lookup.qparams : "");
                                                        break;
                                        default:        topdesk_conn.methode = "";
                                    }
                                    break;
            case "change":          topdesk_url = "/tas/api/operatorChanges";
                                    switch (methode)
                                    {
                                        case "POST":    if (params.info.boundary) // Dus voor attachment.
                                                        {
                                                            missing_id = (params.info.get_id ? false : true);
                                                            topdesk_conn.url = topdesk_url + "/" + params.info.get_id + "/attachments";
                                                            topdesk_conn.methode = "POST";
                                                            topdesk_conn.actie = "attachment";
                                                            topdesk_conn.contenttype = "multipart/form-data;boundary=" + params.info.boundary;
                                                        }
                                                        else
                                                        {
                                                            topdesk_conn.url = topdesk_url;
                                                        }
                                                        break;
                                        case "PATCH":   missing_id = (params.info.get_id ? false : true);
                                                        topdesk_conn.url = topdesk_url + "/" + params.info.get_id;
                                                        topdesk_conn.contenttype = "application/json-patch+json";
                                                        break;
                                        case "GET":     topdesk_conn.url = topdesk_url + (params.info.get_id ? "/" + params.info.get_id : "");
                                                        break;

                                        default:        topdesk_conn.methode = "";
                                    }
                                    break;
        }
        if (missing_id)
        {
            __Logging = 3;
            __Log({"missing_id": { "paramsinfo": params.info
                                 , "connection": topdesk_conn
                                 }
                  });
        }
        else
        {
            __Log({"connectiondata": topdesk_conn});
        }
        topdesk_url = topdesk_conn.baseurl + topdesk_conn.url;
        __Log("URL to TOPdesk: " + topdesk_url);
        __Log({"body_data": params.data});
        var errmsg = "";
        var status = -1;
        var data = {};
        if (topdesk_conn.methode != "" && !missing_id)
        {
            try
            {
                var http_request = Server.CreateObject("WinHTTP.WinHTTPRequest.5.1");
                http_request.open(topdesk_conn.methode, topdesk_url, false); // Synchroon
                if (topdesk_conn.methode == "POST")
                {
                    if (topdesk_conn.actie == "incident")
                    {
                        var body_data = params.data;
                        http_request.setRequestHeader("Authorization", topdesk_aut);
                        http_request.setRequestHeader("Accept", "application/json");
                        http_request.setRequestHeader("Content-Type", topdesk_conn.contenttype);
                        http_request.send(JSON.stringify(body_data));
                    }
                    else if (topdesk_conn.actie == "change")
                    {
                        var body_data = params.data;
                        http_request.setRequestHeader("Authorization", topdesk_aut);
                        http_request.setRequestHeader("Accept", "application/json");
                        http_request.setRequestHeader("Content-Type", topdesk_conn.contenttype);
                        http_request.send(JSON.stringify(body_data));
                    }
                    else if (topdesk_conn.actie == "attachment")
                    {
                        http_request.setRequestHeader("Authorization", topdesk_aut);
                        http_request.setRequestHeader("Content-Type", topdesk_conn.contenttype);
                        http_request.setRequestHeader("Accept","application/json");
                        http_request.setRequestHeader("Content-Transfer-Encoding", "base64");
                        http_request.Send(params.data);
                    }
                }
                else if (topdesk_conn.methode == "PATCH")
                {
                    var body_data = (topdesk_conn.actie == "change"? [params.data] : params.data);
                    http_request.setRequestHeader("Authorization", topdesk_aut);
                    http_request.setRequestHeader("Accept", "application/json");
                    http_request.setRequestHeader("Content-Type", topdesk_conn.contenttype);
                    http_request.send(JSON.stringify(body_data));
                }
                else if (methode == "GET")
                {
                    http_request.setRequestHeader("Authorization", topdesk_aut);
                    http_request.setRequestHeader("Accept", "application/json");
                    http_request.send();
                }
                //
                status = http_request.status;
                var status_ok = "200,201,204,206";
                if (status_ok.indexOf(status) == -1)
                {
                    errmsg = "TOPdesk error. Status: " + http_request.status;
                }
                else
                {
                    if (http_request.responseText)
                    {
                        data = JSON.parse( http_request.responseText);
                    }
                    else
                        data = {};
                }
            }
            catch (e)
            {
                errmsg = "TOPdesk connection error: " + e.description;
            }
        }
        else
        {
            errmsg = (missing_id ? "unknown id in " : "No method found for executing ") + topdesk_url;
        }
        var connect_result = { status: status
                             , message: errmsg
                             , data: data
                             };
        if (missing_id)
        {
            __Log({"connect_result": connect_result});
        }
        return connect_result;
    }   // connectTopdesk

    function load_headerdata()
    {
        if (debug == 1)
        {
            function loadMSXML(x)
            {
                var fso = new ActiveXObject("Scripting.FileSystemObject");
                var file_ext = x.file.slice(-4);
                var ForReading = 1;
                var f1 = fso.OpenTextFile(x.file, ForReading );
                var text = f1.ReadAll();
                f1.Close();

                text = text.substr(text.indexOf("<facilitor>")); // Verwijder alles totdat je de <facilitor> tag tegenkomt.
                if ((text.substr(0,14) != "<?xml version=") && (file_ext == ".xml"))
                {   // Bij ontbreken van encoding in de xml-file treedt de fout
                    // "An invalid character was found in the text content"
                    // op als er diakritische tekens in het xml-bestand staan.
                    // Voeg daarom encoding toe.
                    text = "<?xml version='1.0' encoding='windows-1250'?>" + "\n\r" + text;
                }

                x.doc = new ActiveXObject("MSXML2.DOMDocument.6.0");
                x.doc.async = false;
                x.doc.loadXML(text);
                x.err_code = x.doc.parseError.errorCode;
                x.err_msg = (x.doc.parseError.errorCode != 0 ? x.doc.parseError.reason : "");

                return x;
            }

            var custpath = "../../CUST/PNBR";
            var loader = { success: false
                         , status: -1
                         , xml: { file: Server.MapPath(custpath + "/xsl/" + "mld_434135_1_transformed.xml") }
                         , xsl: { file: Server.MapPath(custpath + "/xsl/" + "zendesk.xsl") }
                         };
            loader.xml = loadMSXML(loader.xml);
            var objreq = xmlToJson(loader.xml.doc);
            //__Log(objreq);
            __Log({"headerdata": {"melding": objreq.melding, "topdesk": {"info": objreq.facilitor.topdesk.info, "data": objreq.facilitor.topdesk.data}}});
            return objreq.facilitor;
        }
        else
        {
            // Lees de xml-data uit de html-header.
            var xmlReq = Server.CreateObject("MSXML2.DOMDocument.6.0");
            xmlReq.load(Request);
            // Converteer de xml naar json-dataobject.
            var objreq = xmlToJson(xmlReq);
            if (objreq && objreq.facilitor && objreq.facilitor.melding && objreq.facilitor.topdesk.info && objreq.facilitor.topdesk.data)
            {
                __Log({"headerdata": {"melding": objreq.facilitor.melding, "topdesk": {"info": objreq.facilitor.topdesk.info, "data": objreq.facilitor.topdesk.data}}});
            }
            return objreq.facilitor;
        }
    }   // load_headerdata

    function getTypeOf(value)
    {
        if (typeof value === "string" || value instanceof String)               return "isString";
        if (typeof value === "number" && isFinite(value))                       return "isNumber";
        if (typeof value === "boolean")                                         return "isBoolean";
        if (typeof value === "symbol")                                          return "isSymbol";
        if (typeof value === "undefined")                                       return "isUndefined";
        if (typeof value === "function")                                        return "isFunction";
        if (value === null)                                                     return "isNull";
        if (value && typeof value === "object" && value.constructor === Array)  return "isArray";
        if (value && typeof value === "object" && value.constructor === Object) return "isObject";
        if (value && typeof value === "object" && value.constructor === RegExp) return "isRegExp";
        if (value instanceof Error && typeof value.message !== "undefined")     return "isError";
        if (value instanceof Date)                                              return "isData";
        return "isUnknown";
    }   // getTypeOf

    function resolve_obj(methode, src, path, value)
    {
        //__Log("resolve_obj " + path);
        var methode = (methode == "PATCH" ? "PATCH" : "GET");
        var result = src;
        var found = true;
        var path_arr = path.split(".");
        var last_index = path_arr.length;
        for (var i = 0; i < last_index; i++)
        {
            var indx = -1;
            var node = path_arr[i];
            if (node.indexOf("[") > 0)
            {
                node = path_arr[i].split("[")[0];
                indx = path_arr[i].split("[")[1].replace("[","").replace("]","");
            }
            var t = getTypeOf(result[node]);
            //__Log("__> " + node + ": "+ t + (indx != -1 ? " ["+indx+"]" : ""));
            switch (t)
            {
                case "isObject":
                case "isString": if (methode == "PATCH" && (i == last_index-1))
                                    result[node] = value;
                                 else
                                    result = result[node];
                                 break;
                case "isArray":  if (result[node].length && indx >= 0 && indx < result[node].length)
                                 {
                                    if (methode == "PATCH" && (i == last_index-1))
                                        result[node][indx] = value;
                                    else
                                        result = result[node][indx];
                                 }
                                 else
                                 {
                                    found = false;
                                 }
                                 break;
                default: found = false;
            }
            if (!found)
                break;
        }
        //
        __Log(path + (found?"":" not") + " resolved with methode " + methode);
        __Log({"resolve_result": result});
        //
        return ((found && methode == "GET") ? result : null);
    }   // resolve_obj

    function replaceLookups(p_obj_topdesk)
    {
        if (p_obj_topdesk.info.methode == "POST" || p_obj_topdesk.info.methode == "GET")
        {
            // Haal eerst de foreign-keys op de je nodig hebt in het data-object.
            var lookup_list = p_obj_topdesk.info.lookup_list;

            // Als er maar 1 lookup gedefinieerd is zal deze als een object in lookup_list staan.
            // Dit moet echter ook in een array staan, net zoals gebeurd als er meer dan 1 lookup gedefinieerd is.
            if (getTypeOf(lookup_list.lookup) != "isArray")
            {
                if (!lookup_list.lookup)
                {
                    lookup_list.lookup = [];
                }
                else
                {
                    var obj_lookup = lookup_list.lookup;
                    delete lookup_list.lookup;
                    lookup_list.lookup = [obj_lookup];
                }
            }

            for (var i = 0; i < lookup_list.lookup.length; i++)
            {
                var z_info = lookup_list.lookup[i];
                __Log({"lookup_info": z_info});                // Wat zoek ik waar op en waar zet ik het resultaat weer neer.
                p_obj_topdesk.lookup = lookup_list.lookup[i];  // Maak een nieuwe node lookup aan met de parameters voor het opzoeken.
                // doe een connectTopdesk met een aanvraag voor gegevens (lookup is altijd GET!)
                var z_result = connectTopdesk("GET", z_info.actie, p_obj_topdesk);
                __Log({"lookup_result": z_result});
                if (z_result.message == "" && z_result.data.length == 1)
                {
                    // voeg het resultaat toe op de aangewezen plek in p_obj_topdesk
                    __Log("Resultaat lookup van " + z_info.actie);
                    var z_waarde = resolve_obj("GET", z_result, z_info.src);
                    resolve_obj("PATCH", p_obj_topdesk, z_info.dest, z_waarde);
                }
                else
                {
                    if (z_result.status == -1)
                        __Log(z_result.message);
                    else
                        __Log("Lookup heeft geen of meer dan 1 records gevonden");
                }
                delete p_obj_topdesk.lookup;                   // Node met parameters voor lookup weer verwijderen.
            }
        }
    }   // replaceLookups

    function streamdata(params, filedata)
    {
        var oStream = new ActiveXObject("ADODB.Stream");
        oStream.charset = "utf-8";
        oStream.Open();
        oStream.Type = 2; // adTypeText
        oStream.LineSeparator = -1;
        // Elke regel van WriteText wordt met CrLf afgesloten. Zet deze niet in de string want dan worden ze als lettertekens beschouwd.
        oStream.WriteText("", 1);
        oStream.WriteText("--" + params.info.boundary, 1);
        oStream.WriteText('Content-Disposition: form-data; name="file"; filename="' + params.info.filename + '"', 1); // LET OP: file en bestandsnaam MOETEN tussen dubbele quotes staan!
        oStream.WriteText("Content-Type: application/plain; charset=utf-8", 1);
        oStream.WriteText("Content-Transfer-Encoding: base64", 1);
        oStream.WriteText("", 1);
        oStream.WriteText(filedata, 1);
        oStream.WriteText("--" + params.info.boundary + "--", 1);
        oStream.Position = 0;
        //
        return oStream;
    }   // streamdata

    // *************************************************************************
    function addAttachments(p_obj_topdesk, p_topdesk_result)
    {
        __Log("addAttachments: " + p_obj_topdesk.info.methode);
        attach_result = [];
        if ((p_obj_topdesk.info.methode == "POST" || p_obj_topdesk.info.methode == "PATCH") && (p_obj_topdesk.info.actie == "change" || p_obj_topdesk.info.actie == "incident"))
        {
            var t = (p_obj_topdesk.bijlagen ? getTypeOf(p_obj_topdesk.bijlagen.bijlage) : "isUnknown");
            __Log("bijlagen: " + (t == "isUndefined" ? "<geen>" : t));
            switch (t)
            {
                case "isUndefined": var bijlagen = [];                               break; // geen bijlagen
                case "isObject":    var bijlagen = [p_obj_topdesk.bijlagen.bijlage]; break; // 1 bijlage
                case "isArray":     var bijlagen = p_obj_topdesk.bijlagen.bijlage;   break; // 2 of meer bijlagen
                default:            var bijlagen = [];
            }
            for (var i=0; i < bijlagen.length; i++)
            {
                var bijlage = bijlagen[i];
                var new_topdesk = { info: p_obj_topdesk.info };
                new_topdesk.info.get_id = p_topdesk_result.data.id;
                new_topdesk.info.boundary = "eWmWdiyWZVsqRAlEjgwicQsLnvXBJAVw"; // random genoeg, als het maar niet voorkomt in de data
                new_topdesk.info.filename = bijlage.name;
                new_topdesk.info.filesize = bijlage.size;
                __Log({"new_topdesk": new_topdesk});
                //
                new_topdesk.data = streamdata(new_topdesk, bijlage.attachment);
                var result = connectTopdesk("POST", p_obj_topdesk.info.actie, new_topdesk);
                //
                result.fclt_msg = ( (result.status == 200 || result.status == 201)
                                  ? "Attachment " + result.data.fileName + " ("+ result.data.size +") toegevoegd"
                                  : "Attachment " + bijlage.name + " kon niet worden toegevoegd"
                                  );
                attach_result.push(result);
            }
        }
        return attach_result;
    }   // addAttachments

    function getResponseStatus(result)
    {
        var response_ok = "200,201,202,204,206";
        var resp_ticket = (result.ticket && (response_ok.indexOf(result.ticket.status) == -1) ? false : true);
        var resp_attach = true;
        if (result.attach)
        {   // Attach komt in result niet voor of is een array van nul of meer status-objecten.
            for (var i=0; i<result.attach.length; i++)
            {
                resp_attach = resp_attach && ((response_ok.indexOf(result.attach[i].status) == -1) ? false : true);
            }
        }
        return (resp_ticket && resp_attach) ? 200 : 400;
    }   // getResponseStatus


    function update_mld(methode, actie, melding, params)
    {
        mld_key = melding.mld_melding_key || -1;
        if (params.ticket)
        {
            var opm = (methode == "POST" ? "Creating " : "Updating ") + actie + " Topdesk. Status: " + params.ticket.status  + (params.ticket.message.length != 0?" Message: " + params.ticket.message:"");
            shared.trackaction("#MLDTRK", mld_key, opm);
        }
        if (params.attach.length)
        {
            for (i=0; i< params.attach.length; i++)
            {
                var opm = "Uploading attachment to Topdesk. "
                        + ( params.ticket.message.length != 0
                          ? " Message: " + params.ticket.message
                                         + ( params.attach && params.attach.fclt_msg && params.attach.fclt_msg.length != 0
                                           ? "\nFoutmelding: " + params.attach.fclt_msg
                                           : ""
                                           )
                          : "Status: " + params.attach[i].status
                          );
                shared.trackaction("#MLDTRK", mld_key, opm);
            }
        }
    }   // update_mld


    function update_mldopdr(methode, actie, melding, params)
    {
        var opdr_key = melding.opdracht.mld_opdr_key || -1;
        if (params.ticket)
        {
            if (params.ticket.status >= 200 && params.ticket.status < 300)
            {
                var sql = "";
                if (methode == "POST" && (actie == "incident" || actie == "change"))
                {
                    var v_omschr = "\nTOPdesk nr: " + params.ticket.data.number;
                    var v_id = "Melding naar TOPdesk doorgestuurd. id: " + params.ticket.data.id;

                    sql = "UPDATE mld_opdr"
                        + "   SET mld_opdr_externnr = " + safe.quoted_sql(params.ticket.data.id)
                        + "     , mld_opdr_omschrijving = SUBSTR( mld_opdr_omschrijving"
                        + "                                     , GREATEST(LENGTH(mld_opdr_omschrijving)+LENGTH(" + safe.quoted_sql(v_omschr) + ")-3999, 1)"
                        + "                                     ) || " +  safe.quoted_sql(v_omschr)
                        + " WHERE mld_opdr_key = " + opdr_key;
                }

                if (sql)
                    Oracle.Execute(sql);
            }
            var opm = (methode == "POST" ? "Creating " : "Updating ") + actie + " Topdesk. Status: " + params.ticket.status;
            shared.trackaction("#ORDTRK", opdr_key, opm);
        }

        if (params.attach.length)
        {
            for (i=0; i< params.attach.length; i++)
            {
                attachment = params.attach[i];
                var opm = "Uploading attachment " + attachment.data.fileName + " to Topdesk. Status: " + params.attach[i].status + "\n";
                shared.trackaction("ORDTRK", melding.opdracht.mld_opdr_key, opm);
            }
        }
    }   // update_mldopdr

    // *************************************************************************

    function topdesk_main(facilitor)
    {
        var obj_topdesk = facilitor.topdesk || {};
        //
        // Zoek eerst de benodigde id's op
        replaceLookups(obj_topdesk);
        //
        // Toevoegen van incident of change

        // Deze log staat als commentaar omdat in deze JSON ook de base64 coded bijlage zit. Dat levert te veel logging op.
        //__Log(obj_topdesk);
        // We gaan alleen een bericht versturen als we een geldige methode hebben. We gebruiken de methode NONE om
        // aan te geven dat dit bericht niet verstuurd hoeft te worden. Dit is de mogelijkheid om
        // in de stylesheet aan te geven dat je geen bericht wilt versturen op deze notificatie.
        if (obj_topdesk.info.methode != 'NONE')
        {
            var topdesk_result = connectTopdesk(obj_topdesk.info.methode, obj_topdesk.info.actie, obj_topdesk);
            __Log({"topdesk_result": topdesk_result});
            if (topdesk_result.status != -1)
            {    // Nu kunnen de bijlagen verstuurd worden.
                if (!topdesk_result.data.id)
                {   // Bij bestaande opdracht het topdesk-id overnemen vanuit de info-node.
                    topdesk_result.data.id = (obj_topdesk.info.get_id ? obj_topdesk.info.get_id : "");
                }
                var attach_result = addAttachments(obj_topdesk, topdesk_result);

                var result = { ticket: topdesk_result
                             , attach: attach_result
                             };

                if (facilitor.melding.opdracht)
                {
                    update_mldopdr(obj_topdesk.info.methode, obj_topdesk.info.actie, facilitor.melding, result)
                }
                else if (facilitor.melding)
                {
                    update_mld(obj_topdesk.info.methode, obj_topdesk.info.actie, facilitor.melding, result)
                }
                else
                {
                    var result = { ticket: { status: 600, message: "Onbekende melding" } };
                    __DoLog(facilitor);
                }
            }
            else
            {
                var result = { ticket: { status: 400, message: topdesk_result.message } };
                __DoLog(safe.html(result.ticket.message), "ff0000");
            }
        }
        else
        {
           var result = { ticket: { status: 200, message: "er hoeft geen bericht verstuurd te worden" } };
        }
        return result;
    }   // topdesk_main

    // *************************************************************************

    __Log("*> TOPdesk.api");
    var debug = 0;
    var facilitor = load_headerdata();
    var result = {};

    if (facilitor && facilitor.topdesk)
    {
        result = topdesk_main(facilitor);
    }
    else
    {
        result = { ticket: { status: 600, message: "geen topdesk data aanwezig" } };
        __DoLog(safe.html(result.ticket.message), "ff0000");
    }

    result.response_status = getResponseStatus(result);
    __Log({"result": result});
    __Log("*< TOPdesk.api: " + result.response_status);
    Response.Status = result.response_status;
    //Response.Write(JSON.stringify(result));
%>
<% ASPPAGE_END(); %>
