// ******************************************
// * $Id$
// *
// *   Log2File()
// *
// * Base64 encode / decode
// * http://www.webtoolkit.info/
// *
// ******************************************

var logfso = new ActiveXObject("Scripting.FileSystemObject");

var __LOGFILEPREFIX = 'putorders';
function Log2File(level, str, severity)
{
    // uses:  scr="../wsf_shared.js"
    //        src="./puo_settings.js"
    //
    var dtstr = toDateTimeString(new Date);
    if (level <= 1 && (typeof WScript != 'undefined'))
    {
        if (typeof WScript != 'undefined')
            WScript.Echo(dtstr + " " + str);
        else if (typeof Response != 'undefined')
        {
            Response.Write("<pre>" + dtstr + " " + safe.html(str) + "</pre>");
            Response.Flush;
        }
    }

    // Aparte logfile per maand
    var logfilename = customerId + "_" + padout((new Date).getFullYear())  + "_" + padout((new Date).getMonth() + 1) + ".log";
    if (typeof PUO_LOGPATH == "undefined")
    {
        logfilename =  "../../../temp/" + customerId + "/" + __LOGFILEPREFIX + "_" + logfilename; // voorkennis: de scheduled versie
    }
    else
        logfilename = PUO_LOGPATH + __LOGFILEPREFIX + "I_" + logfilename; // voorkennis: de immediate versie

    var simpellogfilename = logfilename.replace(/\.log$/, ".compact.log");
    var excludesimpel = /^(SELECT xml.|XML blob|Load company style|Searching attachments|====== Skip opdracht\/bestelopdr)/;
    if ((S("puo_logdestination") & 2) == 2)
    {
        if ((level <= S("puo_loglevel") && level < 2 && !str.match(excludesimpel) && str != "\n") || severity == "E" || severity == "F")
        {
            try
            {
                var flog = logfso.OpenTextFile(simpellogfilename, 8 /* ForAppending */, true /* create */);
                flog.WriteLine("{0};{1};{2}".format(dtstr, severity || "I", str.replace(/\n/g, "<nl>")));
            }
            catch(e)
            {
                var errtxt = "@@@Could not write str to logfile {0}: {1}\nIs it perhaps unicode?".format(simpellogfilename, e.description);
                if (typeof WScript != 'undefined')
                    WScript.Echo(errtxt);
                try
                {
                    flog.WriteLine(errtxt);
                }
                catch (e)
                {
                    // Waarschijnlijk readonly of anderszins locked
                }
            }
            if (flog)
                flog.Close();
        }
    }

    if( level <= S("puo_loglevel"))
    {

        if ((S("puo_logdestination") & 1) == 1)
        {
            try
            {
                var flog = logfso.OpenTextFile(logfilename, 8 /* ForAppending */, true /* create */);
                flog.WriteLine(str);
            }
            catch(e)
            {
                var errtxt = "@@@Could not write str to logfile {0}: {1}\nIs it perhaps unicode?".format(logfilename, e.description);
                if (typeof WScript != 'undefined')
                    WScript.Echo(errtxt);
                try
                {
                    flog.WriteLine(errtxt);
                }
                catch (e)
                {
                    // Waarschijnlijk readonly of anderszins locked
                }
            }
            if (flog)
                flog.Close();
        }
        if (severity == "E" || severity == "F")
        {
            // Merk op: de trigger van imp_log zal voor fatal meldingen een notificatie naar
            //          WEB_PRSSYS leden sturen. Een eventuele e-mail wordt de *volgende* run
            //          van putorders pas verstuurd.
            var sql = "INSERT INTO imp_log"
                    + "( imp_log_applicatie"
                    + ", imp_log_datum"
                    + ", imp_log_status"
                    + ", imp_log_omschrijving"
                    + ", imp_log_hint"
                    + ") VALUES"
                    + "( '$PutOrders$'"
                    + ", SYSDATE"
                    + ", " + safe.quoted_sql(severity)
                    + ", " + safe.quoted_sql((dtstr + " " + str).substr(0, 990))
                    + ", ''"
                    + ")";
           Oracle.Execute(sql);
        }
    }
}

