/**
 * yui is necessary
 */
History = {}

History.factory = function() {
    var ua = navigator.userAgent.toLowerCase(),
        isOpera = (ua.indexOf('opera') > -1),
        isSafari = (ua.indexOf('safari') > -1),
        isGecko = (!isOpera && !isSafari && ua.indexOf('gecko') > -1),
        isIE = (!isOpera && ua.indexOf('msie') > -1);   

    if (isIE) {
        return new History.browser.IE();
    } else if (isSafari) {
        return new History.browser.Safari();
    } else {
        return new History.browser.Gecko();
    }
}

History.browser = {}
History.browser.Common = Class.create();

/**
 * Template  for History
 */
History.browser.Common.prototype = {
    initialize: function() {
        this.addrs = new Array();
        this.currentHash = undefined;
    //    this.vars = new Array();
        this.count = 0;
        this.params = {}
        this.delimiter = '#';
//        this._default = '_default';
        this._default = '';
    },
    
    /**
     * start listening by setInterval
     */
    init: function() {
        this.currentHash = location.hash;        
        var elms = $$('.history');
//        var elms = this.getElementsByClassName('history');
        for (var i=0; i<elms.length; i++) {
            elms[i].onclick= function(){
                var hash = this.href;
    			hash = hash.replace(/^[^#]*#/, '');
    			History.address.load(hash);
            }
            
        }
 	    History.address.load(this.currentHash.replace(/^[^#]*#/, ''));
        setInterval(History.address.check, 100);
    },
    check: function() {
//        if (History.address._default) {
            History.address.callDefault();
//        }
//        if (location.hash != this.currentHash) {
        if (location.hash && location.hash != History.address.currentHash) {
//alert('check : '+ this.currentHash +" / "+ location.hash)
            this.currentHash = location.hash;
            History.address.load(location.hash.replace(/^[^#]*#/, ''));

        }
    },
    load: function(hash, noExec) {
        if (!hash) {
            return false;
        }
       location.hash = "#"+hash;
       this.currentHash = "#"+hash;
//       location.hash = hash;
//       this.currentHash = hash;

//alert(this.currentHash);        
       /**
        * check
        */       
//	   hash = hash.replace(/^.*#/, '');
       hash = this.trim(hash);
       if(!noExec && this.addrs && this.addrs[hash]) {
//           return this.addrs[hash].callbackfunc.apply(this.addrs[hash].callbackobj, this.addrs[hash].args);
            return this._doCallback(hash);
       }
    },
    _doCallback: function(hash){
       if (this.addrs && this.addrs[hash]) {
//       alert(this.addrs[hash].callbackfunc);

//            this.addrs[hash].callbackfunc.apply(this.addrs[hash].callbackobj, this.addrs[hash].args);
            return this.addrs[hash].callbackfunc.apply(this.addrs[hash].callbackobj, this.addrs[hash].args);
       }        
    },
    
    callDefault: function() {
//        var dom = YAHOO.util.Dom.get('result');
//        if (dom) {
////            dom.innerHTML = location.hash;
//        }
        if (!location.hash || location.hash == '#') {
          History.address.load(History.address._default);
//            location.hash = History.address._default;
        }
    },

    /**
     * @param string address (set hash for permalink)
     * @param mix callback function or object
     * @param string callback function
     * @param mix arguments
     */
    setAddress: function(){
    	if(arguments.length == 0) return;
    	var _args = new Array();
    	var _obj = new Object();
    	for(i=0; i<arguments.length; i++){
    		_args.push(arguments[i])
    	}
    	var hash = _args.shift();
    	var callback = _args.shift();
        if (typeof callback == 'function') {
        	_obj.callbackfunc = callback;
        	_obj.callbackobj = null;
        	_obj.args = _args;
//            alert(callback.call(obj));
            //this.addrs[hash] = function(){return callback.call(obj);}
        } else if(typeof callback == 'object'){
			var _callbackfunc = _args.shift();
        	_obj.callbackfunc = callback[_callbackfunc];
        	_obj.callbackobj = callback;
        	_obj.args = _args;
        }
        this.addrs[hash] = _obj;
    },
    
    /**
     * if hash = # this method will be called
     */
    setDefault: function() {
        this._default = arguments[0];
        var _args = arguments;
        this.setAddress.apply(this, _args);
    },
    
    /**
     * replace "&" and following charactors
     */
    trim: function(hash) {
        hash = hash.replace(/\&.+$/, "");
        hash = hash.replace(/^#/, "");
//        alert("hash is "+hash);
        return hash;
    },

    /**
     * set vars from hash
     * #hoge=1&fuga=2&piyo=3 => 
     * History.address.vars['hoge'] = 1;
     * History.address.vars['fuga'] = 2;
     * History.address.vars['piyo'] = 3;
     */    
    getVars: function(hash) {
        var hash = hash || this.currentHash;
//        if (!this.currentHash.match('^[^&]+&(.+)$')) {
        if (!hash || typeof hash == 'undefined' || !hash.match('^[^&]+&(.+)$')) {
            return {};
        }
        var vals = RegExp.$1.split('&');
        for (var i=0; i<vals.length; i++) {
             if (!vals[i].match(/^([^=]+)=(.+)$/)) {
                 continue;
             }
             
             var name = RegExp.$1, val = RegExp.$2;

            val = decodeURIComponent(val);
             if (val.match(/^[0-9]+$/)) {
                 val = parseInt(val, 10);
             }
//             alert(RegExp.$2)
             this.params[name] = val;
//             alert(RegExp.$1);
//              alert("this.vars['" + RegExp.$1 + "'] = " + RegExp.$2 + ";");
//             eval("this.vars['" + RegExp.$1 + "'] = " + RegExp.$2 + ";");
        }
        return this.params;
//        return this.vars;
    },

    /**
     * @param string name variable name
     * @param mixed val variable values
     */
    setParam: function(nameOfVar, val) {
        this.params[nameOfVar] = val;
    },

    /**
     * @param string name variable name
     */
    getParam: function(nameOfVar) {
        return this.params[nameOfVar];
    },
    
    setParams: function(vals) {
        this.params = vals;
    },
    
    serializeVars: function(newHash) {
        this._log_hash = newHash;
        var hash = new Array();
//        alert(this.params.toSource())
//        info('serializeVars', this.params.toSource())
        this.params.forEach(function(value,key,self){
            if (value) {
                // ??? 07/03/05
                value = encodeURIComponent(value);
                hash.push(key + '=' + value);
            }
        });
        
//        for (key in this.params) {
//            if (!this.params[key]) {
//                continue;
//            }
//            hash.push(key + '=' + this.params[key]);
//        }
        var hash = hash.join('&');
        newHash = newHash || this.trim(this.currentHash);
        hash = newHash + "&" + hash;
        this._log_hash_all = hash;
        location.hash = this.delimiter + hash;
//        alert(location.hash)
//        return 
    }
    
}

History.browser.Gecko = Class.create();
History.browser.Gecko.prototype = {
    initialize: function() {
        this.name='Gecko';
    }
}
History.browser.IE = Class.create();
History.browser.Safari = Class.create();


Object.extend(History.browser.Gecko.prototype, History.browser.Common.prototype);
Object.extend(History.browser.IE.prototype, History.browser.Common.prototype);
Object.extend(History.browser.Safari.prototype, History.browser.Common.prototype);

History.browser.IE.prototype.initialize =  function() {
    History.browser.Common.prototype.initialize.call(this);
    this.name='IE';
    this.iframeDummyURL = '/js/History/dummy.html';
}

History.browser.IE.prototype.init = function() {
//	var div = document.createElement('div');
	
	//ie warn if src is null
//	div.innerHTML='<iframe src="/?scid='+this.iframeDummyURL+'" id="jQuery_history" style="display: none;"></iframe>';
//	document.body.appendChild(div);
    new Insertion.Top(document.body, '<iframe src="/?scid='+this.iframeDummyURL+'" id="jQuery_history" style="display: none;"></iframe>');

    var history = $('jQuery_history');
	var iframe = history.contentWindow.document;

	iframe.open();
	iframe.close();
	iframe.location.hash = location.hash;
    History.browser.Common.prototype.init.call(this);
}

/**
 *  we must make a distinction "back" and "next"
 */
History.browser.IE.prototype.check = function() {
//alert(history.length)
    History.address.callDefault();
    var his = $('jQuery_history');
	var iframe = his.contentDocument || his.contentWindow.document;
	var current_hash = iframe.location.hash;
	
	History.address.currentHash = location.hash


	if(current_hash != History.address.currentHash && current_hash != '#') {
        var hash = History.address.trim(current_hash);
        History.address.load(current_hash);
	}
}
History.browser.IE.prototype.load = function(hash, noExec) {
    hash = hash.replace(/^#/, '');
    if (!hash) {
        return;
    }
    
//    var val = History.browser.IE.superclass.load.call(this, hash);
//    var val = History.browser.Common.prototype.load.call(this, hash);
    var his = $('jQuery_history');
	var iframe = his.contentWindow.document;
	iframe.open();
	iframe.close();
	iframe.location.hash = "#"+hash;
	location.hash = "#"+hash;
//	alert(history)
	History.address.currentHash = "#"+hash;

//    alert([hash, noExec]);
    hash = History.address.trim(hash);
//    alert(History.address.addrs[hash]);
    if(!noExec && History.address.addrs && History.address.addrs[hash]) {
//alert(History.address.getParam('a'))
        return History.address._doCallback(hash);
    }

//    alert(hash)
//    return val;
}

//History.browser.IE.prototype.callDefault = function() {
//    if (!location.hash || location.hash == '#') {
//        location.hash = "#step2";
//    }
//}

History.browser.IE.prototype.serializeVars = function(newHash) {
//    History.browser.IE.superclass.serializeVars.call(this, newHash);
//alert(location.hash)
//    var hash = this.trim(location.hash);
    History.browser.Common.prototype.serializeVars.call(this, newHash);
	hash = location.hash.replace(/^[^#]*#/, '');
	History.address.load(hash);
}

History.browser.Safari.prototype.initialize = function() {
    History.browser.Common.prototype.initialize.call(this);
    this.name='Safari';
    this.delimiter = '';
}


History.browser.Safari.prototype.init = function() {
    this.currentHistory = history.length;

    this.historyArray = new Array();
    this.historyArray[history.length] = location.hash;
//	alert(this.historyArray[this.currentHistory]);
    History.browser.Common.prototype.init.call(this);

}


History.browser.Safari.prototype.check = function() {
    History.address.callDefault();
    if (location.hash != History.address.historyArray[History.address.currentHistory]) {
//alert(121)

        History.address.historyArray[History.address.currentHistory] = location.hash;
        var  hash = History.address.trim(location.hash);
//            alert(hash);
        return History.address._doCallback(hash);

        return;
    }

    if (History.address.currentHistory != history.length) {
//alert(122)
        History.address.currentHistory = history.length;
        if (typeof History.address.historyArray[History.address.currentHistory] == "undefined") {
            History.address.historyArray[History.address.currentHistory] = location.hash;
//            var  hash = History.address.trim(location.hash);
//            alert(hash);
//            return History.address._doCallback(hash);
            
        } else {
//alert(123)
            var hash = History.address.historyArray[History.address.currentHistory];
            History.address.load(hash.replace(/^[^#]*#*/, ''), false);
        
            return;
        }
    }
    return;
}
History.browser.Safari.prototype.load = function(hash, noExec, reRegister) {
    //docmentgetElementById('result').innerHTML = 'hioge';
       hash = hash.replace(/^%23/, '');
       if (!hash) {
           return;
       }
       if (reRegister) {
            History.address.currentHistory = history.length;
            History.address.historyArray[History.address.currentHistory] = "#" + hash
//       History.address.currentHash = hash;
return;
       }
       
       if (location.hash != "#" + hash && location.hash) {
//alert(location.hash +" / "+ hash)
         location.hash = hash;
       }
       History.address.currentHash = hash;


       if (!noExec) {
       hash = History.address.trim(hash);
            return History.address._doCallback(hash);
       }
}

History.address = History.factory();

