
function ws_ajax( p ) {
	this.name = p.name;
	this.data = p.data;
	this.config = p.config;
	this.ds = p.ds;
	this.url = p.url;
	this.$el = p.el;
	this.template = p.template;
	this.context_menu = p.context_menu;
	
	this.title_create = p.title_create;
	this.title_edit = p.title_edit;
	this.title_add = p.title_add;
	
	this.display = function( id ) {
		var _this = this;
		var id;
		var values = this.data[id];
		var html = this.template;
	
		html = ws_key_replace( values , html );
		console.log(html);
		
		var $html = $(html).attr('wsaxid',id);
		
		if( this.context_menu ) {
			$html.contextMenu(
					{ menu: this.context_menu} ,
			        function(action, el, pos) {
				        if( action == 'edit' ) {
							_this.edit( $(el).attr('wsaxid') );
						}
				        if( action == 'delete' ) {
							var id = $(el).attr('wsid');
							if( confirm('Really delete '+users[id].name+'?' ) ) {
								_this.remove( $(el).attr('wsaxid') );
							}
						}
				    }
				);
		}
		
		if( $('[wsaxid='+id+']').length ) {
			$('[wsaxid='+id+']').replaceWith( $html );
		} else {
			this.$el.append( $html );
		}
		
	}
	
	this.display_all = function() {
		
		for( var e in this.data ) {
		
			this.display( e );
		
		}
		
	}
	
	this.create = function() {
		var _this = this;
		var cb = function( values ){ 
					var values;
					$.post( _this.url+'&ax_ds='+_this.ds+'&ax_a=create' , values , function(data){
							if( data ) {
								var v = ws_first(data);
								_this.data[v.id] = v;
								_this.display(v.id);
							}
						},
						'json'
					);
				};
		var params = omerge( this.config , { title: this.title_create, callback: cb} );
		ws_ask(params);
		
	}
	
	this.edit = function( id ) {
		var _this = this;
		var values = this.data[id];
		var cb = function( values ){ 
					var values;
					$.post( _this.url+'&ax_ds='+_this.ds+'&ax_a=edit' , values , function(data){
							if( data ) {
								var v = ws_first(data);
								_this.data[v.id] = v;
								_this.display(v.id);
							}
						},
						'json'
					);
				};
		var params = omerge( this.config , { values: values, title: this.title_edit, callback: cb} );
		ws_ask(params);
		
	}
	
	this.remove = function( id ) {
	}
	
}

// check to remote error from server
function ws_ajax_error( data ) {
	try {
		if( data === '' ) {
			alert('unknown error / erreur inconnue');
		} else if( data.error ) {
			if( data.error.indexOf('cmd_logout') > -1 ) {
				alert( 'We are sorry, a problem occured' );
				window.location.href = '/?logout=1';
			} else {
				// extract error code
				var code = '';
				var msg = data.error;
				if( data.error.indexOf('::') != -1 ) {
					var r = data.error.split('::');
					code = r[0];
					msg = r[1];
				}
				alert(msg);
			}
		} else {
			return false;
		}
	} catch(e) {
		debug('check_rm_error() :: an error was encountered during the error check in remote call.');
		debug(e);
	}
	return true;
}

function ws_ask( params ) {
	
	/*
	ws_ask({	id: 'ask',
				title: txt('gift_add'),
				fields:[ 'name' ],
				titles: [ txt('gift_add_sug') ],
				callback: function(values){}
			});
	*/
	
	var $form_el = ws_form( params );
	
	$form_el.dialog({
		title: params.title,
		modal: true,
		buttons: {
			Ok: function() {
				values = ws_form_values( params );
				params.callback( values );
				$(this).dialog('close');
				$(this).dialog('destroy');
				$form_el.remove();
			},
			Cancel: function() {
				$(this).dialog('close');
				$(this).dialog('destroy');
				$form_el.remove();
			}
		}
	});

}

