﻿///<reference path="/Web/Js/TESCO.js" />
///<reference path="/Web/Js/system/event.js" />
///<reference path="/Web/Js/system/event.manager.js" />
///<reference path="/Web/Js/system/connection/XMLHTTP.js" />
///<reference path="/Web/Js/system/connection/ajax.js" />
///<reference path="/Web/Js/system/cookie.js" />
///<reference path="/Web/Js/system/cache.js" />
///<reference path="/Web/Js/system/exception.js" />

/*
	Example:
	
	var myHistory = new TESCO.system.connection.ajax.History("anId");        
	if (myHistory.stale()) {
        //	refresh from ajax post
        post();
    }
    
    function post() {
		myHistory.record();
    }
*/
TESCO.$("system.connection.ajax").History = (function() {

	var CONFIG = TESCO.sites.Configuration;

    //  private static
    //#region
    //  LAT = Last Action Ticker
    var _pageLAT = parseInt(TESCO.sites.Configuration.LAT, 10);
    var _stateCookie = new TESCO.system.Cookie(CONFIG.application.stateCookieName);
    
    function _serverLAT() {
        return parseInt(_stateCookie.getValueByName("LAT"), 10);
    }
    
    var _stale = _pageLAT < _serverLAT(); //  the page has been loaded from a back or forward press after an update had occured
    var _csv = ".*?,";
    var _pattern = new RegExp(_pageLAT + _csv);
    var _useCookie = !window.sessionStorage;

    //	use the maxentries sparingly if using the cookie!
    var _maxEntries = _useCookie ? 5 : 10;
    //#endregion
    
    _constructor.stale = function() {	//	is the page stale?
        return _stale;
    }
    
    var _session = new TESCO.system.Cache.Session("ajax.History", _useCookie);
    
    function _constructor(key) {
		/// <summary>Used to prevent back and forward causing stale data to be shown</summary>
		/// <param name="name">string</param>
		/// <returns type="TESCO.system.connection.ajax.History"></returns>
        this.output = (_session.getItem(key) || "").toString();
        var _self = this;
        TESCO.system.event.attach(window, "unload",
			function() {
				_session.setItem(key, _self.output);
			}
		);
        return this;
    }

    _constructor.prototype.record = function(value) {    // record page LAT where update took place
		/// <summary>record an update</summary>
		/// <param name="value">string (optional)</param>
        if (this.output != "") {
            var _match = _pattern.exec(this.output);  //  page update already entered in cookie?
            if (_match) {
                this.output = this.output.replace(_match[0], "");    //  clear the old update, moved to the top of the stack below
            }
            var _entries = this.output.match(new RegExp(_csv, "g"));  //  crop the output to allow only a few entries
            if (_entries) {
                if (_entries.length > _maxEntries) {
                    for (var i = _maxEntries, L = _entries.length; i < L; i++) {
                        this.output = this.output.replace(_entries[i], "");
                    }
                }
            }
        }
        var _updateLAT = _serverLAT();
        if (_updateLAT === _pageLAT) {
            //  make sure the update is greater than the pageLAT, 
            //  in case the response from the AJAX request has not occured yet
            _updateLAT++;
        }
        value = value ? ("&" + value) : "";
        this.output = _pageLAT + "&" + _updateLAT + value + "," + this.output;  //  record the pageLAT, with the updated serverLAT
    }

    _constructor.prototype.staleValue = function() {
		/// <summary>is the instance stale? if so, return stale value, else null</summary>
		/// <returns>string or null</returns>
        var _result = null;
        if (_stale) { //  the page is stale, the instance may be too
            if (this.output != "") {	//	nothing in the cookie
                _result = _pattern.exec(this.output); //  did any updates occur on this page?
                if (_result) {
                    _result = _result[0].split(",")[0].split("&")[2] || true;
                } else {  //  no? search for subsequent updates to this item
                    var _matches = this.output.match(new RegExp(_csv, "g"));
                    if (_matches) { //  this item had other updates
                        for (var i = 0, L = _matches.length; i < L; i++) {
                            var _values = _matches[i].split("&");
                            if (parseInt(_values[1], 10) > _pageLAT) {
                                //  an update to this item occured in another page loaded after this page
                                _result = _values[2] || true;
                                break;
                            }
                        }
                    }
                }
            }
        }
        return _result;
    }
    
    _constructor.prototype.stale = function() { //  is the instance stale
		/// <summary>is the instance stale</summary>
		/// <returns>boolean</returns>
        return !!this.staleValue();
    }

    return _constructor;
})();