var logcounter = 0;
function LogString2File(level, postfix, data, ext, isStream)
{
    if(level > S("puo_loglevel"))
        return;

    if (logcounter > 99)
    {
        Log2File(level, "Meer dan 100 logfiles in één run? Ik stop er mee");
        return;
    }
    var fso = new ActiveXObject("Scripting.FileSystemObject");
    var folder = custabspath + "/../../temp/" + customerId + "/putorders";
    if (!fso.FolderExists(folder))
        fso.CreateFolder(folder);
    var jsDate = new Date();
    var s = String(jsDate.getFullYear()) + padout(jsDate.getMonth() + 1) + padout(jsDate.getDate()) + "-"
          + padout(jsDate.getHours()) + padout(jsDate.getMinutes()) + padout(jsDate.getSeconds())
    var log_file = "puo_" + s + "_" + padout(logcounter++);
    log_file = log_file + "_" + postfix + "." + (ext || "txt");

    try
    {
        if (isStream)
        {
            data.SaveToFile(folder + "/" + log_file);
        }
        else
        {
            var ts  = fso.CreateTextFile(folder + "/" + log_file, true);
            ts.WriteLine (data);
            ts.Close();
        }
        Log2File(level, "{0} written to {1} ({2} bytes)".format(postfix, log_file, isStream?data.Size:String(data).length));
    }
    catch (e)
    {
        Log2File(level, "ERROR writing {0} to {1}: {2}".format(postfix, log_file, e.description));
    }
}
function LogStream2File(level, postfix, stream, ext)
{
    LogString2File(level, postfix, stream, ext, true);
}

function stream2text(stream)
{
    try
    {
        stream.Position = 0;
        var txt = stream.ReadText();
        stream.Position = 0;
        return txt;
    }
    catch(e)
    {
        throw { description: "Error in function stream2text: {0}\nStream Charset is {1}, size {2}".format(e.description, stream.Charset, stream.Size)
                           + "\nDe gegenereerde tekst is waarschijnlijk geen {0}".format(stream.Charset)
                           + "\nVerkeerde xsl in gebruik of geen xsl-output/encoding gevonden in de XSL?"};
    }
}

