/* S&A code version: 1.0.
Copyright 2008 DGC. More info available at
http://www.digitas.com.cn 
@author:<a mailto="allen.chen@digitas.com">Allen Chen</a>
@author:<a mailto="jim.jiang@digitas.com">Jim Jiang</a>
@date:2008-7-1
*/
var _saPageId;
var _saPageTitle;
//var _saUrl;
var _saLang;
var _saZone;
var _saWidth;
var _saHeight;
var _saColorDepth;
//var _saJsVer;
//var _saExLink;
var _saRefer;
var _saEntryRefer;
var _saEntryReferHost;
var _saTrackingEvent;
var _saResolution;
var _saHost;
var _saBrowser;
var _saPlatform;
var _saPlugin;
var _saTrackingUrl="http://analytics.customercentral.com.cn/webtracking/tracking/doTrack.action";
var _saProtocol;

var _saVisitorId;
var _saMemberId;
var _saVisitId;
var _saLastViewTime;
var _saOlaCode;
var _saEmailCode;
var _saSiteCode;

var _saTracker;
var _saInitialized = false;
var _saSessionTimeout = 0;

function _saGetUrlPara(paraName) { 
  var sUrl  =  location.href;
  var sReg  =  "(?:\\?|&){1}" + paraName + "=([^&]*)";
  var re = new RegExp(sReg, "gi");
  re.exec(sUrl);
  return RegExp.$1;
}

/*Get page id*/
function _saGetPageId() {
	return (new UUID()).id;
}

/*Get page title*/
function _saGetPageTitle() {
	return _saES(document.title);
}

/*Get page url*/
function _saGetURL() {
	var l = document.location;
	var url = l.pathname + l.search;
	return url;
}

/*Get brower info*/
function _saGetBrowerInfo() {
	var n = navigator;	 
	if (self.screen) {
	  _saWidth = screen.width;
	  _saHeight = screen.height;
	  _saColorDepth = screen.colorDepth;
	} else if (self.java) {
	  var j = java.awt.Toolkit.getDefaultToolkit();
	  var s = j.getScreenSize();
	  _saWidth = s.width;
	  _saHeight = s.height;
	}
	_saBrowser = n.appName;//browser type,eg:IE,Firfox etc...
	// var browserversion = n.userAgent;//browser version;
	_saResolution = _saWidth + "x" + _saHeight + " " + _saColorDepth + "bit";
	_saPlatform = n.platform;
	
	var plugins = n.plugins;
	_saPlugin = "";
	if (plugins !== null && plugins.length > 0) {
		for(i = 0; i < plugins.length; i++) {
			_saPlugin += (plugins[i].name) + ";";
		}
	}
	
	if (n.language) _saLang = n.language.toLowerCase();
	else if (n.browserLanguage) _saLang = n.browserLanguage.toLowerCase();
	
	if (document.characterSet) _saZone = _saES(document.characterSet);
	else if (document.charset) _saZone = _saES(document.charset);
}

function _saES(s,u) {
	if (typeof(encodeURIComponent) == 'function') {
		if (u) return encodeURI(s);
		else return encodeURIComponent(s);
	} else {
		return escape(s);
	}
}

function _saTrackingData(siteId) {	
	_saPageId = _saGetPageId();
	_saPageTitle = _saGetPageTitle();
	//_saUrl = _saGetURL(); 
	_saGetBrowerInfo();
	_saRefer = window.location;
	_saHost = window.location.host;
	_saEntryRefer = document.referrer;
	_saEntryReferHost = _saExtractHost(document.referrer);
	_saProtocol = window.location.protocol;
	this.trackingParam = function() {
		var param = "?siteId="+siteId+"&plugin="+_saPlugin+"&lang="+_saLang+
		"&browser="+_saBrowser+"&width="+_saWidth+"&height="+_saHeight+"&colorDepth="+_saColorDepth+"&host="+_saHost+"&platform="+_saPlatform;
		return param;
	};
}

function _saIsExternalLink(link) {
	var hostdomain = _saProtocol + "//" + _saHost;
	return link.indexOf(hostdomain) < 0;
}

function _saTrackViewStart(trackUrl) {
	_saTrackingEvent = "viewStart";
	_saDoTrack(trackUrl + "&event=" + _saTrackingEvent);
}

var _saNewTrackViewClick = function(exLink) {
	return function() {
    	_saTrackViewClick(exLink);
    }
}

function _saTrackViewClick(trackUrl, exLink) {
	_saTrackingEvent = "viewClick";
	_saDoTrack(trackUrl + "&exLink=" + exLink + "&event=" + _saTrackingEvent);
}

