/**
 *	Global functions
 *	Author: Petro Salema
 *	Contact: petro@petrosalema.com
 *	REQUIRES: petrofied_icv.js
 */

 
/* Autocomplete
============================================================ */
var Autocomplete = Class({

	input		: null,
	container	: null,
	num_results	: 5,
	
	_initialize: function ( )
	{
		var input = Util.getElementsByClassName( 'autocomplete' );
		var container = Util.getElementsByClassName( 'autocomplete-results' );
		
		if ( input.length == 0 || container.length == 0 )
			return;
		
		this.input = input[0];
		this.container = container[0];
		
		Util.addEvent( this.input, 'keyup', this.update.bind( this, this.input ) );
		Util.addEvent( document, 'mouseup', this.hideResults.bindWithEvent( this ) );
	},
	
	update: function ( input )
	{
		var q = input.value
			.replace( /[\\]/, '' ).trim()
			.replace( '&', '%26' )
			.replace( '#', '%23' ); // TODO: fix brackers errors
		if ( q.length < 2 )
			this.hideResults();
		else
			var r = Ajax.Request( "/scripts/autocomplete.php?q=" + q + '&l=' + this.num_results, this.showResults.bind( this ), true );
	},
	
	showResults: function ( data )
	{
		this.container.innerHTML = data || "";
	},
	
	hideResults: function ( e )
	{
		if ( !e )
			this.container.innerHTML = "";
		else if ( !Util.getSrc( e, 'a' ) )
			this.container.innerHTML = "";
	}
	
}); // -------------------- End of Autocomplete Class --------------------