function ws_form( params ) {
	
	var form_id = params.id;
	var form_className = params.className ? params.className : 'form';
	var fields = params.fields;
	var values = params.values ? params.values : {};
	var types = params.types ? params.types : {};
	var titles = params.titles ? params.titles : fields; // set default titles from fields ID
	var custom = params.custom ? params.custom : {};
	var options = params.options ? params.options : {};
	var template_html = params.template ? params.template  : '<div id="'+form_id+'" class="'+form_className+'">'+
															'<form>'+
															'<table>'+
															'<tr wsrepeat="1">'+
															'<td class="title">{title}</td><td class="data">{data}</td>'+
															'</tr>'+
															'</table>'+
															'</form>'+
															'</div>';
	
	var f = {}; // mains fields conf
	
	///////////////////////////////////
	// auto set config for each field
	///////////////////////////////////

	for( var e in fields ) {

		var fname = fields[e];
		var ftitle = titles[e];
		var ftype = types[e] ? types[e] : '';
		var fvalue = values[fname] ? values[fname] : '';
		var foptions = options[e] ? options[e] : {};
		
		// check null values
		switch( fvalue ) {
			case '0000-00-00':
			case '0000-00-00 00:00:00':
				fvalue = '';
			break;
		}
		
		// all fields gets this configs
		f[fname] = {	type: 'text', 
						id: form_id+'_'+fname,
						name: form_id+'_'+fname,
						title: ftitle,
						value: fvalue,
						type: ftype,
						options: foptions
					 };

		// detect special fields
		switch( fname ) {
			
			case 'id':
				f[fname].type = 'hidden';
				break;
		
		}
		
	}
	
	///////////////////////////////////
	// set custom configs
	///////////////////////////////////
	
	for( var fname in custom ) {
		
		// get all custom confs		
		for( var param in custom[fname] ) {
			
			f[fname][param] = custom[fname][param];
			
		}
		
	}
	
	///////////////////////////////////
	// generate html
	///////////////////////////////////

	// convert html template to parsed DOM element
	var $tpl = $(template_html);
	// get repeat container
	var $cont = $tpl.find('[wsrepeat=1]').parent();
	// get repeat html
	var row_html = $cont.html();
	// remove repeat element
	$tpl.find('[wsrepeat=1]').remove();
		
	// add visible inputs
	for( var fname in f ) {
		
		// skip hidden
		if( f[fname].type == 'hidden' ) continue;
		
		var field_html = '';
		switch( f[fname].type ) {
			case 'bool':
				field_html = '<input type="checkbox" id="'+f[fname].id+'"  name="'+f[fname].name+'" value="1" '+( f[fname].value == 1 ? 'checked="1"' : '' )+' />';
				break;
			case 'date':
				field_html = '<input type="text" id="'+f[fname].id+'"  name="'+f[fname].name+'" '+( f[fname].value ? 'value="'+f[fname].value+'"' : '' )+' wsasktype="date" />';
				break;
			case 'select':
				field_html = '<select id="'+f[fname].id+'"  name="'+f[fname].name+'" >';
				for( var opt in f[fname].options ) {
					var opt_display = f[fname].options[opt];
					field_html += '<option value="'+opt+'">'+opt_display+'</option>';
				}
				field_html += '</select>';
				break;
			default:
				field_html = '<input type="text" id="'+f[fname].id+'"  name="'+f[fname].name+'" '+( f[fname].value ? 'value="'+f[fname].value+'"' : '' )+' />';
				break;
		}
		
		// insert html in new row
		var new_row = row_html;
		var new_row = new_row.replace( '{title}' , f[fname].title );
		var new_row = new_row.replace( '{data}' , field_html );
		
		// append new row to template
		$cont.append( new_row );
		
	}
	
	// add hidden inputs
	for( var fname in f ) {
		
		// only hidden
		if( f[fname].type != 'hidden' ) continue;
		
		var field_html = '<input type="hidden" id="'+f[fname].id+'"  name="'+f[fname].name+'" '+( f[fname].value ? 'value="'+f[fname].value+'"' : '' )+' />';
		
		// append new row to template
		$tpl.find('form').append( field_html );
		
	}
	
	// add date picker
	if( $tpl.find('[wsasktype=date]').length > 0 ) {
		$tpl.find('[wsasktype=date]').datepicker( params.datepicker ? params.datepicker : {} );		
	}
	
	// make sure form does not trigger
	//$tpl.find('form').attr('onsubmit','return false');
	$tpl.find('form').submit( function(){return false;} );
	
	return $tpl;
	
}

