// Requires jQuery
// Written by Kenneth Ballenegger (3/11/11)

// jquery plugins and helpers

// generic ajax function for use with paraglide and ajax calls
(function($) {
	$.parajax = function(request, callback) {

		var url;

		if (request.url) {
			url = request.url;
		} else {
			url = app_base + request.controller + "/" + request.action;
		}

		if (request.param) {
			url = url + "/" + request.param;
		}

		url = url + ".json";

		user_id = $.readCookie('user_id'),
		user_signature = $.readCookie('user_signature')
		
		if (user_id || user_signature) {
			if (request.body) {
				request.body.user_id = user_id;
				request.body.user_signature = user_signature;
			} else {
				if (request.query && request.query.length>0)
					request.query = request.query + '&';
				else
					request.query = '';
				request.query = request.query + 'user_id=' + user_id + '&user_signature=' + user_signature;
			}
		}

		if (request.query) {
			url = url + "?" + request.query;
		}

		if (request.body) {
			body = request.body;
			method = "post";
		} else {
			body = null;
			method = "get"
		}

		ajaxOpts = {
			type: method,
			url: url,
			data: body,
			success: callback,
			dataType: "json"
		};
		
		return $.ajax(ajaxOpts);
	};
})(jQuery);

(function($) {
	$.fn.findParentRecursively = function(search) {
		next = $(this);
		found = null;
		while (found==null) {
			if (search.substr(0,1)=='.' && next.hasClass(search.substr(1))) {
				found = next;
			} else if (search.substr(0,1)=='#' && next.attr('id')==search.substr(1)) {
				found = next;
			} else if (search.substr(0,1)!='.' && search.substr(0,1)!='.' && next.get(0).tagName.toLowerCase()==search.toLowerCase()) {
				found = next;
			} else if (next.get(0).tagName.toLowerCase()=='body') {
				found = false;
			} else {
				next = next.parent();
			}
		}
		return found;
	};
})(jQuery);

(function($) {
	$.fn.preload = function() {
	    this.each(function(){
	        $('<img/>')[0].src = this;
	    });
	};
})(jQuery);

// builds a loader and displays it if the first argument is passed, otherwise just returns the html
(function($) {
	$.loader = function(element, my_class) {
	
		var html = '';
		// Stupid firefox doesn't work with webkit animations
		// Hack to make a different loader
		var browser_detect = navigator.userAgent.toLowerCase();
		if (browser_detect.indexOf("firefox") + 1) {
			my_class = (typeof my_class != 'undefined') ? my_class : "";
			html = '<div class="spinner spinner_ff '+my_class+'">';
			html += '<div class="inside">';
			html += '<span>Loading</span>';
			html += '</div>';
			html += '</div>';
		} else {
			my_class = (typeof my_class != 'undefined') ? my_class : "";
			html = '<div class="spinner '+my_class+'">';
			for (v = 1; v <= 12; v++) {
				html += '<div class="bar'+v+'"></div>';
			}
			html += '</div>';
		}
		
		// show the loader for this element
		if (typeof element != 'undefined') {
			$(element).html(html);
			$(element).show();
			return true;
		}
		
		// otherwise return the html
		return html;
	};
})(jQuery);

// newer version of the loader
(function($) {
	$.loaderV2 = function(element, my_class, my_text) {
	
		var html = '';
		
		my_class = (typeof my_class != 'undefined') ? my_class : "";
		my_text = (typeof my_text != 'undefined') ? my_text : "Loading. One second...";
		html = '<div class="pm '+my_class+'">'+ my_text +'</div>';
		
		// show the loader for this element
		if (typeof element != 'undefined') {
			$(element).html(html);
			$(element).show();
			return true;
		}
		
		// otherwise return the html
		return html;
	};
})(jQuery);

