/*

	Lepton/JS - Client Side Library for Lepton

	Licensed under the Gnu Public License (GPL) v2 or later.

	(c) 2009, labs.noccy.com
	(c) 2008-2009, Christopher Vagnetoft

	For more info see http://labs.noccy.com

*/

var lepton = {
	version:'0.1'
};

/******************************************************************************
 *
 *   lepton.image
 *
 ******************************************************************************/

lepton.Image = {
	preload:function(src) {
		if (!(this._images)) this._images = [];
		var i = new Image();
		i.src = src;
		this._images.push(i);
	}
};

/******************************************************************************
 *
 *   lepton.data
 *
 ******************************************************************************/

lepton.data = {};

/**
 * LeptonJS DataSet: Provides an abstract API to handle, request, and
 * manipulate data. Initialize the dataset with a provider
 *
 *  var oDS = new lepton.data.Dataset();
 *  oDS.load(new lepton.data.XHRDataProvider('/foo/bar'),{
 *		onSuccess:function(ds) { dosomethinghere }
 *  });
 *
 *
 *
 *
 */
lepton.data.Dataset = Class.create({
	initialize:function(oDataProvider) {
		if (oDataProvider) this.load(oDataProvider);
	},
	load:function(oDataProvider,oArguments) {
		this._provider = oDataProvider;
		this._arguments = oArguments;
		this._provider.bindDataset(this);
		this._provider.fetch(this.onDataAvailableHandler.bind(this));
	},
	onDataAvailableHandler:function() {
		// When this method is called, we should have the data available in
		// this._providerso we go ahead and call on the appropriate callback
		this._arguments.onSuccess(this);
	}
});

/**
 *
 *
 */
lepton.data.GenericProvider = Class.create({
	bindDataset:function(oDataset) {
		this._dataset = oDataset;
	},
	update:function() { },
	getDataObject:function() { }
});

/**
 *
 *
 */
lepton.data.JSONDataProvider = Class.create(lepton.data.GenericProvider,{
	initialize:function(sURL) {
		this._url = sURL;
	},
	fetch:function(fCallback) {
		this._callback = fCallback;
		// TODO: Do the magic here, and then call on this._dataset.onDataAvailable()
	}
});

/**
 *
 *
 */
lepton.data.CSVDataProvider = Class.create(lepton.data.GenericProvider,{
	initialize:function(sURL) {
		this._url = sURL;
	},
	fetch:function(fCallback) {
		this._callback = fCallback;
		// TODO: Do the magic here, and then call on this._dataset.onDataAvailable()
	}
});

/**
 *
 *
 */
lepton.data.TableDataProvider = Class.create(lepton.data.GenericProvider,{
	initialize:function(oElem) {
		this._elem = oElem;
	},
	fetch:function(fCallback) {
		this._callback = fCallback;
		// TODO: Do the magic here, and then call on this._dataset.onDataAvailable()
	}
});


/******************************************************************************
 *
 *   lepton.forms
 *
 ******************************************************************************/

lepton.forms = {};

/**
 * FormValidation is used to validate a form, and to enable/disable the submit
 * button based on the forms state.
 */
lepton.forms.FormValidation = Class.create({
	initialize:function(opts) {
		this._opts = opts || [];
		this._validators = [];
	},
	addValidator:function(validator) {
		validator.bindForm(this);
		this._validators.push(validator);
	},
	hasValidated:function() {
		var valid = 0;
		for (var n = 0; n < this._validators.length; n++) {
			if (this._validators[n].isValid()) valid++;
		}
		if (valid == this._validators.length) {
			if (this._opts.onValid) this._opts.onValid();
		} else {
			if (this._opts.onInvalid) this._opts.onInvalid();
		}
	}
});

/**
 * This is the template for a validator
 *
 */
lepton.forms.GenericValidator = Class.create({
	initialize:function(elem,opts) {
		this._elem = $(elem) || null;
		if (this._options.validateOnBlur) this._elem.observe('blur',this.validate.bindAsEventListener(this));
		if (this._options.validateOnChange) this._elem.observe('keyup',this.validate.bindAsEventListener(this));
		this._valid = this.validate();
	},
    /**
     * Returns true if the value is valid, or false if the value is invalid
     * @returns (boolean) True if valid
     */
    isValid:function() {
        return(this._valid);
    },
	validate:function() {
		alert('I am validator');
	},
	bindForm:function(f) {
		this._form = f;
	}
});

/**
 *
 *
 */