function ws_form_values( params ) {
	
	values = {};
	
	for( var e in params.fields ) {
		
		var input_id = params.id+'_'+params.fields[e];
		var val = $('#'+input_id).val();
		values[params.fields[e]] = val;
		
	}
	
	return values;
	
}

function ws_key_replace( values , html ) {
	
	for( var e in values ) {
		
		var key = '{'+e+'}';
		var val = values[e];
		while( html.indexOf( key ) > -1 ) {
			html = html.replace( key , val );
		}
		
	}
	
	return html;
}

function ws_first( values ) {
	for( var e in values ) {
		return values[e];
	}
}

function ws_wait( el ){
	// create a rectangle in the middle of the screen
	var $el = el;
	$el.html('<img src="/wslib/img/loading.gif" />');
}

function ws_wait_clear( el ) {
	var $el = el;
	$el.html('');
}

function wsid2id( $el ) {
	var $el;
	$el.attr( 'id' , $el.attr('wsid') );
	$el.find('[wsid]').each( function(){
		$(this).attr( 'id' , $(this).attr('wsid') );
	} );
	return $el;
}

function merge( arr1 , arr2 ) {
	var r = new Array();
	var e;
	var f;
	for( e in arr1 ) {
		if( arr1[e] ) {
			r[e] = arr1[e];
		}
	}
	for( f in arr2 ) {
		if( arr2[f] ) {
			r[f] = arr2[f];
		}
	}
	return r;
}

function omerge( o1 , o2 ) {
	var r = {};
	var e;
	var f;
	for( e in o1 ) {
		if( o1[e] ) {
			r[e] = o1[e];
		}
	}
	for( f in o2 ) {
		if( o2[f] ) {
			r[f] = o2[f];
		}
	}
	return r;
}

function attrs_to_str( r ) {
	str = '';
	for( e in r ) {
		if(! r[e] ) continue;
		str += ' '+e+'="'+r[e]+'"';
	}
	return str;
}

function olength( obj ) {
	var obj;
	var i=0;
	for( var e in obj ) {
		if( ! obj[e] ) continue;
		i++;
	}
	return i;
}

function obj2array( obj ) {
	var obj;
	var arr = new Array();
	for( var e in obj ) {
		if( ! obj[e] ) continue;
		arr.push(obj[e]);
	}
	return arr;
}

function obj2str( obj ) {
	var str = '{';
	var c=0;
	for( var e in obj ) {
		if( c > 0 ) { str+=', '; }
		str += '"'+e+'":"'+obj[e]+'"';
		c++;
	}
	str += '}';
	return str;
}

function xml_encode( text ) {
	return $('<div/>').text(text).html();
}

function debug( value ) {
	try{
		console.log( value );
		if( $.browser.msie && typeof value == 'object' ) {
			var str='';
			for( e in value ) {
				var value2 = value[e];
				if( typeof value2 == 'object' ) {
					str += e+': [';
					for( ee in value2 ) {
						if( typeof value2[ee] == 'string' && value2[ee].length > 10 ) {
							str += ee+': '+(value2[ee].substr(0,10))+'... , ';							
						} else {
							str += ee+': '+value2[ee]+', ';							
						}
					}
					str += ']';
				} else {
					str += e+': '+value[e]+', '+"\r\n";
				}
			}
			console.log(str);
		}
	} catch(e) {
		//alert(e);
	}
}

function dump( arr ) {
	var str = '';
	for( var e in arr ) {
		str += e + ': ' + arr[e] + ' / ';
	}
	debug( str );
}

function isset( value ) {
	if( typeof(value) == 'undefined' || value===null ) {
		return false;
	}
	return true;
}
function isnull(value) {
	return ( value === null );
}
function isnumber( value ) {
	if( typeof(value) == 'number' ){
		return true;
	}
	return false;
}

