//prototype's bind and $A 
var $A = Array.from = function(iterable) {
  if (!iterable) return [];
  if (iterable.toArray) {
    return iterable.toArray();
  } else {
    var results = [];
    for (var i = 0, length = iterable.length; i < length; i++)
      results.push(iterable[i]);
    return results;
  }
}
Function.prototype.bind = function() {
  var __method = this, args = $A(arguments), object = args.shift();
  return function() {
    return __method.apply(object, args.concat($A(arguments)));
  }
}

var _Validator_ = {
	total_errors: 0,
	error_codes: {
		'100'	: 'Please provide a valid email address.',
		'101'	: 'Please provide a valid phone number.',
		'102'	: 'Phone number must be at least 10 digits long',
		'103'	: 'Name cannot be empty.',
		'104'	: 'There were errors while processing your request. Please correct the errors and try again.',
		'105'	: 'Text does not match! Please enter the text displayed in the image above.',
		'110'	: 'Missing Required Field!'				
	},
	__errors: {},
	fields_to_validate: {},
	options: {},
	initialize: function(fields_to_validate, options) {
		this.fields_to_validate = fields_to_validate; // array
		$.extend(this.options, options || {});
		this.options.optional = this.options.optional || {};
	},
	validate: function(form) {
		//these are defaults. we always want to validate them?
		var email 	= this.email($('#Email').val(), this.options.optional.email);
		var phone 	= this.phone($('#Phone').val(), this.options.optional.phone);
		var name 	= this.name($('#Name').val(), this.options.optional.name);
		var imgtext = this.imagetext($('#ImageText').val(), 5, 6);
	
		
		//console.log(this.fields_to_validate)
		invalid = false;
		var code = 200;
		for (var f in this.fields_to_validate) {
			
			var res = this.fields_to_validate[f]($('#'+f));
			
			if (res) {
				//the function, if validation fails, should return the error message
				// and error code
				invalid = true;
				if (typeof(res) == 'string')
					this.error_codes[code] = res; //register the error code
				else
					code = '110'
					
				this.error(f, code.toString()); // log the error
			}
			code += 1;
		}
		
		return (email && phone && name && imgtext && !invalid);
	},
	email: function(email, optional) {
		if (optional && email == '')
			return true;
			
		var re	=/^([a-zA-Z0-9_\.\-\+])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
		if (re.test(email))
			return true;
		
		this.error('Email', '100');
		return false;
	},
	phone: function(phone, optional) {
		if (optional && phone == '')
			return true;
		
		var valid 	= false;
		var clean 	= phone.replace(/[\(\)\.\-\+\:\ ]/g, '');
		var re 		= /^[0-9]{10,}$/
		if (re.test(clean))
			return true;
			
		this.error('Phone', '101')
		return false;
	},
	name: function(name, optional) {
		if (optional && name == '')
			return true;
			
		if (this.string(name))
			return true;
		
		this.error('Name', '103')
		return false;
	},
	imagetext: function(str, min_length, max_length) {
		if (!this.string(str, min_length, max_length)) {
			this.error('ImageText', '105');
			return false;
		}
		return true;
	},
	string: function(str, min_length, max_length) {
		str 		= $.trim(str);
		var min 	= min_length || 1;
		var max 	= max_length || false;
		if (str.length < min)
			return false;
		if (max && (str.length > max))
			return false;
		
		return true;
	},
	error: function(key, code) {
		if (code) {
			this.__errors[key] 	= code;
			this.total_errors 	+= 1;
		} else if (key)
			return this.error_codes[this.__errors[key]]
		
		var _errs 		= {}	
		for (err in this.__errors) {
			_errs[err] 	= this.error_codes[this.__errors[err]]
		}
		_errs['default_error_message'] = this.error_codes['104']
		return _errs;
	},
	reset: function() {
		this.__errors 		= {};
		this.total_errors 	= 0;
	},
	has_errors: function() {
		return this.total_errors != 0;
	}
}
function Validator(fields_to_validate, options) {
	this.initialize(fields_to_validate, options);
	return this;
}
Validator.prototype = _Validator_;






function log(msg) {console.log(msg)}