// shows a bottom positioned element when a form action is made
(function($) {
	$.saveForm = function(str) {
	
		container_element = document.createElement('div');
		$(container_element).css({
			display: 'none',
			position: 'absolute',
			width: '100%',
			top: '0px',
			left: '0px',
			right: '0px',
			bottom: '0px',
			'z-index': '1001',
			background: 'black',
			opacity: '0.85',
			height: '1209px',
			'background-position': 'initial initial',
			'background-repeat': 'initial initial'
		});
		$(container_element).addClass('container_box');
		$('body').append(container_element);
		$(container_element).fadeIn(200);		
	
		element = document.createElement('div');
		$(element).addClass('form_saving_box');
		$(element).html(str);
		$('body').append(element);
		$(element).css({'bottom': '-'+($(element).height()+25)+'px', 'z-index' : '1002'});
		$(element).animate({
			'bottom' : '0px'
		}, 300);
		return $(element);
	};
})(jQuery);

(function($) {
	$.fn.removeSaveForm = function(timeout) {
		var me = this;
		if (typeof timeout == 'undefined')
			timeout = 0;
		setTimeout(function() {
			$('.container_box').fadeOut(200, function() {
				$(this).remove();
				$(me).animate({
					'bottom' : '-'+($(me).height()+25)+'px'
				}, 300);
			});
		}, timeout);
	};
})(jQuery);

(function($) {
	$.fn.exists = function() {
		return $(this).length > 0;
	}
})(jQuery);

// an extension that sets up the generic situation where you want to have a check-all checkbox (along
// with the other checkboxes in the list
// checkClass is the class that dintinguishes the checkboxes and checkAll is the id representing the all checkbox
(function($) {
	$.checkAll = function(checkClass, checkAll) {
		$(checkAll).change(function() {
			$(checkClass).attr("checked", $(this).attr("checked"));
		});
		var checkAllIntermediate = function() {
			if ($(checkClass).filter(":checked").length == $(checkClass).length) 
				$(checkAll).attr("checked", true);
		};
		$(checkClass).change(function() {
			if (!$(this).attr("checked")) 
				$(checkAll).attr("checked", false);
			checkAllIntermediate();
		});
		
		checkAllIntermediate();
	};
})(jQuery);

// generic popup function
(function($) {
	$.popup = function(controller, action, param, popup_actions, body) {
		var request = {
			controller: controller,
			action: action,
			param: param,
			body: body
		},
		show = function(html) {
            var overlay = $('<div class="cb_popup" id="popup_overlay" />')
                           .html('<div class="close"><a href="#" rel="close"></a></div><div class="inside"></div>')
                           .appendTo('body')
                           .hide()
                           .find('.inside')
                           .append(html)
                           .end()
                           .lightbox_me({
                                centered: true,
                                destroyOnClose:true,
                                overlayCSS: {
                                	opacity: 0.85,
                                	background: '#000'
                                }
                           })
                           .delegate('a[rel="close"]', 'click', function() {
                                $(this).trigger('close');
                           });
              
            if (popup_actions) {
                for (var key in popup_actions) {
                  	var val = popup_actions[key];
                  	$('#popup_overlay').find('a[rel="'+key+'"]').click(function() { window.location.href=val; });
                  }
            }
		}
		
		if(controller instanceof $) {
            show(controller.clone(true).show());
		} else {
    		$.parajax(request, function(d) {
                (d && d.status == 200) && show(d.html);
    		});
		}
	};
})(jQuery);

// generic form validation function
(function($) {
	$.formValidate = function(form, pad) {
		var formErrors = 0;
		var showFormError = function(element) {
			var trElement = $(element).parents('tr');
			if ($(trElement).is(":hidden")) return false;
			
			if (trElement) {
				$(trElement).find('td').addClass('error_row');
			}
			// handle first form error by calling focusing on the first field that has an error
			if (formErrors == 0) {
				$(element).focus();
			}
			formErrors++;
		};
		
		// remove all previous errors
		$(form).find('td').removeClass('error_row');
		
		// validate form first
		$(form).find('input, select').each(function() {
			if (parseInt($(this).data("requiredfield")) == 1) {
								
				// check for form type
				if ($(this).attr('type') == "text") {
					if ($(this).val() == "")
						showFormError(this);
				} else if ($(this).attr('type') == "checkbox") {
					var name = $(this).attr('name');
					if ($(form).find('input[name="'+name+'"]:checked').length == 0)
						showFormError(this);
				} else if ($(this).get(0).tagName.toLowerCase() == "select") {
					if ($(this).val() == "")
						showFormError(this);
				}
			}
			
			if ($(this).attr('validate-regex')) {
				// check regex
				
				regex = new RegExp($(this).attr('validate-regex'));
				if (!regex.test($(this).val()))
					showFormError(this);
			}
		});
		
		if (formErrors > 0) {
			// remove other error boxes first
			$('div.error_box').remove();
			var div = document.createElement('div');
			$(div).addClass('error_box');
			$(div).css('display', 'none');
			if (pad) {
				$(div).css('margin-bottom', '10px');
			}
			$(div).text('Sorry there are errors.  Please try again!');	
			$(form).prepend(div);
			$(div).fadeIn(500);
			setTimeout(function() { $(div).fadeOut(1000); }, 3000);
			return false;
		}
		
		return true;
	};
})(jQuery);