var _saNewTrackViewEnd = function(trackUrl) {
	return function() {
    	_saTrackViewEnd(trackUrl);
    }
}

function _saTrackViewEnd(trackUrl) {
	_saTrackingEvent = "viewEnd";
	_saDoTrack(trackUrl + "&event=" + _saTrackingEvent);
}

function _saDoTrack(trackUrl) {
	var i = new Image(1, 1);
	i.src = trackUrl;
	i.onload = function() { _saVoid(); }
}

function _saVoid() { return; }

/**
 * Create a cookie with the given name and value and other optional parameters.
 *
 * @example cookie('the_cookie', 'the_value');
 * @desc Set the value of a cookie.
 * @example cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
 * @desc Create a cookie with all available options.
 * @example cookie('the_cookie', 'the_value');
 * @desc Create a session cookie.
 * @example cookie('the_cookie', null);
 * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
 *       used when the cookie was set.
 *
 * @param String name The name of the cookie.
 * @param String value The value of the cookie.
 * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
 * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
 *                             If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
 *                             If set to null or omitted, the cookie will be a session cookie and will not be retained
 *                             when the the browser exits.
 * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
 * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
 * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
 *                        require a secure protocol (like HTTPS).
 * @type undefined
 */

/**
 * Get the value of a cookie with the given name.
 *
 * @example cookie('the_cookie');
 * @desc Get the value of a cookie.
 *
 * @param String name The name of the cookie.
 * @return The value of the cookie.
 * @type String
 */
function _saCookie(name, value, options) {
    if (typeof value != 'undefined') { // name and value given, set cookie
        options = options || {};
        if (value === null) {
            value = '';
            options.expires = -1;
        }
        var expires = '';
        if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
            var date;
            if (typeof options.expires == 'number') {
                date = new Date();
                date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
            } else {
                date = options.expires;
            }
            expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
        }
        // CAUTION: Needed to parenthesize options.path and options.domain
        // in the following expressions, otherwise they evaluate to undefined
        // in the packed version for some reason...
        var path = options.path ? '; path=' + (options.path) : '; path=/';
        var domain = options.domain ? '; domain=' + (options.domain) : '';
        var secure = options.secure ? '; secure' : '';
        document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
    } else { // only name given, get cookie
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = _saTrim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
};

function _saTrim(str) {
	var s = str.replace(/^(\s)*/, '');
	s = s.replace(/(\s)*$/, '');
	return s;
}

function _saExtractHost(url) {
	var hostWithPort = url.substring(url.indexOf("://") + 3);
	hostWithPort = hostWithPort.substring(0, hostWithPort.indexOf("/"));
	return (hostWithPort.indexOf(":") < 0) ? hostWithPort : hostWithPort.substring(0, hostWithPort.indexOf(":"));
}

function _saIsBlank(str) {
	if (str == null || str == "") 
		return true;
	else
		return false;
}

function _saGetEmailDomain(email) {
	if (_saIsBlank(email)) return "";
	var p = email.indexOf("@");
	if (p < 0 || p >= email.length  - 1) return "";
	return email.substring(p + 1);
}

// On creation of a UUID object, set it's initial value
function UUID(){
	this.id = this.createUUID();
}

// When asked what this Object is, lie and return it's value
UUID.prototype.valueOf = function(){ return this.id; }
UUID.prototype.toString = function(){ return this.id; }

//
// INSTANCE SPECIFIC METHODS
//

UUID.prototype.createUUID = function(){
	//
	// Loose interpretation of the specification DCE 1.1: Remote Procedure Call
	// described at http://www.opengroup.org/onlinepubs/009629399/apdxa.htm#tagtcjh_37
	// since JavaScript doesn't allow access to internal systems, the last 48 bits 
	// of the node section is made up using a series of random numbers (6 octets long).
	//  
	var dg = new Date(1582, 10, 15, 0, 0, 0, 0);
	var dc = new Date();
	var t = dc.getTime() - dg.getTime();
	var h = '-';
	var tl = UUID.getIntegerBits(t,0,31);
	var tm = UUID.getIntegerBits(t,32,47);
	var thv = UUID.getIntegerBits(t,48,59) + '1'; // version 1, security version is 2
	var csar = UUID.getIntegerBits(UUID.rand(4095),0,7);
	var csl = UUID.getIntegerBits(UUID.rand(4095),0,7);

	// since detection of anything about the machine/browser is far to buggy, 
	// include some more random numbers here
	// if NIC or an IP can be obtained reliably, that should be put in
	// here instead.
	var n = UUID.getIntegerBits(UUID.rand(8191),0,7) + 
			UUID.getIntegerBits(UUID.rand(8191),8,15) + 
			UUID.getIntegerBits(UUID.rand(8191),0,7) + 
			UUID.getIntegerBits(UUID.rand(8191),8,15) + 
			UUID.getIntegerBits(UUID.rand(8191),0,15); // this last number is two octets long
	return tl + h + tm + h + thv + h + csar + csl + h + n; 
}


