//!
// jc.jquery.js
// written by James D Chalmers
// Where possible, Code Copyright & Property of MTCMedia LTD
// www.mtcmedia.co.uk
// MTCMEDIA: Internet Media Solutions

// v1.634
// UNRELEASED last updated 21 May 2010
// alphabginstance to lowercase
// working on horzscroll, brandscroll & marquee replacement.
// added jcID - a uniform & persistant ID for all jc$ elements.
// horzscroll basic up and running
// fixed ie8 bug for horzscroll. Unfortunately now does not self-clean
// refined isnull & isfunc
// realise need to adopt (function($){/*exec*/})(jQuery); approach
// added jc$.timer - time logging for the lazy peeps
// added is_array
// added count();
// added console.error non-fail support for lacking browsers
// added check for global_debug var, if true, some alerts will display
// added console check alert if (global_debug)
// fixed isnull to actually specify T
// added ajaxForm
// added default value for global_debug
// swapped 1:0 for isfunc so it actually works.
// console.log does $('body').append
// added sip
// added extra interface to horzscroll
// added swapKeys, string method extender to do easy find replace.
// fixed 'float' error on brandscroll
// added jc$.randNum
// fixed object cloning in centerscreen
// fixed some incorrect practices here and there.
// added dragMe - lighter version of the jQuery ui drag.
// added getOuterWidth
// added rewind to horzscroll & refactored '_' to 'self'.

// v1.633
// released 26 Mar 2010
// updated centerscreen to include 'show' option. default : 1
// added bswap
// added findpr
// updated screenfill to include 'onresizeshow' & 'show' option. default : 0, 1
// updated screenfill to modern variable name conventions (mvnc)
// updated screenfill to include forced w & h declarations
// updated centerscreen to mvnc.
// updated screenfill to store ratio as element attribute
// updated screenfill to operate based on parent element
// added syntheticHistory. Even works in safari as long as hash is not a real id.
// updated alphabg to auto window.resize
// added setOpac. Allows easy opacity setting via class name eg: class="something anything setOpac-25"
// 	that will set the element to 25% opacity.
// 	call it $.setOpac.init();
// added stylesheet_swap. allows easy cross-browser changing of stylesheets.
//	methods: init, enable, disable, change.
// further updated centerscreen to mvnc - fixed error.
// renamed _grabber on alphabg
// deprecated jcmarquee !!!!!!! - a new function will replace this and brandscroll
// brandscroll updated to use a central jc$ object
// jc$ object beginnings, this will be further refined.
// added in callback to stylesheet_swap and apply style on startup

// v1.632
// released 17 Feb 2010
// Added auto window.resize events to centerscreen & screenfill

// v1.631
// released 8 Feb 2010
// updated centerscreen
//   added auto positioning to element
// this should be checked across all functions
// some rollfade updates got over-written. These have now been fixed.

// v1.63
// released 27 Jan 2010
// added jcmarquee
//  this is an adaptation of brandscroll
//  these two functions badly need to be deprecated and
//  rewritten as a single light function
//  that is highly customisable.
// modified brandscroll_settings identifier.
// 	now : var i = 'bs_'+Math.floor(Math.random()*10102030123);

// v1.62
// released 19 Jan 2010
// changelog:
// fixed rollfade checkclass
// adjusted rollfade default (fades in to 1.0 opacity now instead of 0.9)
// fixed brandscroll mouse out
// cleared timeout properly in brandscroll
// adding date to new versions

// v1.61
// changelog
// added daisychaining to all functions
// modified centerscreen

// v1.6
// changelog
// added brandscroll();

//  v1.51
// changelog
// added formhint

// v1.0 traced back to 8th Dec 2009


// @TODO
//	move all id and data storage to jc$ object.
//	rewrite brandscroll
//	replace all dom insertions with more effecient methods eg: var $div = $('<div />').insertAfter($el);
//	deprecate jc$.settings


/////// NEEDED GLOBAL VARIABLES

var jc$ = {
		ids			: [],
		timeouts	: [],
		intervals	: [],
		settings	: []
	},
	addMethod	= '',
	global_debug = typeof(global_debug)=='undefined' ? 0 : global_debug;

/////// NEEDED FUNCTIONS

// #sp - stops event bubbling
function sp (event){
	event.stopPropagation();
}

// #sip - stops immediate event bubbling
function sip(event){
	event.stopImmediatePropagation();
}

// #isnull - typeof shorthand
// for use within a function with a defined parameter. function (x){ alert(isnull(x)); }
// returns 1 if null, 0 if not.
// specify t to change 'undefined'
// t=function, returns 1 if function, 0 if not.
function isnull (v, t){
	t = t || 'undefined';
	return typeof(v)==t ? 1 : 0;
}

// #isfunc - isnull(v, 'function') shorthand
// for use within a function with a defined parameter. function (x){ alert(isfunc(x)); }
function isfunc (v){
	return isnull(v, 'function') ? 1 : 0;
}

// #is_array
function is_array(obj) {
  return (obj.constructor.toString().indexOf("Array") == -1)? false : true;
}

