//Based on Brad Neuberg's Browser history project
function History()
{
    this.initialize = function() {
      if (!isIE6plus) {
         return;
      }
      if (!historyStorage.hasKey("historyLoaded")) {
         this.raiseInitially = false;
         this.firstLoad = true;
         historyStorage.put("historyLoaded", true);
      }
      else {
         this.raiseInitially = true;
         this.firstLoad = false;   
      }
   }
       
  this.addListener = function(callback) {
      this.listener = callback;
      
      if (this.raiseInitially == true) {
         this.raiseFromHistory(this.displayedURL);
         this.raiseInitially = false;
      }
   }
   
  this.add = function(newURL, historyData) {
      var outer = this;
      var addImpl = function() {
      
         if (outer.currentWaitTime > 0)
            outer.currentWaitTime = outer.currentWaitTime - outer.sleepFor;
            
         newURL = outer.extractHashpart(newURL);
         var idCheck = document.getElementById(newURL);
         if (idCheck != undefined || idCheck != null) {
            throw "Anchor exists with the provided key name"; 
         }
         historyStorage.put(newURL, historyData);

         outer.ignoreLocationChange = outer.changeForIE = true;
 
         outer.displayedURL         = window.location.hash = newURL;
         
         if (isIE6plus)
            outer.iframe.src = "history.html?" + newURL;
            
         outer.changeForIE = false;
      };

      window.setTimeout(addImpl, this.currentWaitTime);
   
      this.currentWaitTime = this.currentWaitTime + this.sleepFor;
   }
   
   this.isFirstLoad = function() {
      return this.firstLoad;
   }

   this.getCurrentLocation = function() {
   
   var displayedURL = "";
      if (!isIE6plus)
      {
          var href = window.location.href;
          var index = href.indexOf("#");
          if (index > 0)
          {
            hash = href.substring(index);
            displayedURL = this.extractHashpart(hash);
            
          }
      }
      else
      {
      displayedURL = this.extractHashpart(window.location.hash);
      }
      return displayedURL;
   }
   
   this.displayedURL            = 
   this.listener                = 
   this.changeForIE             =
   this.iframe                  = 
   this.firstLoad               =
   this.ignoreLocationChange    =
   this.raiseInitially          = null;
   this.sleepFor                = 200;
   this.currentWaitTime         = 0
   
   
   this.create = function() {
      var initialHash = this.getCurrentLocation();
      
      this.displayedURL = initialHash;
      
      var pat = /\<.*?\>|\'.*?\'/g;
      
      if(pat.test(initialHash))
      {
            initialHash = XMLEncode(initialHash);
      }
      
      if(unescape(initialHash).length < initialHash.length)
        initialHash = escape(initialHash);
        
      if (isIE6plus) {
         document.write("<iframe style='border: 0px; width: 1px;height: 1px; position: absolute; bottom: 0px; right: 0px; visibility: visible;' name='historyFrame' id='historyFrame' src='history.html?" + initialHash + "'></iframe>");
         this.sleepFor = 400;
      }
      
      window.onunload = function() {
         this.firstLoad = null;
      };
      
      if (!isIE6plus) {
         if (historyStorage.hasKey("historyLoaded") == false) {
            this.ignoreLocationChange = true;
            this.firstLoad = true;
            historyStorage.put("historyLoaded", true);
         }
         else {
            this.ignoreLocationChange = false;
            this.raiseInitially = true;
         }
      }
      else { 
         this.ignoreLocationChange = true;
      }
      
      if (isIE6plus) {
      
            this.iframe = document.getElementById("historyFrame");
      }                                                              
      var outer             = this;
      var locationHandler = function() {
         outer.checkLocation();
      };
      setInterval(locationHandler, 100);
   }
   
   this.raiseFromHistory = function(newHash) {
     var historyData = historyStorage.get(newHash);
      try { 
        this.listener.call(null, newHash, historyData);
        }catch(ex){
            //pending implementation 8/29
        }
   }
   
  this.checkLocation = function() {
      if (!isIE6plus
         && this.ignoreLocationChange) {
         this.ignoreLocationChange = false;
         return;
      }
      
      if (!isIE6plus
          && this.changeForIE) {
         return;
      }
      
      var hash = this.getCurrentLocation();
      
      if (hash == this.displayedURL)
         return;
         

      this.changeForIE = true;
      var historyraised = false;
      if (isIE6plus
          && this.extractHiddenHashpart() != hash) {
         this.iframe.src = "history.html?" + hash;
         historyraised = true;
      }
      else if (isIE6plus) {
         return;
      }
         
      this.displayedURL          = hash;
      this.changeForIE = false;
      if (!historyraised)
      this.raiseFromHistory(hash);
   }

   this.extractHiddenHashpart   = function() {
      var historyFrame  = document.getElementById("historyFrame");
      var doc           = historyFrame.contentWindow.document;
      var hash          = doc.location.search;

      if (hash.length == 1 && hash.charAt(0) == "?")
         hash = "";
      else if (hash.length >= 2 && hash.charAt(0) == "?")
         hash = hash.substring(1); 
      return hash;
   }
   
   this.extractHashpart = function(hashValue) {
      if (hashValue == null || hashValue == undefined)
         return null;
      else if (hashValue == "")
         return "";
      else if (hashValue.length == 1 && hashValue.charAt(0) == "#")
         return "";
      else if (hashValue.length > 1 && hashValue.charAt(0) == "#")
         return hashValue.substring(1);
      else
         return hashValue;     
         
   }
   
   this.loadFromFrame = function(newURL) {
      if (this.ignoreLocationChange == true) {
         this.ignoreLocationChange = false;
         return;
      }
      
      var hash = newURL.search;
            
      if (hash.length == 1 && hash.charAt(0) == "?")
         hash = "";
      else if (hash.length >= 2 && hash.charAt(0) == "?")
         hash = hash.substring(1);
      
      
      if (this.pageLoadEvent != true) {
         window.location.hash = hash;
      }

      this.raiseFromHistory(hash);
   }
} //class History