lepton.forms.StringValidator = Class.create(lepton.forms.GenericValidator,{
	initialize:function($super,elem,opts) {
        this._options = Object.extend({
            required: false,
            minLength: null,
            maxLength: null,
			match: '',
            validateOnBlur: true,
            validateOnChange: false
        },opts);
		$super(elem,opts);
	},
	validate:function() {
		var f = this._elem.value;
		var v = true;
		if (f == '') {
			if (this._options.required) v = false;
		} else {
			if ((this._options.minLength != null) && (f.length < this._options.minLength)) v = false;
		}
		this._valid = v;
		if (this._form) this._form.hasValidated();
		return;
	}
});

/**
 * Numeric validator, validates a field according to numeric rules.
 *
 */
lepton.forms.NumericValidator = Class.create(lepton.forms.GenericValidator,{
	initialize:function($super,elem,opts) {
        // Initialize defaults here
        this._options = Object.extend({
            allowNegative: true,
            required: false,
            minValue: null,
            maxValue: null,
            validateOnBlur: true,
            validateOnChange: false
        },opts);
		$super(elem,opts);
	}
});

/**
 * Ajax validator, performs validation by calling on a server side method
 *
 */
lepton.forms.AjaxValidator = Class.create(lepton.forms.GenericValidator,{
    initialize:function($super,elem,opts) {
        this._options = Object.extend({
			validateOnBlur: true,
			validateOnChange: false,
			url: ''
        },opts);
        $super(elem,opts);
    },
	validate:function() {
		var params = {};
		params[this._options.param] = this._elem.value;
		new Ajax.Request(this._options.url,{
			method:'get',
			parameters:params,
			onSuccess:this._validateCallback.bind(this)
		});
	},
	_validateCallback:function(t) {
		var r = t.responseText.evalJSON(true);
		this._valid = (r[this._options.check]);
		if (this._form) this._form.hasValidated();
	}
});

lepton.forms.InlineUpload = Class.create({
	initialize:function(oForm, oArguments) {

	}
});

lepton.forms.Editor = Class.create({
	initialize:function(el,opts) {
		this._el = $(el);
		this._opts = opts;
	},
	insert:function(before,after) {
		if (document.selection) {
			this._el.focus();
			var sr = document.selection.createRange();
			sr.text = before + sr.text + after;
		}
		else if (this._el.selectionStart || this._el.selectionStart == '0') {
			var startPos = this._el.selectionStart;
			var endPos = this._el.selectionEnd;
			this._el.value = this._el.value.substring(0, startPos)
				+ before
				+ this._el.value.substring(startPos, endPos)
				+ after
				+ this._el.value.substring(endPos, this._el.value.length);
		} else {
			this._el.value += before + after;
		}
		this._el.focus();
	}

});


/******************************************************************************
 *
 *   lepton.ui
 *
 ******************************************************************************/

lepton.ui = {};

/**
 *
 *
 *
 */
lepton.ui.Table = Class.create({
	initialize:function(elem,oArguments) {

    }
});

lepton.ui.Tooltip = Class.create({
	initialize:function(elem,opts) {
        this._options = Object.extend({
            opacity: '0.9',
            backgroundColor: '#FFFFE0',
			border: 'solid 1px #404040',
			font: '8pt sans-serif',
			zIndex: '1999',
			padding: '2px',
			textColor: '#101010'
        },opts);
		this._el = new Element('div');
		this._el.setStyle({
			position:'absolute',
			left:'0px',
			top:'0px',
			display:'none',
			padding: this._options.padding,
			opacity: this._options.opacity,
			backgroundColor: this._options.backgroundColor,
			border: this._options.border,
			font: this._options.font,
			color: this._options.textColor,
			zIndex:this._options.zIndex
		});
		this._el.update( this._options.text );
		document.body.appendChild(this._el);
		if (this._options.bind) {
			$(this._options.bind).observe('mouseover', function() { this._el.show(); });
			$(this._options.bind).observe('mouseout', function() { this._el.hide(); });
		}
    },
	show:function(elem,text) {
		if (text) this._el.update(text);
		if (elem) {
			var p = $(elem).cumulativeOffset();
			var x = p[0];
			var y = p[1] + $(elem).getHeight() + 5;
			this._el.setStyle({ left:x+'px', top:y+'px' });
		}
		this._el.show();
	},
	hide:function() {
		this._el.hide();
	}
});

