/**
   Copyright (c) 2005, Brad Neuberg, bkn3@columbia.edu
   http://codinginparadise.org
*/

/** An object that provides DHTML history, history data, and bookmarking
    for AJAX applications. */
//document.domain="alice.it";
window.dhtmlHistory = {
   initialize: function() {
      if (this.isInternetExplorer() == false) {
         return;
      }

      // if this is the first time this page has loaded...
      if (historyStorage.hasKey("DhtmlHistory_pageLoaded") == false) {
         this.fireOnNewListener = false;
         this.firstLoad = true;
         historyStorage.put("DhtmlHistory_pageLoaded", true);
      }
      // else if this is a fake onload event
      else {
         this.fireOnNewListener = true;
         this.firstLoad = false;
      }
   },

   /** Adds a history change listener. Note that
       only one listener is supported at this
       time. */
   addListener: function(callback) {
      this.listener = callback;

      if (this.fireOnNewListener == true) {
         this.fireHistoryEvent(this.currentLocation);
         this.fireOnNewListener = false;
      }
   },

   add: function(newLocation, historyData) {
      var self = this;
      var addImpl = function() {
         // indicate that the current wait time is now less
         if (self.currentWaitTime > 0)
            self.currentWaitTime = self.currentWaitTime - self.WAIT_TIME;

         // remove any leading hash symbols on newLocation
         newLocation = self.removeHash(newLocation);

         var idCheck = document.getElementById(newLocation);
         if (idCheck != undefined || idCheck != null) {
            var message =
               "Exception: History locations can not have "
               + "the same value as _any_ id's "
               + "that might be in the document, "
               + "due to a bug in Internet "
               + "Explorer; please ask the "
               + "developer to choose a history "
               + "location that does not match "
               + "any HTML id's in this "
               + "document. The following ID "
               + "is already taken and can not "
               + "be a location: "
               + newLocation;

            throw message;
         }

         // store the history data into history storage
         historyStorage.put(newLocation, historyData);

         // indicate to the browser to ignore this upcomming
         // location change
         self.ignoreLocationChange = true;

         // indicate to IE that this is an atomic location change
         // block
         this.ieAtomicLocationChange = true;

         // save this as our current location
         self.currentLocation = newLocation;

         // change the browser location
         window.location.hash = newLocation;

         // change the hidden iframe's location if on IE
         if (self.isInternetExplorer())
		 {
            //VALE: inserisco path assoluto
			//self.iframe.src = "blank.html?" + newLocation;
			self.iframe.src = "/common/ajaxCommenti/blank.html?" + newLocation;
		 }

         // end of atomic location change block
         // for IE
         this.ieAtomicLocationChange = false;
      };

      // now execute this add request after waiting a certain amount of time, so as to
      // queue up requests
      window.setTimeout(addImpl, this.currentWaitTime);

      // indicate that the next request will have to wait for awhile
      this.currentWaitTime = this.currentWaitTime + this.WAIT_TIME;
   },

   isFirstLoad: function() {
      if (this.firstLoad == true) {
         return true;
      }
      else {
         return false;
      }
   },

   isInternational: function() {
      return false;
   },

   getVersion: function() {
      return "0.05";
   },

   /** Gets the current hash value that is in the browser's
       location bar, removing leading # symbols if they are present. */
   getCurrentLocation: function() {
      var currentLocation = this.removeHash(window.location.hash);

      return currentLocation;
   },





   /** Our current hash location, without the "#" symbol. */
   currentLocation: null,

   /** Our history change listener. */
   listener: null,

   /** A hidden IFrame we use in Internet Explorer to detect history
       changes. */
   iframe: null,

   /** Indicates to the browser whether to ignore location changes. */
   ignoreLocationChange: null,

   /** The amount of time in milliseconds that we should wait between add requests.
       Firefox is okay with 200 ms, but Internet Explorer needs 400. */
   WAIT_TIME: 200,

   /** The amount of time in milliseconds an add request has to wait in line before being
       run on a window.setTimeout. */
   currentWaitTime: 0,

   /** A flag that indicates that we should fire a history change event
       when we are ready. */
   fireOnNewListener: null,

   /** A variable that indicates whether this is the first time
       this page has been loaded.*/
   firstLoad: null,

   /** A variable to handle an important edge case in Internet
       Explorer. */
   ieAtomicLocationChange: null,

   /** Creates the DHTML history infrastructure. */
   create: function() {
      // get our initial location
      var initialHash = this.getCurrentLocation();

      // save this as our current location
      this.currentLocation = initialHash;

      // write out a hidden iframe for IE and
      // set the amount of time to wait between add() requests
      if (this.isInternetExplorer()) {
         //VALE: inserisco path assoluto
		 document.write("<iframe style='border: 0px; width: 1px; "
                               + "height: 1px; position: absolute; bottom: 0px; "
                               + "right: 0px; visibility: visible;' "
                               + "name='DhtmlHistoryFrame' id='DhtmlHistoryFrame' "
                               + "src='/common/ajaxCommenti/blank.html?" + initialHash + "'>"
                               + "</iframe>");
         // wait 400 milliseconds between history
         // updates on IE, versus 200 on Firefox
         this.WAIT_TIME = 400;
      }

      var self = this;
      window.onunload = function() {
         self.firstLoad = null;
      };

      if (this.isInternetExplorer() == false) {
         if (historyStorage.hasKey("DhtmlHistory_pageLoaded") == false) {
            this.ignoreLocationChange = true;
            this.firstLoad = true;
            historyStorage.put("DhtmlHistory_pageLoaded", true);
         }
         else {
            // indicate that we want to pay attention
            // to this location change
            this.ignoreLocationChange = false;
            this.fireOnNewListener = true;
         }
      }
      else { // Internet Explorer
         // the iframe will get loaded on page
         // load, and we want to ignore this fact
         this.ignoreLocationChange = true;
      }

      if (this.isInternetExplorer()) {
            this.iframe = document.getElementById("DhtmlHistoryFrame");
      }

      var self = this;
      var locationHandler = function() {
         self.checkLocation();
      };
      setInterval(locationHandler, 100);
   },

   /** Notify the listener of new history changes. */
   fireHistoryEvent: function(newHash) {
      // extract the value from our history storage for
      // this hash
      var historyData = historyStorage.get(newHash);

      // call our listener
      this.listener.call(null, newHash, historyData);
   },

   /** Sees if the browsers has changed location. */
   checkLocation: function() {
      // ignore any location changes that we made ourselves
      // for browsers other than Internet Explorer
      if (this.isInternetExplorer() == false
         && this.ignoreLocationChange == true) {
         this.ignoreLocationChange = false;
         return;
      }

      // if we are dealing with Internet Explorer
      // and we are in the middle of making a location
      // change from an iframe, ignore it
      if (this.isInternetExplorer() == false
          && this.ieAtomicLocationChange == true) {
         return;
      }

      // get hash location
      var hash = this.getCurrentLocation();

      // see if there has been a change
      if (hash == this.currentLocation)
         return;

      this.ieAtomicLocationChange = true;

      if (this.isInternetExplorer()
          && this.getIFrameHash() != hash) {
		 //VALE: inserisco path assoluto
         this.iframe.src = "/common/ajaxCommenti/blank.html?" + hash;
      }
      else if (this.isInternetExplorer()) {
         // the iframe is unchanged
         return;
      }

      // save this new location
      this.currentLocation = hash;

      this.ieAtomicLocationChange = false;

      // notify listeners of the change
      this.fireHistoryEvent(hash);
   },

   /** Gets the current location of the hidden IFrames
       that is stored as history. For Internet Explorer. */
   getIFrameHash: function() {
      // get the new location
      var historyFrame = document.getElementById("DhtmlHistoryFrame");
      var doc = historyFrame.contentWindow.document;
      var hash = new String(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;
   },

   /** Removes any leading hash that might be on a location. */
   removeHash: 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;
   },

   /** For IE, says when the hidden iframe has finished loading. */
   iframeLoaded: function(newLocation) {
      // ignore any location changes that we made ourselves
      if (this.ignoreLocationChange == true) {
         this.ignoreLocationChange = false;
         return;
      }

      // get the new location
      var hash = new String(newLocation.search);
      if (hash.length == 1 && hash.charAt(0) == "?")
         hash = "";
      else if (hash.length >= 2 && hash.charAt(0) == "?")
         hash = hash.substring(1);

      // move to this location in the browser location bar
      // if we are not dealing with a page load event
      if (this.pageLoadEvent != true) {
         window.location.hash = hash;
      }

      // notify listeners of the change
      this.fireHistoryEvent(hash);
   },

   /** Determines if this is Internet Explorer. */
   isInternetExplorer: function() {
      var userAgent = navigator.userAgent.toLowerCase();
      if (document.all && userAgent.indexOf('msie')!=-1) {
         return true;
      }
      else {
         return false;
      }
   }
};