/* Calendar Class
============================================================ */
var Calendar = Class({

	isIE		: false,
	canvas		: null,
	cal			: null,
	date_boxs	: null,
	arrow_btns	: null,
	close_btns	: null,
	pagination	: null,
	
	_initialize: function ( calendar )
	{
		this.isIE   = Util.isIE();
		this.canvas = calendar;
		this.loadMonth();
	},
	
	load: function ( )
	{
		this.cal = Util.getElementsByClassName( 'cal', this.canvas, 'table' )[0];
		this.loadEvents();
	},
	
	loadEvents: function ( )
	{
		var a = this.arrow_boxes = Util.getElementsByClassName( 'cal_arr', this.cal, 'a' );
		var d = this.date_boxes  = Util.getElementsByClassName( 'eventful', this.cal, 'a' );
		var b = this.close_btns  = Util.getElementsByClassName( 'cal_event_box_close_btn', this.cal, 'a' );
		var p = this.pagination  = Util.getElementsByClassName( 'cal_pagination', this.canvas, 'a' );
		
		for ( var i = 0, j = d.length; i < j; i++ )
		{
			Util.addEvent( d[i], 'mousedown', this.expandDate.bindWithEvent( this ) );
			Util.addEvent( b[i], 'mousedown', this.collapseDate.bindWithEvent( this ) );
		}
		
		for ( var i = 0, j = p.length; i < j; i++ )
		{
			var pp = p[i];
			var ref = pp.getAttribute( 'href' ).match( /#(.*?)$/ );
			pp.setAttribute( 'href', "javascript:;" );
			Util.addEvent( pp, 'mousedown', this.loadMonth.bindWithEvent( this, ref[1] ) );
		}
		
		for ( var i = 0, j = a.length; i < j; i++ )
		{
			var aa = a[i];
			var ref = ( ( aa.getAttribute( 'href' ).match( /#(.*?)$/ ) )[1] == 'up_events' ) ? 1 : -1;
			aa.setAttribute( 'href', "javascript:;" );
			Util.addEvent( aa, 'mousedown', this.scrollEvents.bindWithEvent( this, ref ) );
		}
	},
	
	unloadEvents: function ( )
	{/*	Sometimes this function is called before events are registered so make sure
		to check if events exist before attempting to remove ie !d !b !p etc...		*/
		
		var d = this.date_boxes;
		var a = this.arrow_boxes;
		var b = this.close_btns;
		var p = this.pagination;
		
		if ( !d || !b ) return;
		for ( var i = 0, j = d.length; i < j; i++ )
		{
			Util.removeEvent( d[i], 'mousedown', this.expandDate.bindWithEvent( this ) );
			Util.removeEvent( b[i], 'mousedown', this.collapseDate.bindWithEvent( this ) );
		}
		
		if ( !p ) return;
		for  ( var i = 0, j = p.length; i < j; i++ )
			Util.addEvent( p[i], 'mousedown', this.loadMonth.bindWithEvent( this ) );
		
		if ( !a ) return;
		for  ( var i = 0, j = a.length; i < j; i++ )
			Util.addEvent( a[i], 'mousedown', this.scrollEvents.bindWithEvent( this ) );
	},
	
	expandDate: function ( e )
	{
		var p = Util.getSrc( e, 'a' ).parentNode;
		var d = Util.getElementsByClassName( 'cal_event_box', p )[0];
		
		p.className += " cal_date_focus";
		
		var win_width = this.isIE ? document.body.offsetWidth : window.innerWidth;
		var win_scroll = this.isIE ? document.documentElement.scrollLeft : window.pageXOffset;
		var px = Util.globalOffset( p ).l;
		var pw = p.offsetWidth;
		var dw = d.offsetWidth;
		
		d.style.left = ( px - win_scroll + dw > win_width ) ?  ( 0 - dw + pw + 4 ) + "px" : "";
		
		d.getElementsByTagName( 'ul' )[0].style.top = "0px";
	},
	
	collapseDate: function ( e )
	{
		var src = Util.getParent(( e.target || window.event.srcElement ), {
			'className': new RegExp( '(^|\\s)cal_date_focus(\\s|$)', 'g' )
		});
		Util.removeClass( src, 'cal_date_focus' );
	},
	
	scrollEvents: function ( e, d )
	{
		var src = Util.getParent(( e.target || window.event.srcElement ), {
			'className': new RegExp( '(^|\\s )cal_event_box_content( \\s|$)', 'g' )
		});
		var ul = src.getElementsByTagName( 'ul' )[0];
		var lih = ul.getElementsByTagName( 'li' )[0].offsetHeight;
		var ulh = ul.offsetHeight;
		var ult = ul.offsetTop;
		var s = lih * d;
		
		if ( s + ult > 0 || ulh + ult + s + lih < ul.parentNode.offsetHeight )
			return;
		
		ul.style.top = ( ult + s ) + "px";
	},
	
	loadMonth: function ( e, q )
	{
		this.unloadEvents();
		var r = "/scripts/calendar.php?q=" + ( q || "" ) + "&t=" + Math.round( ( new Date() ).getTime() / 1000 );
		var request = Ajax.Request( r, this.printMonth.bind( this ), false );
	},
	
	printMonth: function ( payload )
	{
		this.canvas.innerHTML = payload;
		this.load();
	}
	
}); // -------------------- End of Calendar Class --------------------


/* Drawer Class
============================================================ */
var Drawer = Class({

	drawer		: null,
	drawers		: [],
	anim_queu	: [],
	timer		: null,
	delay_timer	: null,
	
	_initialize: function ( drawer )
	{
		if ( !drawer ) return;
		this.drawer = drawer;
		var handles = Util.getElementsByClassName( 'drawer_handle', drawer );
		this.drawers = [];
		this.anim_queue = [];
		
		for ( var i = 0, j = handles.length; i < j; i++ )
		{
			var h = handles[i];
			var p = h.parentNode;
			var height_max = p.offsetHeight;
			var height_min = h.offsetHeight;
			var is_first = ( i == 0 );
			
			p.style.height = ( is_first ? height_max : height_min ) + "px";
			
			this.drawers[i] = { box:p, open:is_first, min:height_min, max:height_max };
		}
		
		Util.addEvent( drawer, 'mouseover', this.mouseOver.bindWithEvent( this ) );
	},
	
	mouseOver: function ( e )
	{
		var src = Util.getSrc( e, 'li' );
		
		// Delay trigger
		this.resetTimer( this.delay_timer );
		this.delay_timer = setTimeout( this.trigger.bind( this, this.drawers.indexOf( src, 'box' ) ), 100 );
	},
	
	trigger: function ( drawer_index )
	{
		// clear delay_trigger
		this.resetTimer( this.delay_timer );
		
		var ds = this.drawers;
		var a = this.anim_queu;
		var drawer = ds[drawer_index];
		
		// If this drawer is already open the don't do anything
		if ( drawer.open ) return;
		
		// Stop any current animation and clear anim_queu
		this.resetTimer();
		a.splice( 0, a.length );
		
		// Add all open drawers into anim_queu to be closed
		for ( var i = 0, j = ds.length; i < j; i++ )
		{
			var d = ds[i];
			if ( d.open )
				a.push({ drawer:d, target:d.min });
		}
		
		// Add drawer to the anim_queu to be opened
		a.push({ drawer:drawer, target:drawer.max });
		
		// Assign it "open" status
		drawer.open = true;
		
		// Start animation
		this.timer = setInterval( this.resize.bind( this ), 10 );
	},
	
	resize: function ( )
	{
		var q = this.anim_queu;
		
		// If nothing to animate then stop
		if ( q.length == 0 ) this.resetTimer();
		
		for ( var i = 0, j = q.length; i < j; i++ )
		{
			var a = q[i];
			
			if ( !a ) continue;
			
			var b = a.drawer.box;
			var h = b.offsetHeight;
			var d = a.target - h;
			d *= 0.7;
			
			if ( Math.abs( d ) <= 2 ) {
				b.style.height = a.target + "px";
				a.drawer.open = ( a.target == a.drawer.max );
				q.splice( i, 1 );
			} else
				b.style.height = ( h + d ) + "px";
		}
	},
	
	resetTimer: function ( timer )
	{
		var t = timer || this.timer;
		if ( t ) {
			clearInterval( t );
			if ( timer ) timer = null;
			else this.timer = null;
		}
	}
	
}); // -------------------- End of Drawer Class --------------------


/* Menu Class
============================================================ */
var Menu = Class({

	menuClassName: "dropdownmenu",
	menu: null,
	menuId: null,
	activeBranch: null,
	hideDelay: 250,
	timers: [],
	
	_initialize: function ( menuId )
	{
		this.menuId = menuId;
		this.menu = document.getElementById( menuId );
		
		var items = Util.getElementsByClassName( this.menuClassName, this.menu );
		
		for ( var i = 0, j = items.length; i < j; i++ )
		{
			Util.addEvent( items[i], 'mouseover', this.onmouseover.bindWithEvent( this ) );
			Util.addEvent( items[i], 'mouseout', this.onmouseout.bindWithEvent( this ) );
		}
		
		Util.addEvent( this.menu, 'mouseover', this.movedWithinMenu.bind( this ) );
	},
	
	movedWithinMenu: function( )
	{
		this.clearTimers( );
	},
	
	onmouseover: function ( e )
	{
		var li = Util.getSrc( e, 'li' );
		
		// Unhightlight, and hide previously highlit menu item
		var h = Util.getElementsByClassName( 'highlighted', li.parentNode );
		
		for ( var i = 0, j = h.length; i < j; i++ ) {
			if ( h[i] ) {
				this.hideBranch( h[i] );
				Util.removeClass( h[i], 'highlighted' );
				h[i].getElementsByTagName( 'a' )[0].style.color = "";
			}
		}
		
		// Hightlight new menu item
		if ( li.parentNode.id != this.menuId ) {
			Util.addClass( li, "highlighted" );
			li.getElementsByTagName( 'a' )[0].style.color = "#fa4";
		}
		
		// Open up its submenu if it has one
		var children = li.getElementsByTagName( 'ul' );
		if ( children.length > 0 )
			this.showMenu( children[0] );
	},
	
	onmouseout: function ( e )
	{
		// If we don't have a hidMenu event in the pipeline, then add one
		if ( this.timers.length < 1 ) {
			var timerId = ( new Date() ).getTime();
			this.timers.push({
					'id': timerId,
					'timer': setTimeout( this.hideMenu.bind( this, timerId ), this.hideDelay )
				});
		}
	},
	
	showMenu: function ( menu )
	{
		// Get the root menu of which the current menu is a child of
		var newActiveBranch = Util.hasClass( menu, 'roots' )
			? menu
			: Util.getParent( menu, {'className': /roots/} );
		
		// If the activeBranch is the same then lets not hide it
		if ( newActiveBranch != this.activeBranch )
			this.hideMenu();
		
		this.activeBranch = newActiveBranch;
		
		menu.style.display = "block";
	},
	
	hideMenu: function ( timerId )
	{
		/*
			var a = this.menu.getElementsByTagName( 'a' );
			for ( var i = 0, j = a.length; i < j; i++ )
				a[i].style.color = "";
		*/
		
		if ( this.activeBranch ) {
			this.hideBranch ( this.activeBranch );
			this.activeBranch.style.display = "none";
			Util.removeClass( this.activeBranch.parentNode, 'highlighted' );
		}
		this.clearTimers( timerId );
	},
	
	hideBranch: function ( branch )
	{
		var trunks = branch.getElementsByTagName( 'ul' );
		for ( var i = trunks.length - 1; i >= 0; i-- ) {
			Util.removeClass( trunks[i].parentNode, 'highlighted' );
			trunks[i].style.display = "none";
			trunks[i].parentNode.getElementsByTagName( 'a' )[0].style.color = "";
		}
	},
	
	clearTimers: function ( timerId )
	{
		for ( var i = 0, j = this.timers.length; i < j; i++ )
		{
			if ( this.timers[i] )
				if ( this.timers[i].id == timerId || !timerId ) {
					clearTimeout( this.timers[i].timer );
					this.timers[i].timer = null;
					this.timers.splice( i, 1 );
				}
		}
	}

});


function submitForm ( )
{
	var form = document.getElementById( 'contactForm' );
	
	// Make input safe
	form.name.value = form.name.value.strip().stripTags( );
	form.subject.value = form.subject.value.strip().stripTags();
	form.message.value = form.message.value.strip().stripTags();
	
	// Validate form
	var form_elements = [
		[form.name, '', true, 'Please include your name'],
		[form.email, /^( [\w-]+( ?:\.[\w-]+ )* )@( ( ?:[\w-]+\. )*\w[\w-]{0,66})\.( [a-z]{2,6}( ?:\.[a-z]{2})? )$/i, false, 'Please provide a valid email address'],
		[form.subject, '', true, 'Please provide a subject'],
		[form.message,  '', true, 'Please write something in the message box']
	];
	
	Validator.reset( form_elements );
	var noErrors = Validator.validate( form_elements );
	
	var error = '1px #f45 solid';
	
	if ( !noErrors ) {
		document.getElementById( 'error_msg' ).style.display = 'block';
		document.location = '#contact_form';
	} else
		form.submit();
}

var Validator = {

	reset: function( elements )
	{
		var e = elements;

		for ( var i=0; i<e.length; i++ )
		{
			if ( e[i][0].value.indexOf( ' ' ) > -1 )
				e[i][0].value = e[i][0].value.replace( /^\s+|\s+$/g, '' );
			e[i][0].style.border = '1px #dedede solid';
		}
		
		var error_box = document.getElementById( 'error_msg' );
		error_box.style.display = 'none';
		error_box.innerHTML = '';
	},
	
	validate: function( elements )
	{
		var noErrors = true;
		var e = elements;
		
		for ( var i=0; i<e.length; i++ )
		{
			if ( !Validator.test( e[i][0], e[i][1], e[i][2], e[i][3] ) )
				var noErrors = false;
		}
		
		return noErrors;
	},
	
	test: function( element, test, flag, msg )
	{
		var error_box = document.getElementById( 'error_msg' );
		var result = false;
		
		if ( typeof( test ) == 'string' )
			if ( element.value == test ) result = true;
		else
			result = test.test( element.value );
		
		if ( result == flag ) {
			element.style.border = '1px #f45 solid';
			error_box.innerHTML += '&nbsp;&#8226;&nbsp;' + msg + '<br />';
			return false;
		}
		
		return true;
	}
	
}

function init ( )
{ /* Run onload initializations */ // TODO MAKE THIS WORK

	var o;
	
	/* dropdown menu */
	var mainmenu = new Menu( 'topMenu' );
	
	/* drawers */
	var dE = Util.getElementsByClassName( 'drawer', document, 'ul' );
	var drawers = [];
	while ( o = dE.shift() )
		drawers.push( new Drawer( o ) );
	
	/* calenders */
	var cE = Util.getElementsByClassName( 'calendar', document );
	var calendars = [];
	while ( o = cE.shift() )
		calendars.push( new Calendar( o ) );
	
	/* autocomplete */
	var ac = new Autocomplete();
}