lepton.ui.tooltip = {
	show:function(elem,text) {
		if (lepton.ui.tooltip.instance) delete(lepton.ui.tooltip.instance);
		lepton.ui.tooltip.instance = new lepton.ui.Tooltip();
		lepton.ui.tooltip.instance.show(elem,text);
	},
	hide:function() {
		if (lepton.ui.tooltip.instance) {
			lepton.ui.tooltip.instance.hide();
			delete(lepton.ui.tooltip.instance);
		}
	}
};

lepton.ui.Overlay = Class.create({
	initialize:function(opts) {
        this._options = Object.extend({
            opacity: '0.9',
            backgroundColor: '#303030',
			zIndex: '999'
        },opts);
		this.attached = false;
		this.oElem = new Element('div');
		this.oElem.setStyle({
			position:'fixed',
			display:'none',
			left:'0px',
			top:'0px',
			right:'0px',
			bottom:'0px',
			opacity: this._options.opacity,
			backgroundColor: this._options.backgroundColor,
			zIndex:this._options.zIndex
		});
	},
	getElement:function() {
		return this.oElem;
	},
	show:function() {
		if (!this.attached) {
			document.documentElement.appendChild(this.oElem);
			this.attached=true;
		}
		this.oElem.show();
	},
	hide:function() {
		this.oElem.hide();
	}
});

lepton.ui.InlineEditor = Class.create({
	initialize:function(elem,oArguments) {
		this.oElem = $(elem);
		this.args = oArguments || {};
		// hook the element
		this.oElem.observe("click", this._click.bindAsEventListener(this));
	},
	_click:function() {

	}
});

lepton.ui.Dialog = Class.create({
	initialize:function(el,opts) {
		this._el = $(el);
		this._opts = {
			overlay:null
		};
		Object.extend(this._opts, opts);
		this._el.setStyle({
			position:'absolute',
			zIndex:20000
		});
		this._el.addClassName('ljs-ui-dialog');
		this._el.hide();
	},
	show:function() {
		if (this._opts.overlay) this._opts.overlay.show();
		this._el.center();
		this._el.show();
	},
	hide:function() {
		if (this._opts.overlay) this._opts.overlay.hide();
		this._el.hide();
	}
});

lepton.ui.dropmenu = {
	current: null
};

lepton.ui.DropMenu = Class.create({
	initialize:function(el,menu,opts) {
		this._parent = $(el);
		if (!this._parent) { return; }
		this._menu = $(menu);
		this._opts = opts;
		this._menu.setStyle({
			'position':'absolute',
			'display':'none'
		});
		this._parent.addClassName('expandable');
		Event.observe(this._parent,'mouseover',this.showMenu.bindAsEventListener(this));
		Event.observe(this._parent,'mousemove',this.__cbShow.bindAsEventListener(this));
		Event.observe(this._parent,'mouseout',this.__cbHide.bindAsEventListener(this));
	},
	showMenu:function() {
		if (lepton.ui.dropmenu.current) {
			lepton.ui.dropmenu.current.hideMenu();
			lepton.ui.dropmenu.current = null;
		}
		if (!this._menu) return;
		lepton.ui.dropmenu.current = this;
		this._menu.show();
		this._state = true;
		this._parent.addClassName('expanded');
		var p = this._parent.cumulativeOffset();
		var x = p[0];
		var y = p[1] + this._parent.getHeight();
		this._menu.setStyle({ left:x+'px', top:y+'px' });
		Event.observe(this._menu,'mousemove',this.__cbShow.bindAsEventListener(this));
		Event.observe(this._menu,'mouseout',this.__cbHide.bindAsEventListener(this));
	},
	hideMenu:function() {
		this._menu.hide();
		this._state = false;
		lepton.ui.dropmenu.current = null;
		this._parent.removeClassName('expanded');
		if (this._htimer) clearTimeout(this._htimer);
	},
	__refreshTimer:function() {
		if (this._htimer) clearTimeout(this._htimer);
		this._htimer = setTimeout(this.__invokeTimer.bindAsEventListener(this),100);
	},
	__invokeTimer:function() {
		if (this._state == false) this.hideMenu();
	},
	__cbHide:function() { this._state = false; this.__refreshTimer(); },
	__cbShow:function() { this._state = true; this.__refreshTimer(); }
});