(function ($) {
	$.dateValidate = function(dateMin, dateMax, elementOne, elementTwo) {
		if (dateMin == "" || dateMax == "") return false; // if one is blank, forget about it
		
		dateMinTimestamp = Date.parse(dateMin);
		dateMaxTimestamp = Date.parse(dateMax);
		if (dateMinTimestamp >= dateMaxTimestamp) {
			if (typeof elementOne != 'undefined') $(elementOne).val('');
			if (typeof elementTwo != 'undefined') $(elementTwo).val('');
			alert('Your start date must be less than your end date!');
			return true;
		}
		
		return false;
	};
})(jQuery);

(function ($) {
	$.timeValidate = function(time_start, time_end, elementOne, elementTwo) {
		if ((time_start == null && time_end != null) || (time_end == null && time_start != null)){
			$(elementOne).val('');
			$(elementTwo).val('');
			alert('You must set both a start time & end time, or neither!');
			return false;
		}

		if (time_start != null && time_end != null && time_start >= time_end) {
			$(elementOne).val('');
			$(elementTwo).val('');
			alert('Your start time must be less than your end time!');
			return false;
		}
		
		return true;
	};
})(jQuery);

(function ($) {
	$.addCommas = 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;
	};
})(jQuery);


(function($){var escapeable=/["\\\x00-\x1f\x7f-\x9f]/g,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};$.toJSON=typeof JSON==='object'&&JSON.stringify?JSON.stringify:function(o){if(o===null){return'null';}
var type=typeof o;if(type==='undefined'){return undefined;}
if(type==='number'||type==='boolean'){return''+o;}
if(type==='string'){return $.quoteString(o);}
if(type==='object'){if(typeof o.toJSON==='function'){return $.toJSON(o.toJSON());}
if(o.constructor===Date){var month=o.getUTCMonth()+1,day=o.getUTCDate(),year=o.getUTCFullYear(),hours=o.getUTCHours(),minutes=o.getUTCMinutes(),seconds=o.getUTCSeconds(),milli=o.getUTCMilliseconds();if(month<10){month='0'+month;}
if(day<10){day='0'+day;}
if(hours<10){hours='0'+hours;}
if(minutes<10){minutes='0'+minutes;}
if(seconds<10){seconds='0'+seconds;}
if(milli<100){milli='0'+milli;}
if(milli<10){milli='0'+milli;}
return'"'+year+'-'+month+'-'+day+'T'+
hours+':'+minutes+':'+seconds+'.'+milli+'Z"';}
if(o.constructor===Array){var ret=[];for(var i=0;i<o.length;i++){ret.push($.toJSON(o[i])||'null');}
return'['+ret.join(',')+']';}
var name,val,pairs=[];for(var k in o){type=typeof k;if(type==='number'){name='"'+k+'"';}else if(type==='string'){name=$.quoteString(k);}else{continue;}
type=typeof o[k];if(type==='function'||type==='undefined'){continue;}
val=$.toJSON(o[k]);pairs.push(name+':'+val);}
return'{'+pairs.join(',')+'}';}};$.evalJSON=typeof JSON==='object'&&JSON.parse?JSON.parse:function(src){return eval('('+src+')');};$.secureEvalJSON=typeof JSON==='object'&&JSON.parse?JSON.parse:function(src){var filtered=src.replace(/\\["\\\/bfnrtu]/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,'');if(/^[\],:{}\s]*$/.test(filtered)){return eval('('+src+')');}else{throw new SyntaxError('Error parsing JSON, source is not valid.');}};$.quoteString=function(string){if(string.match(escapeable)){return'"'+string.replace(escapeable,function(a){var c=meta[a];if(typeof c==='string'){return c;}
c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);})+'"';}
return'"'+string+'"';};})(jQuery);


