// XXX - fix fore firefox 
var icon_reloaded = false;
function reloadIcon(){
    $$('link').each(function(link){
        if(link.rel=="shortcut icon")
            var href=link.get("href");
            link.clone().inject(link,'before');
//            link.destroy();
    });
}


var Converter = new Class({
    initialize: function(defaultValue){
	this.defaultValue = this.fromCode(defaultValue);
    },
    fromCode: function(value){
	return value;
    },
    fromHash: function(value){
	if(value==false)
	    return this.defaultValue;
	return value;
    },   
    toHash: function(value){
	if(value==this.defaultValue)
	    return false;
	return value;
    }    
});
var CSTR = new Class({Extends: Converter});

var CCASE = new Class({
    Extends: Converter,
    initialize: function(defaultValue, cases){
        this.cases = cases;
        this.parent(defaultValue);
    },
    fromCode: function(value){
	if(this.cases.indexOf(value)==-1){
	    return this.defaultValue ? this.defaultValue : this.cases[0];
	}
	return value
    },
    fromHash: function(value){
    	if(this.cases.indexOf(value)==-1){
	    return this.defaultValue;
	}
	return value;
    },   
    toHash: function(value){
	if(value==this.defaultValue)
	    return false;
	return value;
    }    
});

var CINT = new Class({
    Extends: Converter,
    fromCode: function(value){
	return parseInt(value);
    },
    fromHash: function(value){
	value = parseInt(value);
	if(isNaN(value))
	    return this.defaultValue;
	return value;
    }
});

var CFLOAT = new Class({
    Extends: Converter,
    initialize: function(defaultValue, len){
	this.len = len;
	this.parent(defaultValue);
    },
    fromCode: function(value){
	return parseFloat(value).toFixed(this.len);
    },
    fromHash: function(value){
	value = parseFloat(value).toFixed(this.len);
	if(isNaN(value))
	    return this.defaultValue;
	return value;
    }
});

var HashController = new Class({
    initialize: function(){
	this.params = $H();
	this.oldParams = $H();
	this.converters = $H();
	this.handlers = [];
	this.timeout = 2000;
	this.initHash = this.hash = "";//this.getHash();
    },
    getHash: function(){
	return window.location.hash;
    },
    pollHash: function(){
	var hash = this.getHash();
	if(hash==this.hash) return;
	this.hash = hash;
	this.oldParams = this.params;
	this.params = this.getConvertedHashParams();
	var changed = [];
	this.params.each(function(value, key){
	    if(this.oldParams.get(key) != value)
		changed.push(key);
	}, this);
	if(!changed.length) return;
	this.executeHandlers(changed);
	this.updateHash();
    },
    getConvertedHashParams: function(){
	var ret = new Hash();
	var params = this.getHashParams();
	this.params.each(function(value, key){
	    ret.set(key, this.converters.get(key).fromHash(params.get(key)));
	},this);
	return ret
    },
    getHashParams: function(){
	var hash = window.location.hash;
	var params =  hash.substr(1, hash.length).split('&');
	var ret = $H();
	params.each(function(value, index){
	    var pair = params[index].split('=');
    	    if(pair.length!=2)
    		return;
	    ret.set(pair[0], pair[1]);
	})
	return ret;
    },
    updateHash: function(){
	var params = $H();
	this.params.each(function(value, key){
	    var value = this.converters.get(key).toHash(value);
	    if(value!=false) params.set(key, value);
	}, this);
	this.setHash(params);
    },
    setHash: function(params){
	var hash = "#";
	var flag = 0;
	params.each(function(value, key){
	    if(flag){
		hash+="&";
	    }else{
		flag=1;
	    }
	    hash+=(key+"="+value)
	})
	window.location.hash = hash;
        if(!icon_reloaded){
            reloadIcon();
            icon_reloaded = true;
        }
    },
    addParam: function(key, converter){
	this.converters.set(key, converter);
	this.params.set(key, converter.defaultValue);
    },
    addHandler: function(handler, bind){
	this.handlers.push([handler, bind]);
    },
    executeHandlers: function(changed){
	if(!changed){
	    var changed = [];
	}
	this.handlers.each(function(value, index){
	    value[0].run([changed, this.params, this.oldParams], value[1]);
	}, this);
    },
    setParam: function(key, value, execHandlers){
	this.setParams($H({key:value}), execHandlers);
    },
    setParams: function(params, execHandlers){
	params.each(function(value, key, hash){
	    hash.set(key, this.converters.get(key).fromCode(value));
	}, this);
	var curParams = this.params;
	curParams.extend(params);
	if(!execHandlers){ 
	    this.oldParams = this.params;
	    this.params = curParams;
	}
	this.updateHash();
    },    
    run: function(init){
	if(init){
	    this.pollHash();
	}
	this.pollHash.periodical(this.timeout, this);
    }
});

var hashController;
window.addEvent('domready', function() {
    hashController = new HashController()
});