lepton.ui.TabBar = Class.create({
	initialize:function(el,opts) {
		this._parent = el;
		this._el = new Element('div');
		$(this._el).addClassName('ljs-ui-tabbar');
		$(el).appendChild(this._el);
	},
	addButton:function(btn) {
		btn.attach(this._el);
	},
	setActive:function(btnid) {
		var e = $(this._el).childNodes;
		for(var n = 0; n < e.length; n++) {
			var el = e[n];
			if (el.nodeName == 'A') {
				if (el.id == btnid) {
					$(el).addClassName('ljs-current');
				} else {
					$(el).removeClassName('ljs-current');
				}
			}
		}
	}
});

lepton.ui.Accordion = Class.create({
	initialize:function(el,opts) {
		this._el = $(el);
		this._pages = [];
		var e = this._el.childNodes;
		var i = 0;
		for(var n = 0; n < e.length; n++) {
			var te = e[n];
			if (te.nodeName == 'DIV') {
				te.addClassName('ljs-accordion-hidden');
				te.addClassName('ljs-accordion');
				this._pages[i++] = te;
			}
		}
		this.showPage(0);
	},
	showPage:function(index) {
		for(var n = 0; n < this._pages.length; n++) {
			if (n==index) {
				this._pages[n].addClassName('ljs-accordion-visible');
				this._pages[n].removeClassName('ljs-accordion-hidden');
			} else {
				this._pages[n].addClassName('ljs-accordion-hidden');
				this._pages[n].removeClassName('ljs-accordion-visible');
			}
		}
	}
});

lepton.ui.ToolBar = Class.create({

});

lepton.ui.Button = Class.create({
	initialize:function(opts,cb) {
		this._el = new Element('a');
		if (opts.id) $(this._el).id = opts.id;
		if (opts.hash) $(this._el).href = '#' + opts.hash;
		$(this._el).addClassName('ljs-ui-button');
		$(this._el).setStyle({
			backgroundImage:'url(' + opts.icon +')'
		});
		$(this._el).observe('click', cb);
	},
	attach:function(parentel) {
		parentel.appendChild(this._el);
	}
})

/******************************************************************************
 *
 *   lepton.ui.bluebox
 *
 ******************************************************************************/

/**
 * This is the BlueBox namespace. Use the setup() method to hook all elements
 * with the specified class name and turn them into links by creating a new
 * instance of the bluebox.Image class wrapping it.
 *
 * TODO: Make the code respect the tagname - This should only convert A-tags
 * into clickable thingies.
 *
 * @namespace lepton.ui.bluebox
 *
 */
lepton.ui.bluebox = {
	setup:function(cn,opts) {
		var els = document.getElementsByClassName(cn);
		for (var i = 0; i < els.length; i++) {
			new lepton.ui.bluebox.Image(els[i],opts);
		}
	}
};


/**
 * The bluebox Image manager. The constructor here hooks the click event for
 * the anchor, and replaces it with a call to its own showBox() method.
 *
 * @namespace lepton.ui.bluebox
 * @class Image
 *
 */
lepton.ui.bluebox.Image = Class.create({
	initialize:function(el,opts) {
		this._el = $(el);
		this._src = $(el).getAttribute('href');
		this._opts = {
			overlayColor:'#FFFFFF',
			overlayOpacity:0.9
		};
		Object.extend(this._opts, opts);
		$(el).observe('click', this.showBox.bindAsEventListener(this));
	},
	showBox:function(e) {
		this._ol = new lepton.ui.Overlay({
			backgroundColor:this._opts.overlayColor,
			opacity:this._opts.overlayOpacity
		});
		this._ol.show();
		this._pel = new Element('img', { src:this._src } );
		document.documentElement.appendChild(this._pel);
		$(this._pel).setStyle({
			zIndex:99999,
			border:'solid 3px #101010',
			position:'absolute',
			cursor:'pointer'
		});
		$(this._pel).center();
		$(this._pel).observe('click', this.hideBox.bindAsEventListener(this));
		Event.stop(e);
		return false;
	},
	hideBox:function() {
		this._ol.hide();
		delete this._ol;
		document.documentElement.removeChild(this._pel);
		this._pel.hide();
		delete this._pel;
	}
});



/******************************************************************************
 *
 *   lepton.canvas
 *
 ******************************************************************************/

lepton.canvas = {};
lepton.canvas.Color = Class.create({
	initialize:function(r,g,b,a) {
		this._r = r;
		this._g = g;
		this._b = b;
		this._a = a;
	},
	getRGB:function() {
		return 'rgb('+this._r+','+this._g+','+this._b+')';
	},
	getRGBA:function() {
		return 'rgba('+this._r+','+this._g+','+this._b+','+this._a+')';
	}
});

