Object.extend(Event, {
  _domReady : function() {
    if (arguments.callee.done) return;
    arguments.callee.done = true;

    if (this._timer)  clearInterval(this._timer);
    
    this._readyCallbacks.each(function(f) { f() });
    this._readyCallbacks = null;
},
  onDOMReady : function(f) {
    if (!this._readyCallbacks) {
      var domReady = this._domReady.bind(this);
      
      if (document.addEventListener)
        document.addEventListener("DOMContentLoaded", domReady, false);
        
        /*@cc_on @*/
        /*@if (@_win32)
            document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
            document.getElementById("__ie_onload").onreadystatechange = function() {
                if (this.readyState == "complete") domReady(); 
            };
        /*@end @*/
        
        if (/WebKit/i.test(navigator.userAgent)) { 
          this._timer = setInterval(function() {
            if (/loaded|complete/.test(document.readyState)) domReady(); 
          }, 10);
        }
        
        Event.observe(window, 'load', domReady);
        Event._readyCallbacks =  [];
    }
    Event._readyCallbacks.push(f);
  }
});

// Author: Siegfried Puchbauer <rails-spinoffs@lists.rubyonrails.org>
Ajax.History = Class.create({
  initialize: function(options) {
	this.options = Object.extend({
	  currentHash: '',
	  interval: 200,
	  iframeSrc: '/blank.html',
	  urlTemplate: '#{hash}'
	}, options || {});
	this.callback = this.options.callback || Prototype.emtpyFunction;

	if (!Prototype.Browser.IE) this.locator = new Ajax.History.Hash();
	else this.locator = new Ajax.History.Iframe('ajaxHistoryHandler', this.options.iframeSrc);

	this.currentHash = '';
	if (this.options.currentHash) this.add(this.options.currentHash);

	this.locked = false;
  },
  hashStorage : {},
  add: function(hash) {
	this.locked = true;
	clearTimeout(this.timer);

	var hashMD5 = hex_md5( ( typeof( hash ) == 'object' ? $H( hash ).toQueryString() : hash ) );
	this.hashStorage[ hashMD5 ] = hash;
	this.currentHash = hashMD5;
	this.locator.setHash(hashMD5);
	this.timer = setTimeout(this.checkHash.bind(this), this.options.interval);
	this.locked = false;
  },
  checkHash: function() {
	if (!this.locked) {
	  var check = this.locator.getHash();

	  if (check != this.currentHash) {
		var myhash = new Template(this.options.urlTemplate).evaluate({hash: check});
		if (check) this.callback( this.hashStorage[ myhash ] );
		this.currentHash = check;
	  }
	}
	this.timer = setTimeout(this.checkHash.bind(this), this.options.interval);
  },
  getBookmark: function() {
	return this.locator.getBookmark();
  }
});

// Hash Handler for IE (Tested with IE6)
Ajax.History.Iframe = Class.create({
  initialize: function(id, src) {
	this.url = '';
	this.id = id || 'ajaxHistoryHandler';
	this.src = src || '';
	document.write('<iframe src="'+this.src+'" id="'+this.id+'" name="'+this.id+'" style="display: none;" ></iframe>');
  },
  setHash: function(hash) {
	try {
	  $(this.id).setAttribute('src', this.src + '?' + hash);
	} catch(e) {}
	window.location.href = this.url + '#' + hash;
  },
  getHash: function() {
	try {
	  return (document.frames[this.id].location.href||'?').split('?')[1];
	} catch(e) { return ''; }
  },
  getBookmark: function() {
	try {
	  return window.location.href.split('#')[1]||'';
	} catch(e) { return ''; }
  }
});

// Hash Handler for a modern browser (tested with firefox 1.5)
Ajax.History.Hash = Class.create({
  initialize: function() {
	//
  },
  setHash: function(hash) {
	window.location.hash = hash;
  },
  getHash: function() {
	return window.location.hash.substring(1)||'';
  },
  getBookmark: function() {
	try {
	  return window.location.hash.substring(1)||'';
	} catch(e) { return ''; }
  }
});