/** An object that uses a hidden form to store history state
    across page loads. */
window.historyStorage = {
   /** If true, we are debugging and show the storage textfield. */
   debugging: false,

   /** Our hash of key name/values. */
   storageHash: new Object(),

   /** If true, we have loaded our hash table out of the storage form. */
   hashLoaded: false,

   put: function(key, value) {
       this.assertValidKey(key);

       // if we already have a value for this,
       // remove the value before adding the
       // new one
       if (this.hasKey(key)) {
         this.remove(key);
       }

       // store this new key
       this.storageHash[key] = value;

       // save and serialize the hashtable into the form
       this.saveHashTable();
   },

   get: function(key) {
      this.assertValidKey(key);

      // make sure the hash table has been loaded
      // from the form
      this.loadHashTable();

      var value = this.storageHash[key];

      if (value == undefined)
         return null;
      else
         return value;
   },

   remove: function(key) {
      this.assertValidKey(key);

      // make sure the hash table has been loaded
      // from the form
      this.loadHashTable();

      // delete the value
      delete this.storageHash[key];

      // serialize and save the hash table into the
      // form
      this.saveHashTable();
   },

   /** Clears out all saved data. */
   reset: function() {
      this.storageField.value = "";
      this.storageHash = new Object();
   },

   hasKey: function(key) {
      this.assertValidKey(key);

      // make sure the hash table has been loaded
      // from the form
      this.loadHashTable();

      if (typeof this.storageHash[key] == "undefined")
         return false;
      else
         return true;
   },

   /** Determines whether the key given is valid;
       keys can only have letters, numbers, the dash,
       underscore, spaces, or one of the
       following characters:
       !@#$%^&*()+=:;,./?|\~{}[] */
   isValidKey: function(key) {
      // allow all strings, since we don't use XML serialization
      // format anymore
      return (typeof key == "string");
   },




   /** A reference to our textarea field. */
   storageField: null,

   init: function() {
      // write a hidden form into the page
      var styleValue = "position: absolute; top: -1000px; left: -1000px; visible: hidden;";

      if (this.debugging == true) {
         styleValue = "width: 30em; height: 30em;";
      }


      var newContent =
         "<div id='historyContainer'><form id='historyStorageForm' "
               + "method='GET' "
               + "style='" + styleValue + "'>"
            + "<textarea id='historyStorageField' "
                      + "style='" + styleValue + "'"
                              + "left: -1000px;' "
                      + "name='historyStorageField'></textarea>"
         + "</form></div>";
      document.write(newContent);

      this.storageField = document.getElementById("historyStorageField");
      if (this.debugging == false)
      {
        this.historyStorageForm = document.getElementById("historyContainer");
        this.historyStorageForm.style.visibility="hidden";
      }
   },

   /** Asserts that a key is valid, throwing
       an exception if it is not. */
   assertValidKey: function(key) {
      if (this.isValidKey(key) == false) {
         throw "Please provide a valid key for "
               + "window.historyStorage, key= "
               + key;
       }
   },

   /** Loads the hash table up from the form. */
   loadHashTable: function() {
      if (this.hashLoaded == false) {
         // get the hash table as a serialized
         // string
         var serializedHashTable = this.storageField.value;

         if (serializedHashTable != "" &&
             serializedHashTable != null) {
            // destringify the content back into a
            // real JavaScript object
            this.storageHash = eval('(' + serializedHashTable + ')');
         }

         this.hashLoaded = true;
      }
   },

   /** Saves the hash table into the form. */
   saveHashTable: function() {
      this.loadHashTable();

      // serialized the hash table
      var serializedHashTable = JSON.stringify(this.storageHash);

      // save this value

      this.storageField.value = serializedHashTable;
   }
};

/** The JSON class is copyright 2005 JSON.org. */
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.dhtmlHistory.create();