/*************************************************************************
*
* ADOBE CONFIDENTIAL
* ___________________
*
*  Copyright 2014 Adobe Systems Incorporated
*  All Rights Reserved.
*
* NOTICE:  All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any.  The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
**************************************************************************/

/*jslint vars: true, node: true */
"use strict";

var sharedCloudConfig = require('../handlers/sharedCloudConfig');
var https = require(sharedCloudConfig.getSharedCloudProtocol());
var step = require('step');
var logger = require('winston');
var handlerUtils = require('../utils').handlerUtils;

// Use this to define the number of most recent ETS events that will be cached when the user is not logged into IMS. (circular buffer)
var MAX_METRICS_ARRAY_LENGTH = 10;

//--- begin REST call handlers
function etsTrackEventHandler(req, res) {
    var body = '';

    req.on('data', function (chunk) {
        body += chunk.toString();
    });

    req.on('end', function () {
        var params = JSON.parse(body);
        if (params !== null) {
            params.fid = getSharedUserID(req);

            var fidCookie = 'fid=' + params.fid + "; path=/; httpOnly;",
                respHeader = {
                'Content-Type': 'application/json',
                'Set-Cookie': fidCookie
            };

            // if the browser setting says Do Not Track, then....Do Not Track (regardless of adobe Opt-In)
            // At least, however, log the fact to Splunk
            if (req.headers.dnt === '1') {
                logger.verbose("Do Not Track setting is active for " + params.fid);

                res.writeHead(200, respHeader);
                res.end("Do Not Track setting is active");
                return;
            }

            var auth = handlerUtils.getCookie(req, 'creative-cloud-v');
            if (auth !== undefined) {
                try {
                    step(
                        function (err) {
                            if (err) {
                                throw err;
                            }
                            etsLogMetrics(err, auth, params, this);
                        },
                        function returnResults(err, statusCode, responseText) {
                            if (err) {
                                logger.error('etsTrackEventHandler: err = ' + err);
                                res.statusCode = 500;
                                res.send("Error posting metrics event. error = " + err);
                                return;
                            }
                            res.writeHead(200, respHeader);
                            res.end(responseText);
                        }
                    );
                } catch (err) {
                    logger.error('etsTrackEventHandler: err = ' + err);
                    res.statusCode = 500;
                    res.send("Error posting metrics event. error = " + err);
                }
            } else {
                // The user is not logged into IMS. Add this event to our cached metrics cookie
                var metricsArray = etsDeferMetrics(handlerUtils.getCookie(req, 'ets-metrics'), params),
                    header = {
                        'Content-Type': 'application/json',
                        'Set-Cookie': [ 'ets-metrics=' + JSON.stringify(metricsArray) + "; path=/; HttpOnly;",
                                        fidCookie]
                    };
                res.writeHead(200, header);
                res.end("cached metrics for later delivery");
            }

            // Anything we post to this log will get forwarded to Splunk
            params.client_id = sharedCloudConfig.IMS_CLIENT_ID;
            logger.info('metrics:', params);
        }
    });
}
//--- end REST call handlers

// register a unique and persistant hash value so we can correlate logged-out activity with the the user's eventual adobeID,
// as well as any metrics posted to SiteCatalyst from other sub-domains of adobe.com
function getSharedUserID(req) {

    // first look for a cached hash
    var userID = handlerUtils.getCookie(req, 'fid');

    // look for s_pers which is saved by other adobe sub-domains
    if (!userID) {
        var s_pers = handlerUtils.getCookie(req, 's_pers');
        if (s_pers) {
            userID = extractfid(s_pers);
        }
    }

    // look for creative.adobe.com's cookie (this will be replaced by an s_pers cookie "very soon")
    if (!userID) {
        userID = handlerUtils.getCookie(req, 's_fid');
    }

    // create our own if none of the above worked
    if (!userID) {
        userID = createfid();
    }

    return userID;
}

// the s_pers cookie posted by sites that use SiteCatalyst contains a unique user hash to track users across
// adobe.com sub-domains. Extract and use it if available.
function extractfid(cookie) {
    var decoded = decodeURIComponent(cookie);
    if (decoded) {
        var partsArray = decoded.split('s_fid=');
        if (partsArray.length > 1) {
            var idArray = partsArray[1].split('|');
            if (idArray.length > 0) {
                return idArray[0];
            }
        }
    }
    return null;
}

// if s_pers cookie is not present or we can't parse it, we have no choice but to create our own tracking ID.
// for consistency we'll use the same format as that would be contained in s_pers
function createfid() {
    return 'xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random()*16|0,
            v = c == 'x' ? r : (r&0x3|0x8);
        return v.toString(16).toUpperCase();
    });
}

// store the MAX_METRICS_ARRAY_LENGTH most recent metrics events, and return the result
function etsDeferMetrics(cookie, metrics) {
   var metricsArray = [];

    if (cookie !== undefined && cookie.length !== 0) {
        metricsArray = JSON.parse(cookie);
        if (metricsArray.length === MAX_METRICS_ARRAY_LENGTH) {
            metricsArray.shift();
        }
    }

    metricsArray.push(metrics);

    return metricsArray;
 }

function etsLogDeferredMetrics(cookie, auth) {
    var metrics = JSON.parse(cookie);
    if (metrics === undefined || metrics.length === 0) {
        return;
    }
    // iterate through all of our cached metrics and send them to ETS
    for (var idx = 0; idx < metrics.length; idx++) {
        (function(){
            var index = idx;
            try {
                step(
                    function (err) {
                        if (err) {
                            throw err;
                        }
                        etsLogMetrics(err, auth, metrics[index], this);
                    },
                    function returnResults(err) {
                        if (err) {
                            logger.error('etsLogDeferredMetrics: err = ' + err);
                        }
                    }
                );
            } catch (err) {
                logger.error('etsLogDeferredMetrics: err = ' + err);
            }
        })();
    }
}

function etsLogMetrics(err, auth, params, callback) {
    if (err) {
        callback(err);
    }

    var path = '/ims/ets/v1/send_event?client_id=' + sharedCloudConfig.IMS_CLIENT_ID;

    path += '&code=EDGE_EXTRACT&sub_code=INTERACTION';
    path += '&ets=' + params.timestamp;
    path += '&epd=' + JSON.stringify(params);

    var options = {
        hostname: sharedCloudConfig.getIMSHost(),
        port: sharedCloudConfig.getSharedCloudPort(),
        path: path,
        method: 'GET',
        headers: {
            'Authorization': 'Bearer ' + auth
        }
    },
    bodyarr = [],
    req = https.request(options, function (response) {
        response.setEncoding('utf8');
        response.on('data', function (chunk) {
            bodyarr.push(chunk);
        });
        response.on('end', function () {
            var respText = bodyarr.join('');
            callback(null, this.statusCode, respText);
        });
    });

    req.on('error', function (localErr) {
        callback(localErr, null);
    });

    req.end();
}

function installHandlers(server) {
    server.post('/api/v1/metrics/trackEvent', etsTrackEventHandler);
}

module.exports = {
    installHandlers : installHandlers,
    etsLogDeferredMetrics : etsLogDeferredMetrics
};