lepton.Canvas = Class.create({
	initialize:function(el) {
		this._cx = $(el).getContext('2d');
	},
	drawFilledRect:function(x1,y1,x2,y2,bc,fc) {
		this._cx.fillStyle = fc;
		this._cx.lineStyle = bc;
		this._cx.fillRect(x1,y1,x2,y2);
	}
});



/******************************************************************************
 *
 *   lepton.charting
 *
 ******************************************************************************/

lepton.charting = {
    // Chart type constants
    CHART_TYPE_BAR: 1,
    CHART_TYPE_LINE: 2,
    CHART_TYPE_PIE: 3
};

lepton.charting.Chart = Class.create({ });

lepton.charting.ChartProvider = Class.create({
    initialize:function() {

    },
    setChartType:function(eType) {
        this._type = eType;
    },
    setTitle:function(title) {
        this._title = title;
    }
});

lepton.charting.JsCharts = Class.create(lepton.charting.ChartProvider, {
    initialize:function($super,oArgs) {
        $super(oArgs);
    }
});


/******************************************************************************
 *
 *   lepton.animation
 *
 ******************************************************************************/

lepton.effects = {};

/**
 * Effect superclass.
 *
 */
lepton.effects.Effect = Class.create({
    initialize:function(oOpts) {
        this._elem = $(oOpts.elem);
        var dim = this._elem.getDimensions();
        this._width = dim.width;
        this._height = dim.height;
    },
    setOpacity:function(opacity) {
        this._elem.setOpacity(opacity);
    }
});

/**
 * Fade an element in or out
 *
 * oOpts:   element (element) The element to fade
 *          duration (number) The duration of the effect
 *          onComplete (function) The onComplete hook
 *          onBegin (function) The onBegin hook
 */
lepton.effects.FadeIn = Class.create(lepton.effects.Effect,{
    initialize:function($super,oOpts) {

    }
});



/******************************************************************************
 *
 *   lepton.element
 *
 ******************************************************************************/

lepton.Element = {
    center:function(element) {

        try{
            element = $(element);
        }catch(e){
            return;
        }

        var my_width  = 0;
        var my_height = 0;

        if ( typeof( window.innerWidth ) == 'number' ){
            my_width  = window.innerWidth;
            my_height = window.innerHeight;
        } else if ( document.documentElement &&
                 ( document.documentElement.clientWidth ||
                   document.documentElement.clientHeight ) ){
            my_width  = document.documentElement.clientWidth;
            my_height = document.documentElement.clientHeight;
        } else if ( document.body &&
                ( document.body.clientWidth || document.body.clientHeight ) ){
            my_width  = document.body.clientWidth;
            my_height = document.body.clientHeight;
        }

        try {
            element.style.position = 'absolute';
            // element.style.zIndex   = 90;
        } catch(e) { }

        var scrollY = 0;

        if ( document.documentElement && document.documentElement.scrollTop ){
            scrollY = document.documentElement.scrollTop;
        } else if ( document.body && document.body.scrollTop ){
            scrollY = document.body.scrollTop;
        } else if ( window.pageYOffset ){
            scrollY = window.pageYOffset;
        } else if ( window.scrollY ){
            scrollY = window.scrollY;
        }

        var elementDimensions = Element.getDimensions(element);

        var setX = ( my_width  - elementDimensions.width  ) / 2;
        var setY = ( my_height - elementDimensions.height ) / 2 + scrollY;

        setX = ( setX < 0 ) ? 0 : setX;
        setY = ( setY < 0 ) ? 0 : setY;

        element.style.left = setX + "px";
        element.style.top  = setY + "px";

        element.style.display  = 'block';

    },
	loadPage:function(element,url) {
		new Ajax.Updater(element, url, { method:'get' });
	},
	elastic:function(element,maxHeight) {
		this.maxHeight = maxHeight;
		$(element).observe('keyup',function() {
			var text = $(element);
			if ( !text ) return;
			var adjustedHeight = text.clientHeight;
			if ( !this.maxHeight || this.maxHeight > adjustedHeight ) {
				adjustedHeight = Math.max(text.scrollHeight, adjustedHeight);
				if ( this.maxHeight )
					adjustedHeight = Math.min(this.maxHeight, adjustedHeight);
				if ( adjustedHeight > text.clientHeight )
					text.style.height = (adjustedHeight + 5) + "px";
			}
		});
		var baseHeight = text.clientHeight;
		text.style.height = (baseHeight + 5) + "px";
	}
}

Element.addMethods(lepton.Element);