function truncate( str , len , append ) {
	var str, len, append;
	append = append ? append : '...';

	str = str.length > len ? (str.substr(0,len-1))+append : str;
	
	return str;
}

function to_tag( str , max ){
	var tag = '';
	var max = max ? max : 60;
	var s = ['À','Á','Â','Ã','Ä','Å','Ç','È','É','Ê','Ë','Ì','Í','Î','Ï','Ñ','Ò','Ó','Ô','Õ','Ö','Ø','Ù','Ú','Û','Ü','Ý','à','á','â','ã','ä','å','ç','è','é','ê','ë','ì','í','î','ï','ñ','ò','ó','ô','õ','ö','ø','ù','ú','û','ü','ý','ÿ',' '];
	var r = ['A','A','A','A','A','A','C','E','E','E','E','I','I','I','I','N','O','O','O','O','O','O','U','U','U','U','Y','a','a','a','a','a','a','c','e','e','e','e','i','i','i','i','n','o','o','o','o','o','o','u','u','u','u','y','y','_'];
	var c = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','-','_'];
	// convert accents
	str = str_replace( s , r , str );
	// keep only allowed chars
	for( var e in str ) {
		ch = str[e];
		if( in_array(ch , c) ) {
			tag += ch;
		}
	}
	// truncate if necessary
	tag = truncate( tag , max , '' );
	return tag;
}

function str_replace( s , r , str ) {
	var s, r, str;
	var search;
	var replace;
	for( var e in s ) {
		search = s[e];
		replace = r[e];
		//debug( search );
		//debug( replace );
		var i=0;
		//debug(str.indexOf(search));
		while( str.indexOf(search) >= 0 ) {
			str = str.replace( search , replace );
			i++;
			if( i > 10000 ) break;
		}
	}
	return str;
}

function in_array ( needle, haystack ) {
    var key = '';
		//debug('needle: '+needle);
		//debug('haysatck: '+haystack);
	for (key in haystack) {
		if (haystack[key] == needle) {
			return true;
		}
	}
    return false;
}