var historyObj = new History();
//var historyObjGrid = new History();

window.historyStorage = {
  debugging: false,
   
   storageHash: new Object(),
   
   hashLoaded: false, 
   
   put: function(key, value) {
       this.assertValidKey(key);

       if (this.hasKey(key)) {
         this.remove(key);
       }
       
       this.storageHash[key] = value;
       
       this.saveHashTable(); 
   },
   
   get: function(key) {
      this.assertValidKey(key);
      
      this.loadHashTable();
      
      var value = this.storageHash[key];

      if (value == undefined)
         return null;
      else
         return value; 
   },
   
   remove: function(key) {
      this.assertValidKey(key);
      
      this.loadHashTable();
      
      delete this.storageHash[key];
      
      this.saveHashTable();
   },
   
reset: function() {
      this.storageField.value = "";
      this.storageHash = new Object();
   },
   
   hasKey: function(key) {
      this.assertValidKey(key);
      
      this.loadHashTable();
      
      if (typeof this.storageHash[key] == "undefined")
         return false;
      else
         return true;
   },
   
isValidKey: function(key) {
      if (typeof key != "string")
         key = key.toString();
         
      if(unescape(key).length < key.length)
      ;
      else
        key = escape(key);
      var matcher = 
         /^[\"\'\;a-zA-Z0-9_ \-\!\@\#\$\%\^\&\*\(\)\+\=\:\;\,\.\/\?\|\\\~\{\}\[\]]*$/;
                     
      return matcher.test(key);
   },
   
   
   
   
   storageField: null,
   
   init: function() {
      var styleValue = "position: absolute; top: -1000px;";
      if (this.debugging == true) {
         styleValue = "width: 30em; height: 30em;";
      }   
      
      var newContent =
         "<form id='historyStorageForm' " 
               + "method='GET' "
               + "style='" + styleValue + "'>"
            + "<textarea id='historyStorageField' "
                      + "style='" + styleValue + "'"
                              + "left: -1000px;' "
                      + "name='historyStorageField'></textarea>"
         + "</form>";
      document.write(newContent);
      
      this.storageField = document.getElementById("historyStorageField");
   },
   
   assertValidKey: function(key) {
      if (this.isValidKey(key) == false) {
         this.storageField.value = "";
         location.href = "/cui/default.aspx?culture="+getQueryString(location.search,'&',1)["culture"] + "#"//alert('Malformed Request sent from browser, the error and IP has been logged.');
         
       }
   },
   
   loadHashTable: function() {
      if (this.hashLoaded == false) {
         var serializedHashTable = this.storageField.value;
         
         if (serializedHashTable != "" &&
             serializedHashTable != null) {
            this.storageHash = ('(' + serializedHashTable + ')');  
         }
         
         this.hashLoaded = true;
      }
   },
   
    saveHashTable: function() {
      this.loadHashTable();
      
      var serializedHashTable = JSON.stringify(this.storageHash);
      
      this.storageField.value = serializedHashTable;
   }   
};

Array.prototype.______array = '______array';

var JSON = {
    org: 'http://www.JSON.org',
    copyright: '(c)2005 JSON.org',
    license: 'http://www.crockford.com/JSON/license.html',

    stringify: function (arg) {
        var c, i, l, s = '', v;

        switch (typeof arg) {
        case 'object':
            if (arg) {
                if (arg.______array == '______array') {
                    for (i = 0; i < arg.length; ++i) {
                        v = this.stringify(arg[i]);
                        if (s) {
                            s += ',';
                        }
                        s += v;
                    }
                    return '[' + s + ']';
                } else if (typeof arg.toString != 'undefined') {
                    for (i in arg) {
                        v = arg[i];
                        if (typeof v != 'undefined' && typeof v != 'function') {
                            v = this.stringify(v);
                            if (s) {
                                s += ',';
                            }
                            s += this.stringify(i) + ':' + v;
                        }
                    }
                    return '{' + s + '}';
                }
            }
            return 'null';
        case 'number':
            return isFinite(arg) ? String(arg) : 'null';
        case 'string':
            l = arg.length;
            s = '"';
            for (i = 0; i < l; i += 1) {
                c = arg.charAt(i);
                if (c >= ' ') {
                    if (c == '\\' || c == '"') {
                        s += '\\';
                    }
                    s += c;
                } else {
                    switch (c) {
                        case '\b':
                            s += '\\b';
                            break;
                        case '\f':
                            s += '\\f';
                            break;
                        case '\n':
                            s += '\\n';
                            break;
                        case '\r':
                            s += '\\r';
                            break;
                        case '\t':
                            s += '\\t';
                            break;
                        default:
                            c = c.charCodeAt();
                            s += '\\u00' + Math.floor(c / 16).toString(16) +
                                (c % 16).toString(16);
                    }
                }
            }
            return s + '"';
        case 'boolean':
            return String(arg);
        default:
            return 'null';
        }
    },
    parse: function (text) {
        var at = 0;
        var ch = ' ';

        function error(m) {
            throw {
                name: 'JSONError',
                message: m,
                at: at - 1,
                text: text
            };
        }

        function next() {
            ch = text.charAt(at);
            at += 1;
            return ch;
        }

        function white() {
            while (ch != '' && ch <= ' ') {
                next();
            }
        }

        function str() {
            var i, s = '', t, u;

            if (ch == '"') {
outer:          while (next()) {
                    if (ch == '"') {
                        next();
                        return s;
                    } else if (ch == '\\') {
                        switch (next()) {
                        case 'b':
                            s += '\b';
                            break;
                        case 'f':
                            s += '\f';
                            break;
                        case 'n':
                            s += '\n';
                            break;
                        case 'r':
                            s += '\r';
                            break;
                        case 't':
                            s += '\t';
                            break;
                        case 'u':
                            u = 0;
                            for (i = 0; i < 4; i += 1) {
                                t = parseInt(next(), 16);
                                if (!isFinite(t)) {
                                    break outer;
                                }
                                u = u * 16 + t;
                            }
                            s += String.fromCharCode(u);
                            break;
                        default:
                            s += ch;
                        }
                    } else {
                        s += ch;
                    }
                }
            }
            error("Bad string");
        }

        function arr() {
            var a = [];

            if (ch == '[') {
                next();
                white();
                if (ch == ']') {
                    next();
                    return a;
                }
                while (ch) {
                    a.push(val());
                    white();
                    if (ch == ']') {
                        next();
                        return a;
                    } else if (ch != ',') {
                        break;
                    }
                    next();
                    white();
                }
            }
            error("Bad array");
        }

        function obj() {
            var k, o = {};

            if (ch == '{') {
                next();
                white();
                if (ch == '}') {
                    next();
                    return o;
                }
                while (ch) {
                    k = str();
                    white();
                    if (ch != ':') {
                        break;
                    }
                    next();
                    o[k] = val();
                    white();
                    if (ch == '}') {
                        next();
                        return o;
                    } else if (ch != ',') {
                        break;
                    }
                    next();
                    white();
                }
            }
            error("Bad object");
        }

        function num() {
            var n = '', v;
            if (ch == '-') {
                n = '-';
                next();
            }
            while (ch >= '0' && ch <= '9') {
                n += ch;
                next();
            }
            if (ch == '.') {
                n += '.';
                while (next() && ch >= '0' && ch <= '9') {
                    n += ch;
                }
            }
            if (ch == 'e' || ch == 'E') {
                n += 'e';
                next();
                if (ch == '-' || ch == '+') {
                    n += ch;
                    next();
                }
                while (ch >= '0' && ch <= '9') {
                    n += ch;
                    next();
                }
            }
            v = +n;
            if (!isFinite(v)) {
                error("Bad number");
            } else {
                return v;
            }
        }

        function word() {
            switch (ch) {
                case 't':
                    if (next() == 'r' && next() == 'u' && next() == 'e') {
                        next();
                        return true;
                    }
                    break;
                case 'f':
                    if (next() == 'a' && next() == 'l' && next() == 's' &&
                            next() == 'e') {
                        next();
                        return false;
                    }
                    break;
                case 'n':
                    if (next() == 'u' && next() == 'l' && next() == 'l') {
                        next();
                        return null;
                    }
                    break;
            }
            error("Syntax error");
        }

        function val() {
            white();
            switch (ch) {
                case '{':
                    return obj();
                case '[':
                    return arr();
                case '"':
                    return str();
                case '-':
                    return num();
                default:
                    return ch >= '0' && ch <= '9' ? num() : word();
            }
        }

        return val();
    }
};



/** Initialize all of our objects now. */
window.historyStorage.init();
window.historyObj.create();
//window.historyObjGrid.create();
