﻿
//  The TrafficCookie object handles the "tfx" cookie, which is used to keep track of traffic "touches".
//
//  TrafficCookie usage:
//      Constructor:
//          var trafficCookie = new TrafficCookie()
//      Functions:
//          trafficCookie.addTouch(trafficMedium, trafficSource, timeStamp, domainName)
//          trafficCookie.getAllTouches()
//          trafficCookie.getLastTouch()
//
function TrafficCookie() {
    this.TFX_COOKIE_NAME = "tfx_touch";
    this.TFX_SESSION_COOKIE_NAME = "tfx_session";
    this.TOUCH_LIMIT = 10;
}

// If tfx_session cookie does not exist, this method adds new touch to existing touches in cookie and cookie will be rewritten with new value
// as follows:
//      - traffic_medium_no in new touch will not be validated
//      - traffic_source in new touch will be truncated if greater than 50 chars
//      - total number of touches will be limited to TOUCH_LIMIT
// If tfx_touch cookie is add or rewritten, the tfx_session cookie will be created.
TrafficCookie.prototype.addTouch = function() {
    var tfxSessionCookie = getCookieByName(this.TFX_SESSION_COOKIE_NAME);
    if (tfxSessionCookie && tfxSessionCookie != "" && tfxSessionCookie != 'undefined') {
        var currentTouch = tfxSessionCookie.split(",");

        if (currentTouch.length < 5) {
            currentTouch[4] = currentTouch[4];
            currentTouch[3] = "";
        }

        var allTouches = this.constructCookieValue(currentTouch);

        var expDate = new Date();
        var year = expDate.getFullYear();
        expDate.setFullYear(year + 20);

        document.cookie = this.TFX_COOKIE_NAME + "=" + allTouches +
                        "; expires=" + expDate.toUTCString() +
                        "; domain=" + currentTouch[currentTouch.length - 1] +
                        "; path=/";


        document.cookie = this.TFX_SESSION_COOKIE_NAME + "=" + "" +
                        "; domain=" + currentTouch[currentTouch.length - 1] +
                        "; path=/";
    }
}

function getCookieByName(cookieName) {
    var aCookie = document.cookie.split("; ");
    for (var i = 0; i < aCookie.length; i++) {
        // a name/value pair (a crumb) is separated by an equal sign
        var aCrumb = aCookie[i].split("=");
        if (aCrumb[0] != null) {
            if (cookieName == aCrumb[0]) {
                if (aCrumb[1] != null)
                    return aCrumb[1];
                else
                    return "";
            }
        }
    }
    // a cookie with the requested name does not exist
    return "";
}

// Retrieves all touches from cookie and returns it as a string in format:
//      traffic_medium_no,traffic_source,timestamp|traffic_medium_no,traffic_source,timestamp|traffic_medium_no,traffic_source,timestamp|...
// where:
//      - each touch consists of "traffic_medium_no,traffic_source,timestamp" e.g. "8,Direct,20090820133056"
//      - timestamp format is "yyyyMMddhhmmss" with time in 24-hr format
// Returns "" if no cookie is present.
//
// cookies are separated by semicolons
//
TrafficCookie.prototype.getAllTouches = function() {
    return getCookieByName(this.TFX_COOKIE_NAME)
}

// Returns last touch in cookie in format "traffic_medium_no,traffic_source,timestamp" e.g. "8,Direct,20090820133056" 
// or "" if no cookie present
//
TrafficCookie.prototype.getLastTouch = function() {
    var allTouches = this.getAllTouches();
    var touches = allTouches.split("|");  // split allTouches string into array; array will be empty if allTouches is an empty string
    return touches.length > 1 ? touches[touches.length - 1] : "";
}

// Returns new cookie value after adding new touch to touches retrieved from cookie.
// Traffic_source will be truncated to 50 chars.
// Total number of touches in returned value will be limited to TOUCH_LIMIT.
//
TrafficCookie.prototype.constructCookieValue = function(currentTouch) {
    var allTouches = this.getAllTouches();
    var touches = allTouches.split("|");
    var len = touches.length;

    var trafficMedium = currentTouch[0];
    var trafficSource = currentTouch[1];

    var timeStamp = currentTouch[2];
    if (timeStamp == "placeholder") {
        timeStamp = getCurrentTimeStamp();
    }

    var utmStracking = currentTouch[3];

    var newTouch = trafficMedium + "," + trafficSource.toString().substr(0, 50) + "," + timeStamp + "," + utmStracking;

    if (newTouch != touches[len - 1]) {  // don't add new touch if its same as last touch; this is to handle multiple simultaneous touches from multiple browser tabs
        touches[len] = newTouch;
        ++len;
        if (len > this.TOUCH_LIMIT) {
            touches.shift(); // remove first touch from array
        }
    }

    var cookieValue = touches.join("|");
    if (cookieValue.indexOf("|") == 0) {
        cookieValue = cookieValue.substr(1);
    }

    return cookieValue;
}

// get the current time, convert to PST and format to "yyyyMMddHHmmss" pattern
function getCurrentTimeStamp() {
    var format = "yyyyMMddHHmmss";

    // get current computer local time
    var ts = new Date();

    // get UTC date/time components
    var year = ts.getUTCFullYear();
    var month = ts.getUTCMonth();
    var day = ts.getUTCDate();
    var hour = ts.getUTCHours();
    var min = ts.getUTCMinutes();
    var sec = ts.getUTCSeconds();

    // set ts as UTC time
    ts.setFullYear(year, month, day);
    ts.setHours(hour);
    ts.setMinutes(min);
    ts.setSeconds(sec);

    // get ts milliseconds and subtract 7 hours to get PST
    var utc = ts.valueOf();
    utc -= 7 * 60 * 60 * 1000;

    // set PST time to ts
    ts.setTime(utc);

    // get PST time components
    year = ts.getFullYear();
    month = ts.getMonth() + 1;
    day = ts.getDate();
    hour = ts.getHours();
    min = ts.getMinutes();
    sec = ts.getSeconds();

    // format timestamp string with PST time
    format = format.replace("yyyy", year.toString());
    format = format.replace("MM", month.toString().padL(2, "0"));
    format = format.replace("dd", day.toString().padL(2, "0"));
    format = format.replace("HH", hour.toString().padL(2, "0"));
    format = format.replace("mm", min.toString().padL(2, "0"));
    format = format.replace("ss", sec.toString().padL(2, "0"));

    return format;
}

String.repeat = function(chr, count) {
    var str = "";
    for (var x = 0; x < count; x++) { str += chr };
    return str;
}

String.prototype.padL = function(width, pad) {
    if (!width || width < 1)
        return this;

    if (!pad) pad = " ";
    var length = width - this.length
    if (length < 1) return this.substr(0, width);
    return (String.repeat(pad, length) + this).substr(0, width);
}

String.IsNullOrEmpty = function(value) {
    var isNullOrEmpty = true;
    if (value) {
        if (typeof (value) == 'string') {
            if (value.length > 0)
                isNullOrEmpty = false;
        }
    }
    return isNullOrEmpty;
}


var trafficCookie = new TrafficCookie();
trafficCookie.addTouch();