// #count
function count(obj){
	if(!isnull(obj)){
		var c = 0;
		for (var i in obj) {
			c++;
		}
		return c;
	}
	return false;
}

// #console - support for console.debug
if(typeof(console)=='undefined') {
	if(global_debug){
		$('body').prepend(	"This site is in global_debug mode.\nConsole was not"+
				" found.\nConsole.log() messages appended to body."
				);
					}

	var console = {};
	console.debug 	= function(){};
	console.log 	= function(text){
		if(global_debug){
			$('body').append('<p>'+text+'</p>');
		}
	};
	console.error 	= function(){};
}

// #jcID - assigns an id & stores in the jc$ object, returns id.
$.fn.jcID = function(){
	var $el = $(this),
		id = $el.attr('jc');

	if(!id) {
		id = Math.floor(Math.random()*10120310010123);
		$el.attr('jc', id);
		jc$.ids[id] = this;
	}

	return id;
};


// #timer
jc$.timer = function(name){
	name = name || 'A function';
	this.name		= name;
	this.startTime 	= new Date().getTime();
	this.endTime	= 0;
	this.timeTaken	= 0;
};

jc$.timer.prototype.log = function(){
	this.getTime();
	console.log(this.name+'; Completed in '+this.timeTaken+'ms.');
	return true;
};

jc$.timer.prototype.getTime = function(){
	this.endTime	= new Date().getTime();
	this.timeTaken 	= this.endTime-this.startTime;
}

jc$.timer.prototype.start = function(name){
	this.startTime = new Date().getTime();
	this.endTime = 0;
	this.name = name || this.name;
};


// #randNum
jc$.randNum = function(p){
	p = p || 'jc$randNum';
	return p+Math.floor(Math.random()*10210010);
};


/////// JC.JQUERY.FUNCTIONS

// #screenfill
// leaves no borders
// yset

$.fn.screenfill = function(o){

	o = $.extend({
		animate : 1,
		animateDuration : 500,
		onresize : 1,
		onresizeanimate : 0,
		show : 1,
		onresizeshow : 0,
		w : 0,
		h : 0,
		parent : 0
	}, o);

	$('html, body').css({overflow : 'hidden'});

	var w = $(window).width();
	var h = $(window).height();

	return this.each(function(){

		var $el = $(this),
			ew = $el.outerWidth(),
			eh= $el.outerHeight();

		if(o.parent){
			w = $el.parent().outerWidth();
			h = $el.parent().outerHeight();
		}

		if(o.w>0){ew = o.w;}
		if(o.h>0){eh = o.h;}

		// store ratio
		if(typeof($el.attr('screenfill_ratio'))!='undefined'){
			var ratio = $el.attr('screenfill_ratio');
		} else {
			var ratio = ew / eh;
			$el.attr('screenfill_ratio', ratio);
		}

		// auto positioning
		if($el.css('position')!='absolute'){
			$el.css('position', 'relative');
		}

		var co = {}; // css options

		if(w > h){
			co.width = w;
			co.height = (w/ratio);
		} else {
			co.height = h;
			co.width = (h*ratio);
		}

		if(co.width < w){
			co.height = h;
			co.width = (h*ratio);
		}

		if(co.height < h) {
			co.height = h;
			co.width = (h*ratio);
		}

		// center

		co.left = ((w-co.width)/2)+'px';
		co.top = ((h-co.height)/2)+'px';

		co.height += 'px';
		co.width += 'px';

		if(o.animate){
			$el.stop().animate(co, {queue : false, duration : o.animateDuration});
		} else {
			$el.stop().css(co);
		}

		if(o.show){
			$el.fadeIn();
		}

		if(o.onresize){

		var o2 = $.extend(true, {}, o);
		o2.animate = o.onresizeanimate;
		o2.onresize = 0;
		o2.show = 0;
		$(window).bind('resize', function(){
			$el.screenfill(o2);
		});

		}

	});

};

// #centerscreen

// v1.631 update:
// supports auto positioning

// v1.61 updates:
// now supports custom pre-set width / height
// and horizontal and vertical adjustments
// also supports centering relative to immediate parent

$.fn.centerscreen = function(opts){
	var defaults = {
			horizontal : 1,
			vertical : 1,
			animate : 1,
			speed : 500,
			parent : 0,
			vertical_adjustment : 0,
			horizontal_adjustment : 0,
			w : 0,
			h : 0,
			onresize : 1,
			onresizeanimate : 0,
			show : 1
		};

	this.each(function(){

		var o	= $.extend({},defaults,opts),
			$el	= $(this),

			ew	= $el.outerWidth(true),
			eh	= $el.outerHeight(true);

		if(o.parent){
			var w = $el.parent().outerWidth(),
				h = $el.parent().outerHeight();
		} else {
			var w = $(window).width(),
				h = $(window).height();
		}

		// auto positioning
		if($el.css('position') != 'absolute'){
			$el.css('position', 'relative');
		}

		if(o.w >0){
			w = o.w-1+1;
		}

		if(o.h>0){
			h = o.h-1+1;
		}

		w = (o.horizontal_adjustment-1+1)+w;
		h = (o.vertical_adjustment-1+1)+h;

		var co = {};

		if(ew < w){
			if(o.horizontal){
				co.left = (w-ew)/2+'px';
			}
		} else {
			co.left = 0;
		}

		if(eh < h) {
			if(o.vertical){
				co.top = (h-eh)/2+'px';
			}
		} else {
			co.top = 0;
		}


		if(o.animate){
			$el.stop().animate(co, {queue : false, duration : o.speed});
		} else {
			$el.stop().css(co);
		}

		if(o.onresize){
			var o2		= $.extend({}, o);
			o2.onresize	= 0;
			o2.animate	= o.onresizeanimate;
			o2.show		= 0;
			$(window).bind('resize', function(){
				$el.centerscreen(o2);
			});
		}

		if(o.show) {
			$el.show();
		}

	});

	return this;

};