//
// GENERAL METHODS (Not instance specific)
//


// Pull out only certain bits from a very large integer, used to get the time
// code information for the first part of a UUID. Will return zero's if there 
// aren't enough bits to shift where it needs to.
UUID.getIntegerBits = function(val,start,end){
	var base16 = UUID.returnBase(val,16);
	var quadArray = new Array();
	var quadString = '';
	var i = 0;
	for(i=0;i<base16.length;i++){
		quadArray.push(base16.substring(i,i+1));	
	}
	for(i=Math.floor(start/4);i<=Math.floor(end/4);i++){
		if(!quadArray[i] || quadArray[i] == '') quadString += '0';
		else quadString += quadArray[i];
	}
	return quadString;
}

// Numeric Base Conversion algorithm from irt.org
// In base 16: 0=0, 5=5, 10=A, 15=F
UUID.returnBase = function(number, base){
	//
	// Copyright 1996-2006 irt.org, All Rights Reserved.	
	//
	// Downloaded from: http://www.irt.org/script/146.htm	
	// modified to work in this class by Erik Giberti
	var convert = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];
    if (number < base) var output = convert[number];
    else {
        var MSD = '' + Math.floor(number / base);
        var LSD = number - MSD*base;
        if (MSD >= base) var output = this.returnBase(MSD,base) + convert[LSD];
        else var output = convert[MSD] + convert[LSD];
    }
    return output;
}

// pick a random number within a range of numbers
// int b rand(int a); where 0 <= b <= a
UUID.rand = function(max){
	return Math.floor(Math.random() * max);
}

function _saRebuildTrackUrl() {
	var trackUrl = _saTrackingUrl;
	
	trackUrl += "&viewUUID="+_saGetPageId();
	
	_saVisitorId = _saCookie("_saVisitorId");
	_saMemberId = _saGetUrlPara("_saMemberId");
	if (_saIsBlank(_saMemberId)) {
		_saMemberId = _saCookie("_saMemberId");
	} else {
		_saCookie('_saMemberId', _saMemberId, { expires: 36500 });
	}
	_saVisitId = _saCookie("_saVisitId");
	_saLastViewTime = _saCookie("_saLastViewTime");
	
	/* Set visitorId, memberId */
	if (_saIsBlank(_saVisitorId)) {
		_saVisitorId = new UUID().id;
		_saCookie('_saVisitorId', _saVisitorId, { expires: 36500 });
		trackUrl += "&visitorUUID=" + _saVisitorId + "&newVisitor=true";
	} else {
		trackUrl += "&visitorUUID=" + _saVisitorId;
	}
	if (!_saIsBlank(_saMemberId)) {
		trackUrl += "&memberId=" + _saES(_saMemberId);
	}
	
	/* Set visitId, if has sessionTimeout configured, validate whether the session is expired or not */
	if (_saIsBlank(_saVisitId) || _saIsBlank(_saLastViewTime)) {
		// New visits
		_saGetPageId();
		_saVisitId = new UUID().id;
		_saCookie('_saVisitId', _saVisitId);
		trackUrl += "&visitUUID=" + _saVisitId + "&newVisit=true";
	} else {
		// Old visits
		if ((_saSessionTimeout > 0) && (new Date().getTime() - _saLastViewTime > _saSessionTimeout * 60 * 1000)) {
			// If set valid session timeout and session is expired, create new visits 
			_saVisitId = new UUID().id;
			_saCookie('_saVisitId', _saVisitId);
			trackUrl += "&visitUUID=" + _saVisitId + "&newVisit=true";
		} else {
			trackUrl += "&visitUUID=" + _saVisitId;
		}
	}
	
	if (!_saInitialized) {
		/* Set campaign track param */
		_saOlaCode = _saGetUrlPara("_saOlaCode");
		_saEmailCode = _saGetUrlPara("_saEmailCode");
		_saSiteCode = _saGetUrlPara("_saSiteCode");//customer link
		
		if (!_saIsBlank(_saOlaCode)) {
			trackUrl += "&campaignCode=" + _saES(_saOlaCode) + "&campaignType=ola";
			trackUrl += "&entryRefer=" + _saES(_saEntryRefer);
			trackUrl += "&entryReferHost=" + _saES(_saEntryReferHost);
		} else if (!_saIsBlank(_saEmailCode)) {
			trackUrl += "&campaignCode=" + _saES(_saEmailCode) + "&campaignType=email";
			var emailStr = _saGetUrlPara("_saEmail");
			var emailDomain = _saGetEmailDomain(emailStr);
			trackUrl += "&entryRefer=" + _saES(emailStr);
			trackUrl += "&entryReferHost=" + _saES(emailDomain);
			trackUrl += "&email=" + _saES(_saGetUrlPara("_saEmail"));
		} else if (!_saIsBlank(_saSiteCode)) {
			trackUrl += "&campaignCode=" + _saES(_saSiteCode) + "&campaignType=site";
		} else if (!_saIsBlank(_saEntryRefer) && _saIsExternalLink(_saEntryRefer)) {
			trackUrl += "&campaignCode=search&campaignType=search";
			trackUrl += "&entryRefer=" + _saES(_saEntryRefer);
			trackUrl += "&entryReferHost=" + _saES(_saEntryReferHost);
		} else {
			trackUrl += "&campaignCode=direct&campaignType=direct";
		}
		
		if(_saGetUrlPara("trackingType") == "email")
			trackUrl += "&trackingType=email";
	}
	
	return trackUrl;
}