(function($) {
	$.pageSize = function() {
		var xScroll, yScroll;
		if (window.innerHeight && window.scrollMaxY) {	
			xScroll = window.innerWidth + window.scrollMaxX;
			yScroll = window.innerHeight + window.scrollMaxY;
		} else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
			xScroll = document.body.scrollWidth;
			yScroll = document.body.scrollHeight;
		} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
			xScroll = document.body.offsetWidth;
			yScroll = document.body.offsetHeight;
		}
		var windowWidth, windowHeight;
		if (self.innerHeight) {	// all except Explorer
			if(document.documentElement.clientWidth){
				windowWidth = document.documentElement.clientWidth; 
			} else {
				windowWidth = self.innerWidth;
			}
			windowHeight = self.innerHeight;
		} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
			windowWidth = document.documentElement.clientWidth;
			windowHeight = document.documentElement.clientHeight;
		} else if (document.body) { // other Explorers
			windowWidth = document.body.clientWidth;
			windowHeight = document.body.clientHeight;
		}	
		// for small pages with total height less then height of the viewport
		if(yScroll < windowHeight){
			pageHeight = windowHeight;
		} else { 
			pageHeight = yScroll;
		}
		// for small pages with total width less then width of the viewport
		if(xScroll < windowWidth){	
			pageWidth = xScroll;		
		} else {
			pageWidth = windowWidth;
		}
		arrayPageSize = new Array(pageWidth,pageHeight,windowWidth,windowHeight);
		return arrayPageSize;
	};
})(jQuery);

// random password generator
$.extend({password:function(length,special){var iteration=0;var password="";var randomNumber;if(special==undefined){var special=false;}
while(iteration<length){randomNumber=(Math.floor((Math.random()*100))%94)+33;if(!special){if((randomNumber>=33)&&(randomNumber<=47)){continue;}
if((randomNumber>=58)&&(randomNumber<=64)){continue;}
if((randomNumber>=91)&&(randomNumber<=96)){continue;}
if((randomNumber>=123)&&(randomNumber<=126)){continue;}}
iteration++;password+=String.fromCharCode(randomNumber);}
return password;}});




(function($) {
	$.scrolledIntoView = function(element) {
		var docViewTop = $(window).scrollTop();
	    var docViewBottom = docViewTop + $(window).height();
	
	    var elemTop = $(element).offset().top;
	    var elemBottom = elemTop + $(element).height();
	
	    return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom));
	}
})(jQuery);

// hack to make sure everyone has the function Object.keys()
if (typeof Object.keys != 'function') {
    Object.keys = function(obj) {
       if (typeof obj != "object" && typeof obj != "function" || obj == null) {
            throw TypeError("Object.keys called on non-object");
       }
       var keys = [];
       for (var p in obj) obj.hasOwnProperty(p) &&keys.push(p);
       return keys;
    }
}


function urlencode(str) {
	return escape(str).replace('+', '%2B').replace('%20', '+').replace('*', '%2A').replace('/', '%2F').replace('@', '%40');
}

// actual code