var _Form_ = {
	/** @id 
		string to hold the id of the form 
	*/
	id: '', 
	/** @return_url 
		string to keep a copy of the return url that will be removed from the form 
	*/
	return_url: '', 
	initialize: function(id, options) {
		this.options 	= {}
		
		$.extend(this.options, options || {})
		this.validator 	= new Validator(this.options.validate, this.options);
		this.id 		= id;
		this.setup();
		return this;
	},
	setup: function() {
		form 			= $('#'+this.id + ' form')
		ret_url 		= $('input[name=return_url]', form)
		this.return_url = ret_url.val()
		/*ret_url.remove();*/
		form.submit(this.submit.bind(this))
	},
	submit: function(e) {
		
		this.validator.reset();
		
		var form 		= $('#'+this.id + ' form');
		
		this.clear_errors(form);
						
		if (this.validate(form)) {
			/* log('valid'); */
		} else {
			e.preventDefault();
			e.stopPropagation();
			this.display_errors(form)
			return;
		}
	},
	clear_errors: function(form) {
		$(".error", form).remove();
		$(".errors", "#"+this.id).remove();
		$(".field_with_errors", form).removeClass('field_with_errors');
	},
	display_errors: function(form) {

		var errors = this.validator.error();
		for (err in errors) {
			$('#'+this.id + ' #'+err).addClass('field_with_errors').after('<strong class="error" style="color: red; background: white;">'+errors[err]+'</strong>');
		}
		$('#'+this.id + ' form').before('<div class="errors" style="color:red; background:white;">'+errors['default_error_message']+'</div>');
		
	},
	validate: function(form) {
		return this.validator.validate(form);
	}
	
	
}
function ContactForm(id, options) {
	this.initialize(id, options);
	return this;
}	
ContactForm.prototype = _Form_;


try {

(function($) {
	/* functions for forms injected */
	$.fn.to_json = function() {
		j = {};
		if (this.length == 0) return j;
		$('*[@name]', this).each(function(i, el) {
			j[$(el).attr('name')] = $(el).val();
		})
		return j;
	};
	$.fn.to_s = function() {
		if (this.length == 0) return '';
		return $('*[@name]', this).serialize();
	};
})(jQuery);


function log(msg) {
}

/* a lighter accordion plugin without dependencies */
(function($) {
	$.fn.oheight = function() {
		t = this;
		return parseInt(t.css('margin-top').replace('px', '')) +  
					parseInt(t.css('margin-bottom').replace('px', '')) + 
					parseInt(t.css('padding-bottom').replace('px', '')) + 
					parseInt(t.css('padding-top').replace('px', '')) + 
					parseInt(t.css('border-top-width').replace('px', '')) +
					parseInt(t.css('border-bottom-width').replace('px', '')) + t.height();
					
	};
	$.fn.owidth = function() {
		t = this;
		return parseInt(t.css('margin-left').replace('px', '')) +  
					parseInt(t.css('margin-right').replace('px', '')) + 
					parseInt(t.css('padding-left').replace('px', '')) + 
					parseInt(t.css('padding-right').replace('px', '')) + 
					parseInt(t.css('border-left-width').replace('px', '')) +
					parseInt(t.css('border-right-width').replace('px', '')) + t.width()
	};
	$.fn.accordion = function(def) {
		this.children('div').each(function(i, e) {			
			var el = $(e);
			
			el.css({overflow:'hidden'});
			var t = el.find('h4:first');
			if (t.length == 0) return;
			var h = t.oheight();
			e.originalHeight = el.height() + (isNaN(h) ? t.height() : h);
		 	/*	console.log(typeof h); */
			
			
			t.bind('click', function(e) {	
				par = $(this).parent();
				sibs = par.siblings();
				sibs.each(function(i, s) {
					$(s).removeClass('open').animate({height:(isNaN(h) ? t.height() : h)}, 500)
				});
				par.addClass('open').animate({height:par[0].originalHeight}, 500)
			});

			if (def != i) el.height(isNaN(h) ? t.height() : h);		
			/* console.log(isNaN(h)); */
		});	
	};
})(jQuery);

} catch(e) { /* if (console) {console.log(e)} */  }

String.prototype.capitalize = function() {
	return this.replace(/\_/g, ' ').replace(/\w+/g, function(a){
	   return a.charAt(0).toUpperCase() + a.substr(1).toLowerCase();
	});
}