function date_utils(){
	this.month_strs = [];
	this.weekday_strs = [];
	
	switch( WS_LANG ) {
		case 'fr':
			this.month_strs = ['Jan','Fev','Mar','Avr','Mai','Jun','Jul','Aou','Sep','Oct','Nov','Dec'];
			this.weekday_strs = ['Dim','Lun','Mar','Mer','Jeu','Ven','Sam'];
			break;
		case 'en':
			this.month_strs = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
			this.weekday_strs = ['Sun','Mon','Tue','Wen','Thu','Fri','Sat'];
			break;
	}
	

	this.day_diff = function( date1, date2 ){
		var oneday = 1000*60*60*24;
		var odate1 = this.parse( date1 , true );
		var odate2 = this.parse( date2 , true );
		var diff = odate2.getTime()-odate1.getTime();
		diff = diff / oneday;
		diff = Math.ceil( diff );
		return diff;
	}
	
	this.date_to_stamp = function( datestr ){
		var odate = this.parse( datestr , true );
		if( odate ) {
			return odate.getTime();
		}
		return 0;
	}
	
	this.parse = function( datestr , return_date_obj ){
		if( ! datestr ) {
			//alert('error: booklet_editor / parse / no datestr');
			//debug('error: date_utils::parse, no datestr: '+datestr);
			return false;
		}
		
		if( typeof datestr == 'number' ) {
			
			// unixtimestamp
			var mydate = new Date( datestr );
			var year = mydate.getFullYear();
			var month = mydate.getMonth()+1;
			var day = mydate.getDate();
			
		} else {
			
			// parse from str 'yyyy-mm-dd'
			var r = datestr.split('-');
			var year = parseInt(r[0]);
			
			// clean up month num that beggins with 0
			if (r[1].substr(0, 1) == '0') {
				r[1] = r[1].substr(1);
			}
			var month = parseInt(r[1]);
			
			// clean up day num that beggins with 0
			if (r[2].substr(0, 1) == '0') {
				r[2] = r[2].substr(1);
			}
			var day = parseInt(r[2]);
			
		}
		
		var dateObj = new Date();
		dateObj.setFullYear(year , month-1 , day);
		
		var weekday = (dateObj.getDay()) + 1;
		
		if( return_date_obj ) {
			return dateObj;
		} else {
			return {year: year, month: month, day: day, weekday:weekday };
		}
	}
	
		
	this.to_month_text = function( datevalue ) {
		if( ! datevalue.year ) {
			d = this.parse(datevalue);
		} else {
			d = datevalue;
		}
		return this.month_strs[ d.month-1 ];
	}
	
	this.to_weekday_text = function( datevalue ) {
		if( ! datevalue.year ) {
			d = this.parse(datevalue);
		} else {
			d = datevalue;
		}
		return this.weekday_strs[ d.weekday ] ? this.weekday_strs[ d.weekday ] : '';
	}
	
	this.to_text = function( datevalue , format ) {
		if( ! datevalue.year ) {
			d = this.parse(datevalue);
		} else {
			d = datevalue;
		}
		
		var	monthstr = this.month_strs[ d.month-1 ];
		var	weekdaystr = this.weekday_strs[ d.weekday ];
		
		switch( format ) {
			case 2:
				switch( WS_LANG ) {
					case 'fr':
						return weekdaystr + ', ' + d.day + ' ' + monthstr + '. ' + d.year;
						break;
					case 'en':
						return weekdaystr + ', ' + monthstr + '. ' + d.day + ', ' + d.year;
						break;
				}
				break;
			
			default:
				switch( WS_LANG ) {
					case 'fr':
						return d.day + ' ' + monthstr + '. ' + d.year;
						break;
					case 'en':
						return monthstr + '. ' + d.day + ', ' + d.year;
						break;
				}
				break;
		}
		
		return null;
	}
	
	this.date_plus_day = function( datevalue , dayvalue , tostring ) {
		var d1 = this.parse( datevalue );

		var mydate = new Date();
		mydate.setFullYear( d1.year , d1.month-1 , d1.day+dayvalue );
		var d2 = {	year: mydate.getFullYear() , 
					month: mydate.getMonth()+1 , 
					day: mydate.getDate() , 
					weekday: mydate.getDay() };
		
		if( tostring ) {
			return	d2.year + '-' +
					(d2.month>9 ? d2.month : '0'+d2.month) + '-' +
					(d2.day>9 ? d2.day : '0'+d2.day);
		} else {			
			return d2;
		}
	}
	
}
/*
 * jQuery outside events - v1.1 - 3/16/2010
 * http://benalman.com/projects/jquery-outside-events-plugin/
 * 
 * Copyright (c) 2010 "Cowboy" Ben Alman
 * Dual licensed under the MIT and GPL licenses.
 * http://benalman.com/about/license/
 */

try {
(function($,c,b){$.map("click dblclick mousemove mousedown mouseup mouseover mouseout change select submit keydown keypress keyup".split(" "),function(d){a(d)});a("focusin","focus"+b);a("focusout","blur"+b);$.addOutsideEvent=a;function a(g,e){e=e||g+b;var d=$(),h=g+"."+e+"-special-event";$.event.special[e]={setup:function(){d=d.add(this);if(d.length===1){$(c).bind(h,f)}},teardown:function(){d=d.not(this);if(d.length===0){$(c).unbind(h)}},add:function(i){var j=i.handler;i.handler=function(l,k){l.target=k;j.apply(this,arguments)}}};function f(i){$(d).each(function(){var j=$(this);if(this!==i.target&&!j.has(i.target).length){j.triggerHandler(e,[i.target])}})}}})(jQuery,document,"outside");
} catch(e) {}


function click_stop( e ) {
	if(!e) e = window.event;
	e.cancelBubble = true;
	e.returnValue = false;
	if (e.stopPropagation) {
		e.stopPropagation();
		e.preventDefault();
	}
}

function tooltips() {
	$('[wstooltip]').tipTip({speed: 150, delay: 300, defaultPosition: 'top', attribute: 'wstooltip'});
}