$(document).ready(function() {
	$('.auto_add').submit(function() {
		body = '';
		$(this).find('input').each(function() {
			if ($(this).attr('type')!='submit')
				body = body + '&' + urlencode($(this).attr('name')) + '=' + urlencode($(this).attr('value'));
		});
		controller = $(this).attr('controller');
		request = {
			controller: controller,
			action: "add",
			body: body,
			query: "require_html=1"
		};
		$.parajax(request, function(data) {
			if (data && data.status == 200) {
				$('.addable').each(function() {
					if ($(this).attr('controller')==controller) {
						$(this).append(data.html);
						$('#'+data.object.id).slideDown();
					}
				});
			} else {
				alert("error: " + data.message);
			}
		});
		return false;
	});
	
	$('.auto_delete').live('click', function() {
		object = $(this).findParentRecursively('.deletable');
		if(!object)
			return;
		request = {
			controller: object.attr('controller'),
			action: "delete",
			param: object.attr('id')
		};
		$.parajax(request, function(data) {
			if (data && data.status == 200)
				object.slideUp("slow");
			else
				alert("error: " + data.message);
		});
		return false;
	});
	
	var auto_submit_fn = function(input) {
		
		value = $(input).val();
		
		if ($(input).attr('type') == 'checkbox') {
			value = input.checked?1:0;
		}
		request = {
			url: $(input).parents('form').attr('action'),
			body: {}
		};
		key = $(input).attr('name');
		request.body[key] = value;
		$.loader('#profile_edit_loader_div', 'loader')
		$.parajax(request, function(response) {
			if (response.status >= 300) {
				alert('There was an error saving your changes: ' + response.message);
				console.log(response);
			}
			// if id autosubmit_$ID is present, magically set its value, too
			$('#autosubmit_'+key).html(value);
			
			// trigger event
			$(input).trigger('auto_submitted');
			
			$('#profile_edit_loader_div').children('.loader').fadeOut();
		});
	}
	
	// auto-submit intelligent forms
	$('form.auto_submit').submit(function() { return false; });
	$('form.auto_submit input').live('change blur cancel', function() { 
		if ($(this).data('ignoreAutoSubmit') != 1)
			auto_submit_fn(this);
		 
	});
	
	$('.lightbox').live('click', function() {
		controller = $(this).data('controller');
		action = $(this).data('action');
		param = $(this).data('param');
		$.popup(controller, action, param);
		return false;
	});
	
	// feedback tab
	pageSize = $.pageSize();
	$('.feedback_tab a').css("top", Math.round((pageSize[3]/2) - 60)+"px");
	$('.feedback_tab a').live('click', function(e) {
		body = { redirect: $(this).attr('redirect') };
		$.popup('support', 'index', false, false, body);
		e.preventDefault();
	});	
});

// Easing functions
jQuery.easing['jswing'] = jQuery.easing['swing'];
jQuery.extend( jQuery.easing,
{
	def: 'easeOutQuad',
	easeInBounce: function (x, t, b, c, d) {
		return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
	},
	easeOutBounce: function (x, t, b, c, d) {
		if ((t/=d) < (1/2.75)) {
			return c*(7.5625*t*t) + b;
		} else if (t < (2/2.75)) {
			return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
		} else if (t < (2.5/2.75)) {
			return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
		} else {
			return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
		}
	},
	easeInOutBounce: function (x, t, b, c, d) {
		if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
		return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
	},
	easeInQuart: function (x, t, b, c, d) {
		return c*(t/=d)*t*t*t + b;
	},
	easeInElastic: function (x, t, b, c, d) {
		var s=1.70158;var p=0;var a=c;
		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
		if (a < Math.abs(c)) { a=c; var s=p/4; }
		else var s = p/(2*Math.PI) * Math.asin (c/a);
		return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
	}
});


(function($) {
	$.readCookie = function(name) {
		var nameEQ = name + "=";
		var ca = document.cookie.split(';');
		for(var i=0;i < ca.length;i++) {
			var c = ca[i];
			while (c.charAt(0)==' ') c = c.substring(1,c.length);
			if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
		}
		return null;
	};	
})(jQuery);


(function($,undefined){
  '$:nomunge'; // Used by YUI compressor.
  
  $.fn.serializeObject = function(){
    var obj = {};
    
    $.each( this.serializeArray(), function(i,o){
      var n = o.name,
        v = o.value;
        
        obj[n] = obj[n] === undefined ? v
          : $.isArray( obj[n] ) ? obj[n].concat( v )
          : [ obj[n], v ];
    });
    
    return obj;
  };
  
})(jQuery);

(function($) {
    $.fn.dateVal = function(d) {
        return this.each(function() {
            var month = (d.getMonth() > 8 ? '' : '0') + (d.getMonth() + 1),
                day = (d.getDate() > 9 ? '' : '0') + d.getDate();
            $(this).val(month + '/' + day + '/' + d.getFullYear());
        });
    }
})(jQuery);

