(function(){
    var storage = {
        storage: {},
        store: function(key, value){
            this.storage[key] = value;
        },
        retrieve: function(key){
            return this.storage[key] || null;
        }
    };
    
    Class.Singleton = function(){
        this.$className = String.uniqueID();
    };
    
    Class.Singleton.prototype.check = function(item){
        if (!item) item = storage;
        var instance = item.retrieve('single:' + this.$className);
        if (!instance) item.store('single:' + this.$className, this);
        return instance;
    };
    var gIO = function(klass){
        var name = klass.prototype.$className;
        return name ? this.retrieve('single:' + name) : null;
    };
    if (('Element' in this) && Element.implement) Element.implement({getInstanceOf: gIO});
    Class.getInstanceOf = gIO.bind(storage);
}).call(this);


Class.Instantiate = function(klass, options){
    var create = function(object){
        new klass(object, options);
    };
    return function(objects){
        objects.each(create);
    };
};

Class.Binds = new Class({
    $bound: {},
    bound: function(name){
        return this.$bound[name] ? this.$bound[name] : this.$bound[name] = this[name].bind(this);
    }
});

/*
---

name: Form.Placeholder

description: Provides a fallback for the placeholder property on input elements for older browsers.

authors: Christoph Pojer (@cpojer)

license: MIT-style license.

requires: [Core/Class.Extras, Core/Element, Core/Element.Event, Core/Element.Style, Class-Extras/Class.Binds, Class-Extras/Class.Singleton]

provides: Form.Placeholder

...
*/

(function(){

if (!this.Form) this.Form = {};

var supportsPlaceholder = ('placeholder' in document.createElement('input'));
if (!('supportsPlaceholder' in this) && this.supportsPlaceholder !== false && supportsPlaceholder) return;

var wrapSet = function(set, self){
	return function(key, value){
		if (key == 'value' && !value){
			self.reset();
			return this;
		}

		return set.apply(this, arguments);
	};
};

var wrapGet = function(get, self){
	return function(key){
		if (key == 'value' && !self.hasValue())
			return '';

		return get.apply(this, arguments);
	};
};

this.Form.Placeholder = new Class({

	Implements: [Class.Singleton, Class.Binds, Options],

	options: {
		color: '#BBB'
	},

	initialize: function(element, options){
		this.setOptions(options);
		element = this.element = document.id(element);

		return this.check(element) || this.setup();
	},

	setup: function(){
		var element = this.element;
		
		this.defaultValue = element.get('placeholder') || element.value;
		this.color = element.getStyle('color');

		//element.erase('placeholder');
		element.set = wrapSet(element.set, this);
		element.get = wrapGet(element.get, this);
		
		this.attach();
		
		element.getParent('form').addEvent('submit', this.clear.bind(this));

		if (!this.hasValue()) this.reset();
	},

	attach: function(){
		this.element.addEvents({
			focus: this.bound('focus'),
			blur: this.bound('blur')
		});
		
		return this;
	},

	detach: function(){
		this.element.removeEvents({
			focus: this.bound('focus'),
			blur: this.bound('blur')
		});

		return this;
	},

	clear: function(){
		var element = this.element;
		element.setStyle('color', this.color);
		if (element.value == this.defaultValue) element.value = '';
		
		return this;
	},

	reset: function(){
		this.element.setStyle('color', this.options.color).value = this.defaultValue;

		return this;
	},
	
	focus: function(){
		this.clear();
	},
	
	blur: function(){
		if (!this.element.value) this.reset();
	},

	hasValue: function(){
		var value = this.element.value;
		return (value && value != this.defaultValue);
	}

});

})();