// #rollover
// name images, imagename_0.jpg (or whatever filetype)
// imagename_1.jpg (for hover)..

$.fn.rollover = function(options){

	var options = $.extend({
		preloadID : '#rollover_preloader'
	}, options);

	return this.each(function(){
		var el = $(this);
		if(typeof(el.attr('src')) == 'undefined'){
			// find the image
			el = el.find('img');
		}

		if(el.length > 0){
			// start rollover
			var thissrc = el.attr('src');
			// thissrc is image original src

			var thishover = thissrc;
			thishover = thishover.replace(/(.*)_[0-9](\.[a-z]+)$/, "$1_1$2");

			el.hover(function(){
				el.attr('src', thishover);
			}, function(){
				el.attr('src', thissrc);
			}); // close hover

			// PRELOAD
			if($(options.preloadID).length == 0){
				// create it
				$('body').prepend('<div id="'+options.preloadID.replace(/[#.]/g, '')+'" style="display:none"></div>');
			}

			$(options.preloadID).append('<img src="'+thishover+'" />');

		}	// close el.length
	}); // close each

};

// #slidepanel

$.fn.slidepanel = function(options) {

	var options = $.extend({
		slideID : '.slider',
		speed_in : 500,
		speed_out : 500,
		hideOptions :	{
						top : '100%'
						}
	},options);

	return this.each(function(){

		var el = $(this);
		var slide = $(this).find(options.slideID);

		// auto positioning
		if(el.css('position')!='absolute'){
			el.css('position', 'relative');
		}

		// store original positions etc
		var originalcss = {
			top : slide.css('top'),
			left : slide.css('left')
			};

		function hide() {
			slide.stop().animate(options.hideOptions, {queue : false, duration : options.speed_out});

		}

		function show() {

			slide.stop().animate(originalcss, {queue : false, duration : options.speed_in});

		}

		hide();

 		el.hover(show, hide);

		slide.mouseover(sp);

		slide.children().mouseover(sp);
	});
};

////// Alpha PNG Background replacement...
///// note that options.color could supply a background image as well.

//// #alphabg

$.fn.alphabg = function(o) {

	var o = $.extend({
		opacity : 0.7,
		zIndex : '-1',
		color : '#000',
		fadeDuration : 0,
		onresize : 1,
		fade : 1,
		onresizeFade : 0
	},o);

	return this.each(function(){
		var $el = $(this);
		var grabber = Math.floor(Math.random()*10010923);
		$el.attr('alphabginstance', grabber);


		// auto positioning
		if($el.css('position')!='absolute'){
			$el.css('position', 'relative');
		}

		var thisz = $el.css('z-index');

		if(typeof(thisz) == 'undefined' || (thisz+'x').replace(/[^0-9]/g, '') == ''){
			$el.css('z-index', '1');
		}

		var w = $el.outerWidth()+'px';
 		var h = $el.outerHeight()+'px';

		var bghtml  = '<div class="bg" style="position:absolute; top:0; left:0; ';
			bghtml += 'width:'+w+'; height:'+h+'; z-index:'+o.zIndex+'; background:'+o.color+';"></div>';

		var g = '[alphabginstance="'+grabber+'"] ';

		if($(g+'> .bg').length == 0){
			$el.append(bghtml);
		} else {
			$(g+'> .bg').css({width : w, height : h});
		}

		if(o.fade){
			$(g+'> .bg').fadeTo(o.fadeDuration, o.opacity);
		}

		if(o.onresize){

			var o2 = {};
			for (var i in o){o2[i] = o[i];}

			o2.onresize = 0;

			$(window).bind('resize', function(){
				$el.alphabg(o2);
			});
		}

	});

};




// #rollfade
// apply fading effects to rollover
// check's custom class
$.fn.rollfade = function(options){

	var options = $.extend({
		checkClass : 'clicked',
		fadeIn : 1.0,
		fadeOut : 0.5, // also default fade
		duration : 300
	}, options);

	options.checkClass = options.checkClass.replace(/\./g, '');

	return this.each(function(){

		var el = $(this);
		if(!el.hasClass('.'+options.checkClass)){
			el.fadeTo(0, options.fadeOut);
		}

		el.hover(function(){
			if(el.hasClass('.'+options.checkClass) == false){
				el.stop().fadeTo(options.duration, options.fadeIn);
			}
		}, function(){
			if(el.hasClass(options.checkClass) == false){
				el.stop().fadeTo(options.duration, options.fadeOut);
			}
		});

	});

};



// #formhint
// helpful form field hint text
// clears on focus
$.fn.formhint = function(options){

	var options = $.extend({
	attr : 'title'
	}, options);

	return this.each(function(){
		// set value as title
		var el = $(this);

		if(el.val() == ''){
			el.val(el.attr(options.attr));

			el.focus(function(){
				if(el.val() == el.attr(options.attr)){
					el.val('');
				} else {
					el.select();
				}
			}); // close focus

			el.blur(function(){
				if(el.val() == ''){
					el.val(el.attr(options.attr));
				}
			}); // close blur
		} else { // close if)
			el.focus(function(){
			el.select();
		});

		}
	}); // close each

};

// #brandscroll
// notes: needs continuous mode
// needs work on onclick etc - passing $(this)
// needs support for multiple instances.

// example usage

//	 $(window).load(function(){
//		 $('#brandscroll').brandscroll();
//
//		 $('.right').brandscroll_button({
//			 el : '#brandscroll',
//			 direction : 'right'
//		 });
//
//		 $('.left').brandscroll_button({
//			 el : '#brandscroll'
//		 });
//	 });

// html markup
// <div id="brandscroll">
//	<div class="item">
//		<img src="/images/image.jpg" alt="" />
//	</div>
// </div>

// apply styles to #brandscroll and .item, as well as perhaps .left and .right
jc$.settings.brandscroll = [];
jc$.intervals.brandscroll = [];
jc$.timeouts.brandscroll = [];

$.fn.brandscroll = function(options){

	var options = $.extend({
		speed : 1000,
		stoponhover : true,
		onclick : '',
		onmouseover : '',
		onmouseout : '',
		autoplay : true,
		autoplayinterval : 2000,
		cycle : true,
		autoheight : true,
		itemspacing : 5,
		autocenteritems : true,
		force : 100,
		rewindspeed : 1900
	},options);

	return this.each(function(){
	if($(this).length>0){

		var el = $(this);

		// assign id and save to moveQueue
		var i = 'bs_'+Math.floor(Math.random()*10102030123);
		// this is used to add actions to queue :)

		el.attr('brandscrollInstance', i);

		// save settings
		jc$.settings.brandscroll[i] = options;

		// get items
		var items = el.children('.item');

		// empty el interior
 		el.children(':not(.item)').remove();

		// build
		el.wrapInner('<div class="viewport"></div>');
		var vp = el.children('.viewport');

		vp.wrapInner('<div class="universe"></div>');
		var us = vp.children('.universe');

		// force apply some el css
		if(el.css('position')!='absolute'){
			el.css('position', 'relative');
		}

		// force apply some vp css
		vp.css({
			'position' : 'relative',
			height : '100%',
			width : '100%',
			'z-index' : 1,
			overflow : 'hidden'
		});

		// insert a clear
		us.append('<div style="clear:both;"></div>');

		// style universe items
		items = us.children('.item');

		items.css({
			'float' : 'left',
			'margin-right' : options.itemspacing+'px'
		});

		// calculate universe width
		var us_width = 0;

		// also calculate max height
		var maxheight = 0;

		items.each(function(){
			var e = $(this);
			us_width += (e.outerWidth(true));
			var thisheight = e.outerHeight(true);
			if(thisheight > maxheight){maxheight=thisheight;}
		});

		// force apply some universe css
		us.css({
			'position' : 'absolute',
			top : '0px',
			left : '0px',
			height : '100%',
			'z-index' : 5,
			width : us_width+'px'
		});

		if(options.autoheight){
		 	var css = {height : maxheight+'px'};
			el.css(css);
			us.css(css);
			vp.css(css);
		}

		// do autocenter
		if(options.autocenteritems){

			items.each(function(){

				var e = $(this);
				if(e.outerHeight(true) < maxheight){
					var thistop = maxheight - e.outerHeight(true);
					thistop = thistop/2;

					e.css({
						'position' : 'relative',
						top : thistop+'px'
					});
				}

			});

		}

		// do autoplay
		if(options.autoplay){
			jc$.intervals.brandscroll[i] = setInterval(function(){
				el.brandscroll_move({
					force : options.force,
					cycle : options.cycle,
					i : i,
					speed : options.speed,
					rewindspeed : options.rewindspeed
				});
			}, options.autoplayinterval);

		}

		// do stop on hover
		if(options.stoponhover){
			items.hover(function(){
				el.brandscroll_pause({i:i});
			}, function(){
				el.brandscroll_resume({i:i});
			});
		}

		if(options.onclick!=''){
			items.click(function(){
				return options['onclick']();
			});
		}

		if(options.onmouseover!=''){
			items.mouseover(function(){
				return options['onmouseover']();
			});
		}

		if(options.onmouseout!=''){
			items.mouseout(function(){
				return options['onmouseout']();
			});
		}
	}
	});
};

// brandscroll animation event

$.fn.brandscroll_move = function(options){

	options = $.extend({
		force : '',
		cycle : '',
		i : '',
		speed : '',
		direction : 'right',
		rewindspeed : '',
		stopqueue : false
	}, options);

	return this.each(function(){
		// establish elements
		var el = $(this);
		var vp = el.children('.viewport');
		var us = vp.children('.universe');

		var i = options.i;

		if(i==''){
			i = el.attr('brandscrollInstance');
		}

		var s = jc$.settings.brandscroll[i];

		for (var c in options){
			if(options[c]==''){
				options[c]=s[c];
			}
		}

		// get width of universe
		var uswidth = us.outerWidth(true);

		// get viewport width
		var vpwidth = vp.outerWidth();

		// get current position
		var thisleft = us.position().left;

		// integify
		options.force = options.force-1+1;
		thisleft = thisleft-1+1;

		var speed = options.speed;

		if(options.direction=='right'){
			// get moveleft value
			var ml = thisleft-options.force;

			// cycle
			if(options.cycle){
				if(ml == (-(uswidth-vpwidth)-(options.force))) {
					// reset
					ml = 0;
					speed = options.rewindspeed;
				}
			}

			if((ml*-1)>uswidth-vpwidth){
				ml = -(uswidth-vpwidth);
			}

		} else {
			// move left
			// get moveleft value
			var ml = thisleft+options.force;

			// cycle
			if(options.cycle){
				if((ml*-1)==(-options.force)){
					ml = (uswidth-vpwidth);
					ml = ml*-1;
					speed = options.rewindspeed;
				}
			}
			// see if its greater than end.
			if(ml>0){
				ml = 0;
			}
		}

		ml = Math.floor(ml);

		if(options.stopqueue){
			us.stop(true);
		}

		us.animate({
			left : ml+'px'
		}, {queue : true, duration : speed});

		el.brandscroll_pause();

		var waitspeed = speed;
		if(speed==options.rewindspeed){
			waitspeed += (options.rewindspeed/2);
		}

		jc$.timeouts.brandscroll[i] = setTimeout(function(){
			el.brandscroll_resume();
		}, waitspeed);

	});

};


$.fn.brandscroll_pause = function(options){

	var options = $.extend({
		i : ''
	}, options);

	return this.each(function(){

		var el = $(this);
		var i = options.i;

		if(i==''){
			i = el.attr('brandscrollInstance');
		}

		var us = el.find('.universe');

		// we have enough info to re-start the
		// interval so we can just clear it here
		clearInterval(jc$.intervals.brandscroll[i]);
		clearTimeout(jc$.timeouts.brandscroll[i]);

	});

};

$.fn.brandscroll_resume = function(options){

	var options = $.extend({
		i : ''
	}, options);

	return this.each(function(){
		var el = $(this);
		var i = options.i;

		if(i==''){
			i = el.attr('brandscrollInstance');
		}

		var s = jc$.settings.brandscroll[i];

		// we will restart the interval from the saved settings
		if(s.autoplay){
			jc$.intervals.brandscroll[i] = setInterval(function(){
				el.brandscroll_move({
					force : s.force,
					cycle : s.cycle,
					i : i,
					speed : s.speed
				});
			}, s.autoplayinterval);
		}

	});
};

$.fn.brandscroll_button = function(opts){

	opts = $.extend({
		direction : 'right',
		el : '',
		force : '',
		stopqueue : true
	}, opts);

	this.each(function(){
		var options = $.extend(true, {}, opts);
		var el = $(this);

		if(options.el == ''){
			alert('Please provide the el option. This can be a normal jquery css reference to the brandscroll element.');
		}

		var e = $(options.el);
		var i = e.attr('brandscrollInstance');
		var s = jc$.settings.brandscroll[i];

		for (var c in options){
			options[c] = (options[c]=='')? s[c] : options[c];
		}

		el.click(function(){
			e.brandscroll_move(options);
			return false;
		});

	});

	return this;
};


// #bswap
$.fn.bswap = function(o){
	o = $.extend({
		template : '<img id="{thisid}" class="bswapped" src="{src}" alt="{value}" style="cursor:pointer;" />',
		rollfade : 1,
		rollfade_options : {fadeIn : 0.8, fadeOut : 1}
	}, o);

	return this.each(function(){

		var $el = $(this);
		var thisid = 'bswap_'+Math.floor(Math.random()*1023092);
		var html = o.template.replace('{thisid}', thisid);
			html = html.replace('{src}', $el.attr('src'));
			html = html.replace('{value}', $el.attr('value'));

		$el.after(html);
		var $img = $('#'+thisid);

		$img.click(function(){
			$el.trigger('click');
			if($el.attr('tagName').toLowerCase == 'a'){
				if(typeof($el.attr('href'))!='undefined'){
					window.location = $el.attr('href');
				}
			}
		});

		if(o.rollfade){
			$img.rollfade(o.rollfade_options);
		}

		$el.css({
			'position' : 'absolute',
			'left' : '-99999px',
			'width' : '50px',
			'visibility' : 'hidden'
		});

	});
};

// #findpr
// find the specified parent by tagname
$.fn.findpr = function(o){
	o = $.extend({
		tagName : 'li',
		limit : 5
	}, o);

	var $el = $(this);

	if($el.parent().attr('tagName').toLowerCase() ==o.tagName){
		var li = $el.parent();
	} else {
		var foundli = 0, p = $el.parent(), i =0;
		while(!foundli) {
			p = p.parent();
			if(p.attr('tagName').toLowerCase() == o.tagName){
				li = p;
				foundli = 1;
			}
			// self protection
			i++;
			if(i>o.limit){break;}
		}
	}

	return li;

};


// #syntheticHistory
// important to know this doesnt work for ie6, ie7
$.syntheticHistory = function(o){
	o = $.extend({
		interval : 100,
		fn : function(){}
	}, o);

	var lastClick = '';
	$('a[href^="#"]').each(function(){
		var $e = $(this);
		$e.bind('click.syntheticHistory', function(){
			lastClick = $e.attr('href');
		});
	});

	var hash = window.location.hash;
	// watch history
	var inverval = setInterval(function(){
		var newhash = window.location.hash;
		if (newhash!=hash){
			hash = newhash;

			if(lastClick!=hash){
				$('a[href="'+hash+'"]:first').trigger('click');
				o.fn(hash, lastClick);
			}
		}
	}, o.interval);

};


// #setOpac
// class of setOpac-57 = opacity of 57

jc$.timeouts.setOpac = [];
$.setOpac = function(o){

	o = $.extend({
		init : 1
	}, o);

	var setOpac = {
		// vars
		prefix : "setOpac",
		regexp : '',
		fadeDuration : 1,
		id : Math.floor(Math.random()*100010),

		// functions
		init : function(){
			clearTimeout(jc$.timeouts.setOpac[this.id]);
			var obj = this;

			this.regexp = new RegExp('.*'+this.prefix+"\-([0-9.]+).*");

			$('[class*="'+this.prefix+'"]').each(function(){
				var $e = $(this);
				var opacity = $e.attr('class');
				opacity = opacity.replace(obj.regexp, '$1');
				opacity = opacity / 100;

				$e.fadeTo(obj.fadeDuration, opacity);
			});

			return this;
		},

		destroy : function(){

			$('[class*="'+this.prefix+'"]').each(function(){
				var $e = $(this);
				$e.fadeTo(1,1);
			});

		},

		refresh : function () {

			this.destroy();
			jc$.timeouts.setOpac[this.id] = setTimeout(function(){
				this.init();
			}, this.fadeDuration);

		}
	};

	if(o.init){setOpac.init();}

	return setOpac;

};


// #stylesheet_swap
$.stylesheet_swap = function (o) {

	o = $.extend({
		init : 1
	}, o);

	var stylesheet = {
		stylesheet : $('#global-stylesheet'),
		selector : '#select-style',
		activeStyle : '',
		changeCallBack : '',

		init : function(){
			var obj = this;
			this.selector = $(this.selector);
			this.stylesheet = this.stylesheet;

			if(this.activeStyle!=''){
				this.change(this.activeStyle);
			}
			this.activeStyle = this.stylesheet.attr('href');

			this.selector.val(this.activeStyle).change(function(){
				var $e = $(this);
				obj.stylesheet.trigger('swapStyle');
				obj.change($e.val());
			});

			return this;
		},

		disable : function(){
			this.stylesheet.attr('disabled', true);
			return this;
		},

		enable : function(){
			this.stylesheet.removeAttr('disabled');
			return this;
		},

		change : function(url){
			this.stylesheet.attr('href', url);

			if(typeof(this.changeCallBack) != 'string' && typeof(this.changeCallBack) != 'undefined'){
				this.changeCallBack(url, this.stylesheet, this.activeStyle);
			}

		}
	};

	if(o.init){stylesheet.init();}

return stylesheet;

};

// #horzscroll
jc$.horzscroll = {};

$.horzscroll = function(init,o){
	var self = this;
	// vars

	self.$el = '';
	self.$us = '';
	self.$vp = '';
	self.$items = '';
	self.itemSelector = '.item';
	self.extraWidth = 0;
	self.id = 0;
	self.speed = 1000;
	self.rewindspeed = 2500;
	self.intervalSpeed = 2500;
	self.rewind = 1;
	self.force  = 300;
	self.easing = 'swing';
	self.autoplay = 0;
	self.autorefresh = 1;
	self.$next = '';
	self.$prev = '';
	self.createButtons = 1;
	self.callbacks = 	{
					onMove : '',
					afterMove : '',
					getWidth : '',
					refresh : '',
					afterInit : ''
					};
	self.templates = 	{
					vp : '<div class="vp"></div>',
					us : '<div class="us"></div>'
					};
	self.width = 0;
	self.uswidth = 0;
	self.usleft = 0;
	self.usmovestack = 0;

	self.intervals =	{

					};

	self.timeouts = {};

	// functions

	self.init = function(){

		self.$el = $(self.$el);

		self.$items = self.$el.find(self.itemSelector);

		// BUILD
		self.$vp = $(self.templates.vp).appendTo(self.$el);
		self.$us = $(self.templates.us).appendTo(self.$vp);

		self.$items.each(function(){
			self.$us.append(this);
		});

		self.updateItemHandle();
		self.getUsWidth();

		// CSS
		self.$vp.css({
			'position' : 'relative',
			'overflow' : 'hidden',
			'width' : '100%',
			'height' : '100%',
			'left' : '0px',
			'top' : '0px'
		});

		self.$us.css({
			'position' : 'absolute',
			'height' : '100%',
			'left' : '0px',
			'top' : '0px'
		});

		// SET
		self.getWidth();

		if(self.id==0){
			self.id = self.$el.jcID();
		}

		if(self.autoplay){
			self.move(self.force);
			self.intervals.autoplay = setInterval(function(){
				self.move(self.force);
			}, self.intervalSpeed);
		}

		if(self.createButtons){
			self.buttons();
		}

		if(self.autorefresh){
			$(window).bind('resize.horzscroll'+self.id, function(){
				if(self.autorefresh){
					clearTimeout(self.timeouts.autorefresh);
					self.timeouts.autorefresh = setTimeout(function(){
						self.refresh();
					}, 1000);
				}
			});
		}

		if(typeof(self.callbacks.afterInit)=='function'){
			self.callbacks.afterInit(self.usleft, -(self.uswidth - self.width), (self.force*-1), self.width, self.uswidth, self.$el);
		}
	};

	self.move = function(force){

		self.usleft = self.$us.position().left;

		if(isnull(force)){
			force = self.force;
		}

		force = force*-1;
		force = force + self.usleft;

		self.getWidth();

		var speed = self.speed;

		// get limit
		var limit = -(self.uswidth - self.width);

		// prevent moving too far
		if(force < limit){
			force = (self.rewind)?0:limit;
		}
		if (force > 0){
			
			force = (self.rewind)?limit:0;
		}

		// move it ja ja ja
		self.$us.stop(1).animate({
			left : force+'px'
		}, {duration : speed, easing : self.easing, complete : function(){

			self.usleft = self.$us.position().left;
			if(typeof(self.callbacks.aftermove)=='function'){
				self.callbacks.aftermove(self.usleft, limit, force, self.width, self.uswidth, self.$el);
			}

		}});

		if(typeof(self.callbacks.onmove)=='function') {
			self.callbacks.onmove(self.usleft, limit, force, self.width, self.uswidth, self.$el);
		}

	};

	self.buttons = function(){

		if(isnull(self.$next)){
			self.$next = self.$el.parent('.next');
		}
		if(isnull(self.$prev)){
			self.$prev = self.$el.parent('.prev');
		}

		self.$next = $(self.$next);
		self.$prev = $(self.$prev);

		self.$next.click(function(){
			self.move(self.force);
			return false;
		});

		self.$prev.click(function(){
			self.move(self.force*-1);
			return false;
		});

	};

	self.getWidth = function(){
		self.width = self.$vp.outerWidth();
		if(typeof(self.callbacks.getWidth)=='function'){
			self.callbacks.getWidth(self.width, self.uswidth, self.$items.length);
		}
	};

	self.getUsWidth = function(){
		self.uswidth = 0;
		self.$items.each(function(){
			self.uswidth += $(this).outerWidth(true);
		});
		self.$us.css({
			'width' : self.uswidth+'px'
		});
	};

	self.updateItemHandle = function(){
		self.$items = self.$el.find(self.itemSelector);
		self.$items.css({
			'float' : 'left'
		});
	}

	self.refresh = function(){
		self.updateItemHandle();
		self.getWidth();
		self.getUsWidth();
		if(typeof(self.callbacks.refresh)=='function'){
			var limit = -(self.uswidth - self.width);
			self.callbacks.refresh(self.usleft, limit, (self.force*-1), self.width, self.uswidth, self.$el);
		}
	}

	self.destroy = function(){
		self.$el.remove();
		self.clearIntervals();
		self.$el.html(self.$us.html());
		self.$el.unbind('*');
		$(window).unbind('resize.horzscroll'+self.id);
	};

	self.clearIntervals = function(){
		clearInterval(self.intervals.autoplay);
		clearTimeout(self.timeouts.autorefresh);
	};

	// merge vars with options
	self = $.extend(self, o);

	// init
	if(!isnull(init)){
		if(init){self.init();}
	} else {self.init();}

	return self;
};

$.fn.horzscroll = function(o, param2) {

	return this.each(function(){
		var $el = $(this);
		var id = $el.jcID();

		if(typeof(o)=='string'){
			switch(o.toLowerCase()){
				case 'destroy' :
				jc$.horzscroll[id].destroy();
				break;

				case 'refresh' :
				jc$.horzscroll[id].refresh();
				break;

				default :
				jc$.horzscroll[id][o.toLowerCase()](param2);
				break;
			}
		} else {
			if(isnull(o)){o = {};}
			o.$el = $el;
			o.id = id;
			jc$.horzscroll[id] = new $.horzscroll(1,o);
		}

	});

};

// #ajaxForm
(function(){
	var instances = {};
	var addMethod = '';

	$.ajaxForm = function(o, init){
		var self 	= this;

		if(isnull(init)){init = 1;}
		if(init){this.init(o);}

	};
	addMethod = $.ajaxForm.prototype;

	addMethod.init = function(o){
		this.instance	= '';
		this.data 		= {};
		this.ready		= 1;
		this.$			= '';
		this.getBy 		= '.ajax';
		this.url		= '';
		this.success	= function(){};

		if(isnull(o)){o = {};}
		$.extend(true, this, o);

		this.$ 						= $(this.$);
		this.instance 				= this.$.jcID();
		instances[this.instance]	= this;

		this.url					= this.$.attr('action');
	};

	addMethod.get = function(){
		var self 	= this;
		this.data 	= {};

		// get all data
		this.$.find(this.getBy).each(function(){
			var $el = $(this);

			var type 	= $el.attr('type');
			type 		= type.toLowerCase();

			var addToData = 1;

			switch(type){
				case 'checkbox':;
				case 'radio':
				if(!$el.is(':checked')){
					addToData = 0;
				}
				break;
			}

			if(addToData){
				self.data[$el.attr('name')] = $el.val();
			}
		});

		self.data.ajaxForm = true;

	};

	addMethod.post = function(){
		var self = this;
		self.get();
		$.post(self.url, self.data, self.success);
	};

	$.fn.ajaxForm = function(o){

		if(typeof(o)=='string'){
			return this.each(function(){
				var $el = $(this);
				return instances[$el.jcID()][o]();
			});
		} else {
			o 	=  $.extend({}, o);
			return this.each(function(){
				o.$ = this;
				return new $.ajaxForm(o);
			});
		}
	};
})();

// #swapKeys
String.prototype.swapKeys = function(keyPairs){
	var txt		= this,
		r		= '';

	for (var i in keyPairs) {
		r = new RegExp('{'+i+'}', 'g');
		txt = txt.replace(r, keyPairs[i]);
	}

	return txt;
};


// #dragMe
$.dragMe = function(o, $el){
	o = $.extend(true, {
		moveOnDrag	: 1,
		onDrag		: function($el, e){},
		dragging	: function(offset, event){},
		dragStop	: function($el){},
		grid		: 0,
		roundtype	: 'floor'
	}, o);

	var	cursor		= $el.css('cursor') || 'auto',
		offset		=	{};


	$el.bind('mousedown.object-dragging', function(e){
		// CONFIGURE
		var top = $el.position().top,
			left= $el.position().left;

		offset = {
			x : e.pageX-left,
			y : e.pageY-top
		};

		// BUILD
		$el.css('cursor', 'move').stop(1);
		$.dragMe.stopTextSelection();
		o.onDrag($el, e);

		// BIND
		$(document)	.bind('mousemove.object-dragging', function(event){
			var l = left	+(event.pageX - offset.x-left);
			var t = top		+(event.pageY - offset.y-top);

			if(o.grid>0){
				l = (Math[o.roundtype](l/o.grid)*o.grid);
				t = (Math[o.roundtype](t/o.grid)*o.grid);
			}

			if(o.moveOnDrag){
				$el.css({
					top		: t+'px',
					left	: l+'px'
				});
			}

			o.dragging(l, t, offset, event, $el);
		})
		.bind('mouseup.object-dragging', function(){
			$(document)
			.unbind('mousemove.object-dragging')
			.unbind('mouseup.object-dragging');

			$.dragMe.resumeTextSelection();
			$el.css('cursor', cursor);
			o.dragStop($el);
		});

		return false;
	});
};

$.fn.dragMe = function(opts){

	this.each(function(){
		var o = opts;

		if(typeof(o)=='string'){
			if(o=='destroy'){
				$(this).unbind('mousedown.object-dragging');
			}
		} else {
			o = $.extend(true, {}, opts);
			$.dragMe(o, $(this));
		}
		
	});

	return this;
};

$.dragMe.stopTextSelection = function(){
	// prevent selecting text when dragging
	$(document).bind('selectstart.object-dragging', function(){
		return false;
	});

	if($.browser.mozilla){
		$('body').css('MozUserSelect', 'none');
	}
	return true;
};


$.dragMe.resumeTextSelection = function(){
	$(document).unbind('selectstart.object-dragging');

	if($.browser.mozilla){
		$('body').css('MozUserSelect', 'auto');
	}
	return true;
};


$.dragMe.iedragimages = function(){

	if($.browser.msie){
		// IE
		document.ondragstart = function(){return false;};
	}

};


$.fn.getOuterWidth = function(){

	return (typeof window.getComputedStyle == 'function') ? Math.ceil(parseFloat(window.getComputedStyle(this.get(0), "").getPropertyValue("width"))) : this.outerWidth();

};



$.remoteImageDimensions = function (path, fn){
	var self	= this,
		img		= new Image();

	img.onload = function(){
		self.width = img.width;
		self.height= img.height;

		fn(img.width, img.height, img);


	};

	img.src = path;
};