/**
 * Create a tracker for track with optional parameters.
 *
 * @example 
 * _saTracker = new _SATracker();
 * _saTracker._initData('siteId');
 * _saTracker._setSessionTimeout(30);
 * _saTracker._setMemberLogin('loginId');
 * _saTracker._track();
 * @desc 
 * Create a tracker.
 * Initialize data for a site with a site id.
 * Set session timeout, the parameter unit is minute.
 * Set member login id if member has logined.
 * Do track.
 *
 * @type undefined
 */
function _SATracker() {
	this._initData = function(siteId) {
		_saTrackingUrl += new _saTrackingData(siteId).trackingParam();
	};
	this._setSessionTimeout = function(minutes) {
		_saSessionTimeout = minutes;
	};
	this._setMemberLogin = function(loginId) {
		if (_saIsBlank(loginId)) return;
		_saCookie('_saMemberId', loginId, { expires: 36500 });
	};
	this._setMemberLogout = function() {
		_saCookie('_saMemberId', null);
	};
	this._trackPageview = function(pageview) {
		if (_saProtocol == "file:") return;
		var trackUrl = _saRebuildTrackUrl();
		
		if (_saInitialized) trackUrl += "&campaignCode=direct&campaignType=direct";
		
		if (typeof pageview != 'undefined') {
			trackUrl += "&pageTitle=" + _saES(pageview);
			trackUrl += "&refer=" + _saES(pageview);
		} else {
			trackUrl += "&pageTitle=" + _saPageTitle;
			if (document.location.href.indexOf("https") >= 0) {
				/* If site is https, then must add refer, because can't get refer from request header */
				trackUrl += "&refer=" + _saES(document.location.href);
			}
		}
		
		/* Do view start track, and update last view time into cookie */
		_saTrackViewStart(trackUrl);
		_saCookie("_saLastViewTime", new Date().getTime());
		
		if (_saInitialized) return;
		
		_saInitialized = true;
		/* Bind external link click event and view end event */
		if (window.addEventListener) {//FireFox
		  	window.addEventListener('beforeunload', _saNewTrackViewEnd(trackUrl), false);
		  	for(var b = 0; b < document.links.length; b++) {
				var d = document.links[b];
				var linkItem = d.href;
				if (_saIsExternalLink(linkItem))
					d.addEventListener('click', _saNewTrackViewClick(trackUrl, linkItem), false);				
	  		}
		} else if (window.attachEvent) {//IE
		  	window.attachEvent('onunload', _saNewTrackViewEnd(trackUrl));
		  	for(var b = 0; b<document.links.length; b++) {
				var d = document.links[b];
				var linkItem = d.href;
				if (_saIsExternalLink(linkItem))
					d.attachEvent('onclick', _saNewTrackViewClick(trackUrl, linkItem));	
	  		}
		}
	}
	this._trackEvent = function(event) {
		var trackUrl = _saRebuildTrackUrl();
		if (typeof event != 'undefined') {
			trackUrl += "&pageTitle="+_saES(event);
			trackUrl += "&refer=" + _saES(event);
			trackUrl += "&campaignCode=event&campaignType=event";
			_saTrackViewStart(trackUrl);
			_saCookie("_saLastViewTime", new Date().getTime());
		}
	}
	this._track = function() {
		this._trackPageview();
	};
}

_saTracker = new _SATracker();