function trimall(s)
{
    //Spaties *en quotes* er af
    s = s.replace(/^\s+|\s+$/g,"");
    s = s.replace(/^\'+|\'+$/g,"");
    s = s.replace(/^\"+|\"+$/g,"");
    return s;
}

var lastContentType; // global
function doHTTP(url, params) // params is sterk vergelijkbaar met p_bedrijfadres
{
    params = params || {};
    if (!params.method)
        params.method = params.data?"POST":"GET"; // Met data default POST, zonder data default GET
    if (!params.headers)
        params.headers = {};
    params.headers["X-FCLT-cust"] = customerId; // Wordt door logger.inc eventueel opgepikt
    try
    {
        var WshShell = new ActiveXObject("WScript.Shell");
        var computername = WshShell.ExpandEnvironmentStrings("%COMPUTERNAME%");
    }
    catch (e)
    {
        var computername = "???";
    }
    params.headers["X-FCLT-cust"] += " (" + computername + ")";

    var http_request = new ActiveXObject("Msxml2.ServerXMLHTTP.6.0");
    var lResolve = 60 * 1000; // The default value is infinite, meaning no timeout.     DNS om ip-adres te vinden
    var lConnect = 60 * 1000; // With a default timeout value of 60 seconds             Opzetten https verbinding
    var lSend    = S("puo_sendtimeout") * 1000; // The default value is 30 seconds.     Upload data
    var lReceive = S("puo_receivetimeout") * 1000; // The default value is 30 seconds.  Server processing time en download data
    http_request.setTimeouts(lResolve, lConnect, lSend, lReceive);

    // contanten in msxml2
    var SXH_PROXY_SET_PROXY = 2;
    var SXH_OPTION_SELECT_CLIENT_SSL_CERT = 3;
    if (S("puo_useproxy"))
    {
        var proxy_ip = S("puo_proxyserveripaddress");
        Log2File(2, "Opening proxy " + proxy_ip);
        http_request.setProxy(SXH_PROXY_SET_PROXY, proxy_ip);
    }

    if (params.certificateName)
    {
        Log2File(2, "Client certificateName= " + params.certificateName);
        http_request.setOption(SXH_OPTION_SELECT_CLIENT_SSL_CERT, params.certificateName);
    }

    if (params.username && params.authmethod == 1) // Forced base64
    {
      var base64 = new Base64Cls();
      params.headers["Authorization"] = "Basic " + base64.encode(params.username + ":" + params.password);
    }
    else if (params.username && params.authmethod == 2) // Custom header, bijvoorbeeld user=X-FACILITOR-API-Key, pass=VERYSECRET
    {
      if (!params.password) // gebeurt lokaal omdat bij anonimiseren wachtwoorden worden gewist
      {                     // als we het niet ondervangen eindigt de setRequestHeader in 'Type mismatch'
        RaiseAnError(1, "Authentication method 'Custom header' is missing password");
      }

      params.headers[params.username] = params.password;
      params.username = null;
      params.password = null;
    }
    else if (params.username && params.authmethod == 3) // Stonden ze (al) in de XML
    {
      params.username = null;
      params.password = null;
    }
    else if (params.username && params.authmethod == 4) // OAuth basic authentication
    {                                                   // recursief eerst token ophalen
      var client_id = params.username;
      var client_secret = params.password;
      var params2 = { "username": client_id,
                      "password": client_secret,
                      "authmethod": 1, // forced base64
                      "method": "POST",
                      "data": "grant_type=client_credentials",
                      "headers": { "Content-Type": "application/x-www-form-urlencoded" }
                    };

      if (params.oa_scope)
        params2.data += "&scope=" + params.oa_scope;
      puo_hook.callhook("pre_custom_oauth_authentication", { params: params, params2: params2 });

      Log2File(1, "Fetching oAuth token at: " + params.token_url);
      // vaak secret tokens dus maar niet loggen Log2File(2, params2.data);
      var result = doHTTP(params.token_url, params2);
      var ctype = String(result.getResponseHeader("Content-Type"));
      if (ctype.indexOf("application/json") == -1) // kan ook application/json;charset=UTF-8 zijn
      {
        RaiseAnError(result.status, "oAuth token error. Not application/json: " + ctype);
      }

      var jresult = JSON.parse(result.responseText);
      Log2File(1, "Got token. Now resuming real request");
      params.headers["Authorization"] = "Bearer " + jresult.access_token;
      params.username = null;
      params.password = null;

      puo_hook.callhook("post_custom_oauth_authentication", { params: params, params2: params2, jresult: jresult });
    }

    http_request.open(params.method, url, false, params.username, params.password); // Synchroon

    for (var head in params.headers)
        http_request.setRequestHeader(head, params.headers[head]);

    // let op: params.data kan een string of ADODB.Stream zijn. Daarom moet de aanroeper maar loggen
    var oAbout = new ActiveXObject("SLNKDWF.About");
    var tmStart = oAbout.usTimer;
    http_request.send(params.data);
    var tm = Math.round((oAbout.usTimer - tmStart) / 1000);
    if (tm >= 2000 && params.data) // Meer dan 2 seconde?
    {
        var sz = (typeof params.data == "string"? params.data.length: params.data.Size);
        Log2File(1, "Sending {0} bytes took {1}ms, about {2}MBit/s".format(sz, tm, Math.round(sz * 8 / tm / 100) / 10));
    }
    /*global*/ lastContentType = http_request.getResponseHeader("Content-Type");

    if (http_request.status < 200 || http_request.status > 299)
    {
        var ext = null;
        var ctype = String(http_request.getResponseHeader("Content-Type"));
        if (ctype.indexOf("xml") > 0)
            ext = "xml"
        else if (ctype.indexOf("html") > 0)
            ext = "html";
        else if (ctype.indexOf("json") > 0)
            ext = "json";
        Log2File(1, "response Status = " + http_request.status + ": " + http_request.statusText);
        LogString2File(2, "HTTP response", http_request.responseText, ext); // Level 2 omdat het soms dagen doorloopt en te groot is
        Log2File(3, "response Headers = " + http_request.getAllResponseHeaders);
        RaiseAnError(http_request.status, "http_request error " + http_request.status + ": (" + http_request.statusText + ")");
    }
    else
    {
        Log2File(3, "response = " + http_request.responseText);
    }
    return http_request;
}