var jc = {
	init:function(){
		jc.ui.init();
	},
	util:{
		dump:function(o){
			x = function(obj,prefix){
				prefix = (typeof prefix == 'undefined')?'':prefix;
				var str = '';
				for (var i in obj) {
					str += prefix+''+i+' = '+obj[i]+'\n';
					str += x(obj[i],prefix+'   ');
				}
				return str;
			}	
			alert(x(o));
		},
		string:{
			isEmail:function(str){
				var filter  = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
				return (filter.test(str));
			}	
		},
		number:{
			commaFormat:function(nStr){
				nStr += '';
				x = nStr.split('.');
				x1 = x[0];
				x2 = x.length > 1 ? '.' + x[1] : '';
				var rgx = /(\d+)(\d{3})/;
				while (rgx.test(x1)) x1 = x1.replace(rgx, '$1' + ',' + '$2');
				return x1 + x2;
			},
			dollarFormat:function(n){
				if (typeof n != 'number') return '0.00';
				var n1 = n.toFixed(2);
				var n2 = jc.util.number.commaFormat(n1);
				return n2;
			}
		}
	},
	ui:{
		init:function(){
			$.each($('div.jc-slideShow'),function(i,e){ jc.ui.slideShow.init($(e)) });
			$.each($('a.jc-ddMenu'),function(i,e){ jc.ui.ddMenu.init($(e)) });
		},
		slideShow:{
			interval:3000,
			indexPosition:'bottom right',
			init:function(ss){
				$(ss).find('.jc-slide').width($(ss).width()).height($(ss).height()); //.click(function(){ jc.ui.slideShow.next($(this).closest('.jc-slideShow')); }); // set inividual slide dimensions
				if (ss.find('.jc-slide-active').length == 0) ss.find('.jc-slide').first().addClass('jc-slide-active'); // set first slide to be active
				jc.ui.slideShow.restartTimer(ss);
				var slideCount = $(ss).find('.jc-slide').length;
				// add index controls
				var control = $('<div class="jc-slide-control" />').appendTo(ss);
				// position
				if (jc.ui.slideShow.indexPosition.indexOf('bottom') >= 0) control.css('bottom','5px');
				else if (jc.ui.slideShow.indexPosition.indexOf('top') >= 0) control.css('top','5px');
				if (jc.ui.slideShow.indexPosition.indexOf('left') >= 0) control.css('left','5px');
				else if (jc.ui.slideShow.indexPosition.indexOf('right') >= 0) control.css('right','5px');
				// slides
				$.each($(ss).find('.jc-slide'),function(i,e){
					$('<div class="jc-slide-control-node" />').appendTo(control).click(function(){ jc.ui.slideShow.slideTo($(e)); });
					$(e).attr('jc-index',i);
				});
				control.css('width',(slideCount*(12+5))+'px');
				// marker
				$('<div class="jc-slide-control-marker" />').appendTo(control);
			},
			next:function(ss){
				var e1 = ss.find('.jc-slide-active');
				var e2 = e1.next('.jc-slide');
				if (e2.length == 0) e2 = ss.find('.jc-slide').first();
				jc.ui.slideShow.slideTo(e2);
			},
			previous:function(ss){
				var e1 = ss.find('.jc-slide-active');
				var e2 = e1.previous('jc-slide');
				if (e2.length == 0) e2 = ss.find('jc-slide').last();
				jc.ui.slideShow.slideTo(e2);
			},
			slideTo:function(e2){
				var s = $(e2).closest('.jc-slides');
				$(s).animate({left:'-'+e2.position().left+'px'}, function(){
					s.find('.jc-slide-active').removeClass('jc-slide-active');
					$(e2).addClass('jc-slide-active');
					jc.ui.slideShow.restartTimer($(e2).closest('.jc-slideShow'));
				});
				var m = $(s).closest('.jc-slideShow').find('.jc-slide-control-marker');
				var i = $(e2).attr('jc-index');
				$(m).animate({left:(i*16)+'px'});
			},
			restartTimer:function(ss){
				var t = $(ss).data('timer');
				if (typeof t != 'undefined')
					if (t != null)
						clearTimeout(t);
				$(ss).data('timer',setTimeout(function(){ jc.ui.slideShow.next(ss); },jc.ui.slideShow.interval));
			}
		},
		ddMenu:{
			init:function(a){
				var dd = $(a).siblings('div.jc-ddMenu'); // find and drop down
				$(a).data('jc-ddClone',dd.clone()); // clone/store it for use later
				dd.remove(); // remove original drop down HTML from DOM (waste of memory)
				$(a).mouseover(function(){ jc.ui.ddMenu.show($(this)); });
			},
			show:function(a){
				var dd = a.data('jc-ddClone');
				dd.appendTo(document.body);
				var p = a.offset();
				dd.css({top:(p.top+a.height())+'px',left:p.left+'px'});
				dd.slideDown('fast');
				$(document).click(function(e){
					if ($(e.target).closest('.jc-ddMenu').length == 0)
						jc.ui.ddMenu.hide(dd);
				});
				$('.jc-ddMenu').mouseout(function(e){
					if ($(e.relatedTarget).closest('.jc-ddMenu').length == 0) 
						jc.ui.ddMenu.hide(dd);
				});
			},
			hide:function(dd){
				dd.slideUp('fast',function(){ $(dd).remove(); });
			}
		}
	},
	form:{
		init:function(sel, fnError, fnSuccess){
			jc.form.field.init(sel, fnError, fnSuccess);
		},
		fireFn:function(input, test, fnError, errorMessage, fnSuccess){
			var er = '';
			// is required
			if (input.hasClass('required') && jc.form.field.isEmpty(input))
				er += 'This field is required. ';
			// match value test
			if (input.data('matchValue') != null) {
				if (input.val() != input.data().matchValue.val())
					if (input.hasClass('password'))
						er += 'The passwords do not match. ';
					else
						er += 'The value do not match. ';
			}
			
			// custom input type test
			if (!test)
				er += errorMessage+' ';
			
			if (er != '' && typeof fnError == 'function') fnError(input,er);
			else if (er == '' && typeof fnSuccess == 'function') fnSuccess(input);
			
			return (er == '');
		},
		// loop through a form and validates all the fields
		validate:function(form){
			// track errors
			var errors = 0;
			// loop through all form fields
			$.each($(form).find('input, select, textarea'),function(i,e){
				// call validation (what would usually happen onblur)
				var validate = $(this).data().validate;
				if (typeof validate == 'function') errors += Number(!validate($(this)));
			});
			return (errors == 0);
		},
		unvalidate:function(formSel){
			// loop through all form fields
			$(formSel).find('input, select').each(function(i,e){
				// call validation (what would usually happen onblur)
				var onSuccess = $(this).data().onSuccess;
				if (typeof onSuccess == 'function') onSuccess($(this));		
			});
			return true;
		},
		field:{
			init:function(sel, fnError, fnSuccess){
				if (typeof sel == 'undefined') sel = document.body; // search entire DOM by default
				if (typeof fnError == 'undefined') fnError = null;
				if (typeof fnSuccess == 'undefined') fnSuccess = null;
				// common input bindings
				$.each($(sel).find('input, select, textarea'),function(i,e){
					$(e).data('onError',fnError); // store a pointer to the validation function in the data object
					$(e).data('onSuccess',fnSuccess); // store a pointer to the validation function in the data object
					if ($(e).attr('matchvalue') != null) $(e).data('matchValue',$('#'+$(e).attr('matchvalue')));
				});
				// add's type specific event handlers and formatting
				for (var i in jc.form.field.types) {
					$(sel).find('input.'+i).each(function(j,e){ 
						jc.form.field.types[i].init(e);
					});
				}
				$(sel).find('textarea').each(function(j,e){ 
					jc.form.field.types.textarea.init(e);
				});

			},
			isEmpty:function(input){
				// is the field empty or not (text value = '', selectbox selected index = 0, radio/checkbox = unchecked)
				var tag = $(input)[0].tagName;
				var type = $(input).attr('type');
				if (tag == 'INPUT')
					if (type == 'checkbox' || type == 'radio') return ($(input).attr('checked') == false);
					else return ($(input).val() == '');
				else if (tag == 'SELECT') return ($(input).selectedIndex == -1);
				else if (tag == 'TEXTAREA') return ($(input).val() == '');
			},
			types:{
				email:{
					init:function(input){
						$(input).data('validate',jc.form.field.types.email.validate); // store a pointer to the validation function in the data object
						//$(input).blur(function(){ $(this).data().validate($(this)); }); // BIND validation on blur
					},
					validate:function(input){
						var test = (jc.util.string.isEmail(input.val())) || jc.form.field.isEmpty(input);
						var d = $(input).data();
						return jc.form.fireFn(input, test, d.onError, 'Invalid email address.', d.onSuccess);
					}
				},
				text:{
					init:function(input){
						$(input).data('validate',jc.form.field.types.text.validate); // store a pointer to the validation function in the data object
						//$(input).blur(function(){ $(this).data().validate($(this)); }); // BIND validation on blur
					},
					validate:function(input){
						var test = true;
						var d = $(input).data();
						return jc.form.fireFn(input, test, d.onError, 'Invalid text.', d.onSuccess);
					}
				},
				password:{
					init:function(input){
						$(input).data('validate',jc.form.field.types.password.validate); // store a pointer to the validation function in the data object
						//$(input).blur(function(){ $(this).data().validate($(this)); }); // BIND validation on blur
					},
					validate:function(input){
						var test = ($(input).val().indexOf(' ') == -1); // no spaces (simple validation)
						var d = $(input).data();
						return jc.form.fireFn(input, test, d.onError, 'Your password cannot contain any spaces.', d.onSuccess);
					}
				},
				checkbox:{
					init:function(input){
						$(input).data('validate',jc.form.field.types.checkbox.validate); // store a pointer to the validation function in the data object
						//$(input).click(function(){ $(this).data().validate($(this)); }); // BIND validation on blur
					},
					validate:function(input){
						var test = true; // no test
						var d = $(input).data();
						return jc.form.fireFn(input, test, d.onError, 'Checkbox error.', d.onSuccess);
					}
				},
				textarea:{
					init:function(input){
						$(input).data('validate',jc.form.field.types.textarea.validate); // store a pointer to the validation function in the data object
						//$(input).blur(function(){ $(this).data().validate($(this)); }); // BIND validation on blur
					},
					validate:function(input){
						var test = true;
						var d = $(input).data();
						return jc.form.fireFn(input, test, d.onError, 'Invalid text.', d.onSuccess);
					}
				}
			}
		}		
	}
};
