var localeInitStrings = [];
//var localeInitStrings =
	//[
	//{name:"logo",value:"<%=_("logo")%>"}
	//,{name:"logo-design",value:"<%=_("logo-design")%>"}
	//,{name:"animated-logo",value:"<%=_("animated-logo")%>"}
	//,{name:"Design-",value:"<%=_("Design-")%>"}
	//];

var localeStrings = {};

try {
var i;
//localeInitStrings located another .js
for (i=0;i<localeInitStrings.length;i++) {
	var o = localeInitStrings[i];
	localeStrings[o.name] = o.value;
};
} catch (e) {} // just carry on if can't init.  It'll work in English

function _(str) {
	return localeStrings[str] || str;
}
/*
//dont do this for now.
//simply use val function of hintedInput widget
//reasons if we use myjQuery for all code this will make extra comparison for each val() call
//if we use it only for hintedInput elements then its same as calling $(el).hintedInput("val")

var myjQuery = jQuery.sub();
var orig = jQuery.fn.val;
myjQuery.fn.val = function(newVal) {
	if (typeof newVal == 'undefined' && $(this).data('hintedInput') && !!$(this).hintedInput("isHintOn")) {
		//return empty string instead of hint value
		return "";
	}
	
	//call the original jQuery method
	return orig.apply( this, arguments );
};
*/
(function($){
	//hintedInput
	$.widget("ft.hintedInput", {
		options: {
			hintText:"Type your text here"
			,hintCss:{
				color:"#555"
			}
		}
		,_create: function() {
			if($(this.element).prop('type')!='text')
				return;
			//prepare css to use when hint is not displayed
			this._buildNoHintCss();
			
			$(this.element).bind('focus.hintedInput',{self:this},function(e) {
				e.data.self._hideHint();
			});
			$(this.element).bind('blur.hintedInput',{self:this},function(e) {
				e.data.self._showHint();
			});
			this._showHint();
		}
		,_buildNoHintCss: function(){
			var css = {};
			var el = $(this.element);
			$.each(this.options.hintCss,function(k,v){
				css[k] = el.css(k);
			});
			this.noHintCss = css;
		}
		,_hideHint:function(){
			if(this.hintOn){
				$(this.element).val("").css(this.noHintCss);
				this.hintOn = false;
			}
		}
		,_showHint:function(){
			if($(this.element).val() == ""){
				$(this.element).val(this.options.hintText).css(this.options.hintCss);
				this.hintOn = true;
			}
			else
				this.hintOn = false;
		}
		,isHintOn:function(){
			return this.hintOn;
		}
		,val:function(newVal){
			if(typeof newVal != 'undefined')
				return $(this.element).val(newVal);
			if(this.hintOn)
				return "";
			return $(this.element).val();
		}
		,destroy:function(){
			this.element
				.removeClass('hintedInput')
				.removeData('hintedInput')
				.unbind('.hintedInput');
			$(document).unbind('.hintedInput');
			$.Widget.prototype.destroy.apply(this,arguments);

		}
	});
})(jQuery);
var isIE6 = navigator.userAgent.toLowerCase().indexOf('msie 6') != -1;
var isIE7 = navigator.userAgent.toLowerCase().indexOf('msie 7') != -1;

var MODE_IMAGEBOT=1;
var APP_WEB="web";
var APP_CHROME="chrome";

var ft = ft || {};

if (!ft.dynamicForms) {
	ft.dynamicForms = {};
}


function DynamicForm(id,mode,app,updateImmediately,fthost) {
	this.id=id;
	this.mode=mode;
	this.app = app || APP_WEB;
	this.ftExtension=null;
	this.host = fthost;
	this.formChange=true;
	this.proxyFormId="proxyform-"+id;
	this.proxyForm= document.getElementById(this.proxyFormId);
	if (!this.proxyForm) {
		log("proxyform not found:"+this.proxyFormId);
	}
	//this.oldFormParams=""; //moved to updateHandler
	this.updateImmediately=updateImmediately;
	
	if (this.app == APP_CHROME) {
		this.host=this.host || "http://www.flamingtext.com";
	}
	
	this.docReady = false;
	
	this.registerChangeEvents();
	this.init();
	
	ft.dynamicForms[id] = this;
	this.test = function() {
		window.alert("this is dynamicform.test()");
		logger.info("ftExtension");
		logger.info(ftExtension);
		ftExtension.test();
		logger.info("called");
	};
}

DynamicForm.prototype.registerChangeEvents = function() {
	if (!isIE6) {
		var df = this;
		
		var changeFunction = function(evt){
			//console.log($(this).prop('type') + " " + evt.type + " event");
			var df = evt.data.df;
			
			if(df.docReady){
				//console.log("doc ready: call checkFormChange");
				//this will help not making too many unneccessary image requests when 2+ parameters change quickly
				setTimeout(function(){
					df.updateHandler.checkFormChange();
				},100);
			}
			else{
				df.updateImmediately = true;
				//console.log("doc NOT ready: call checkFormChange when ready");
				$(document).ready(function() {
					df.updateHandler.checkFormChange();
				});
			}
			//var str = $(this).attr('id')+":fired "+evt.type;
			//console.log(str);
		};
		
		//use live event so that we capture changes made before document.ready
		$(":input",$("#proxyform-"+df.id)).live('change', {df: df}, changeFunction);
		$('textarea,select,input:text',$("#proxyform-"+df.id)).live('keyup', {df: df}, changeFunction);
	}
}

DynamicForm.prototype.init = function() {
	var df = this;
	//when ready
	$(document).ready(function() {
		df.docReady = true;
		
		df.updateHandler = new UpdateHandler(df);
		df.updateHandler.init();
		
		setupBoxes();
		
		if (df.mode == MODE_IMAGEBOT) {
			var changeLogo = function(evt) {
				//window.alert("change:"+$(this)+":"+$(this).val()+":"+id);
				//window.alert("XX"+ "&text="+$("#"+id+"-text").val());
				ftExtension.showLogoPopup(df.id,"script="+$(this).val()+"&text="+$("#"+df.id+"-text").val());
			}
			var initChangeLogo = function() {
				$("#"+df.id+"-changeLogo").change(changeLogo);
			};
			initChangeLogo();
			

		}
		
		if(!isIE6 && df.updateImmediately){
			df.updateHandler.checkFormChange();
		}
		//console.log("id:"+"#proxyform-"+df.id+"selector:"+$('input:text',$("#proxyform-"+df.id)).attr('id'));
	});
};


function UpdateHandler(df) {
	//log ("update handler");
	var ret= {
		dynamicForm: df,
		id: df.id,
		mode: df.mode, // 0 for standard, 1 for svg-edit
		currentHttpRequest: null,
		working: false,
		originalImageSrc: null,
		logoPreviewDivId: "logoPreview-"+df.id,
		imageId: "logoImage-"+df.id,
		statusImageId: "statusImage-"+df.id,
		statusElement: null,
		errorStatusId: "errorStatus-"+df.id,
		imageNoteId: "logoImageNote-"+df.id,
		imageElement: null,
		maxHttpRequestTime: 20000, //timeout for ajax call
		oldFormParams:"",
		currentFormParams:"",
		params:"",
		
		init: function() {
			this.statusElement =  document.getElementById(this.statusImageId);
			this.imageNote = $("#"+this.imageNoteId);
			this.fullSizePreview = false;
			
			if (!this.statusElement) {
				log ("unable to find status element:"+this.statusImageId);
			}
			if (this.mode != MODE_IMAGEBOT) {
				this.imageElement =  document.getElementById(this.imageId);
				if (this.imageElement) {
					var me = this;
					this.imageElement.onload=function() {me.imageLoaded();};
					this.imageElement.onerror=function() {me.imageErrored();};
					this.originalImageSrc = this.imageElement.src;
				} else {
					log ("unable to find image element:"+this.imageId);
				}
			}
			
			
			this.logoPreviewDiv = document.getElementById(this.logoPreviewDivId);
			this._initScroll();
		},

		_initScroll: function(){
			var ie = navigator.appVersion.indexOf("MSIE")!=-1;
			var ieVersion = parseFloat(navigator.appVersion.split("MSIE")[1]);
			
			//does not work for ie7
			if(!ie || ieVersion>=8){
				var top = $(this.logoPreviewDiv).offset().top - parseFloat($(this.logoPreviewDiv).css('marginTop').replace(/auto/, 0));
				$(window).bind('scroll.ft',{self:this},function (e) {
					var updateHandler = e.data.self;
					//if we are in a scalled mode
					if(!updateHandler.fullSizePreview){
						var preview = $(updateHandler.logoPreviewDiv);
						var winY = $(this).scrollTop();
						if (winY >= top) {
							var w = $(".logoPreviewWrapper").outerWidth();
							preview.addClass('logoPreviewFixed');
							preview.css({width:w-2});
						} else{
							preview.removeClass('logoPreviewFixed');
						}
					}
					return false;
				});
				$(window).trigger('scroll.ft');//in case we go away and click back
				this._scaleImage();
			}
			
		},
		updateImage: function(src,params,data) {
			//log("updateImage:mode="+this.mode);
			if (this.imageElement)
				this.imageElement.src = src;
 			else {
				if (this.mode == MODE_IMAGEBOT) {
					updateFtLogo(this.id,src,params,data);
				}
				this.clearStatus();
 				this.working=false;
				if (this.statusElement)
 					this.statusElement.src="http://cdn1.ftimg.com/x.gif";
			}
		},

		failed: function(str) {
			this.setStatus(str);
			log(str);
			this.working=false;
			this.statusElement.src="http://cdn1.ftimg.com/fail.gif"
		},

		imageLoaded: function() {
			//log("image loaded");
			this._scaleImage();
 			this.clearStatus();
 			this.working=false;
 			this.statusElement.src="http://cdn1.ftimg.com/x.gif";
		},
		//scale does both full size as well as scaling depending on the mode
		//this.fullSizePreview - true if mode is "full size image preview", false if mode is "scaled image preview"
		_scaleImage: function(){
			this.imageNote.html("");
			$(this.imageElement).width('auto');
			$(this.imageElement).height('auto');

			//add a note
			if($(this.imageElement).width() > 560 || $(this.imageElement).height() > 200){
				this._addFullSizeNote(!this.fullSizePreview);
			}

			//scaled preview mode
			if(!this.fullSizePreview){
				var scale = 1, scaleW = 1, scaleH = 1;
				var w = $(this.imageElement).width();
				var h = $(this.imageElement).height();
				
				if(w > 560)
					scaleW = 560/w;
				if(h > 200)
					scaleH = 200/h;
				scale = Math.min(1,scaleW,scaleH);
				if(scale<1){
					$(this.imageElement).width(w*scale);
					$(this.imageElement).height(h*scale);
				}
				
				$(window).trigger('scroll.ft');
			}
			else{
				$(this.logoPreviewDiv).removeClass('logoPreviewFixed');
			}
			//set height of the wrapper to be same as previewDiv, so that it looks good when scrolling
			$(".logoPreviewWrapper").height($(this.logoPreviewDiv).height());
		}
		,_addFullSizeNote: function(fullsize){
			var self = this;
			var alert;
			
			if(fullsize){
				alert = $("<div><img src=\"http://cdn1.ftimg.com/images/alert.png\"/> Note: Preview image has been scaled. </div>");
			}
			else{
				alert = $("<div><img src=\"http://cdn1.ftimg.com/images/alert.png\"/> Note: Image shown at full size. </div>");
			}
			var link = $("<a href=\"#\"> Toggle preview size</a>");
			link.bind('click.ft',{df:self, fullsize:fullsize}, function(e){
				e.preventDefault();
				var df = e.data.df;
				df.fullSizePreview = fullsize;
				df._scaleImage();
			});
			this.imageNote.html("");
			this.imageNote.append(alert);
			this.imageNote.append(link);
		}
		,ready: function() {
			return !this.working;
		},
		// Not supportted in IE6
		abortCurrentHttpRequest: function() {
			this.working=false;
			if (!isIE6 && this.currentHttpRequest) this.currentHttpRequest.abort();
		},
		setStatus: function(str) {
			var xx = document.getElementById(this.errorStatusId);
			if (xx)
				xx.innerHTML="<font size='-1' color='red'>"+str+"</font>"
			//else log("no errorStatus div");
		},

		imageErrored:  function() {
 			this.setStatus("Image Errored");
 			this.working=false;
 			this.statusElement.src="http://cdn1.ftimg.com/fail.gif";
		},

		clearStatus: function() {
			var xx = document.getElementById(this.errorStatusId);
			if (xx)
				xx.innerHTML="";
		},

		setWorking: function(val) {
			this.working=val;
		},
		
		checkFormChange: function(){
			//log("Caller:"+arguments.callee.caller.toString());
			var reqAvail = this._isHttpRequestAvailable();
			var imageOutdated = this._isImageOutdated();
			//console.log("_checkFrame:reqAvail="+reqAvail+";imageOutdated="+imageOutdated);
			if(reqAvail && imageOutdated){
				this._getNewImage();
				return true;
			}
			return false;
		
		},
		_isHttpRequestAvailable: function (){			
			var ms = this.httpRequestStartTime ? ((new Date().getTime())-this.httpRequestStartTime) : 0;
			//log("ms="+ms);
			if(!this.working || ms >= this.maxHttpRequestTime){
				return true;
			}
			return false;
		},
		_getFtHost: function() {
			if (df.host) {
				return df.host;
			}
			var ret;
			ret='http://'+document.location.hostname;
			if(document.location.port!=80){
				ret+=":"+document.location.port;
			}
			return ret;
		},
		_isImageOutdated: function (){
			this.currentFormParams = this._getFtHost();
			this.currentFormParams+='/net-fu/image_output.cgi?';
			this.params=buildParams(df.proxyForm,{},df.id+"-");
			this.currentFormParams += this.params + 'imageoutput=true';
			if (this.mode == MODE_IMAGEBOT) {
				this.currentFormParams += '&_dataurl=true';
			}
			
			//console.log("this.currentFormParams="+this.currentFormParams+";this.oldFormParams="+this.oldFormParams+";df.updateImmediately"+df.updateImmediately);
			if(this.currentFormParams != this.oldFormParams){
				return true;
			}
			return false;
		},
		_getNewImage: function() {
			var updateHandler=this;
			// ray: only one http request at a time - so we don't need worry about async image update problem any more
			if (!isIE6 && this.currentHttpRequest) this.currentHttpRequest.abort();
			//TODO: remove this
			//currently happens on ie9 in imagebot when logo options are opened in properties panel and change is triggered for the first time
			if(this.currentFormParams.indexOf('script=')==-1)
				return;
			this.currentHttpRequest =$.ajax({
				//type:"get",
				url:updateHandler.currentFormParams,
				cache:false,
				//async: true, //needed?
				dataType: "json",
				beforeSend: function(req){
					req.updateHandler=updateHandler;
					req.params=updateHandler.params;
					req.updateHandler.setWorking(true);
					req.updateHandler.statusElement.src="http://cdn1.ftimg.com/running.gif";
					req.updateHandler.clearStatus();
					req.updateHandler.oldFormParams=updateHandler.currentFormParams;
				},
				success: function (json_imgObject, textStatus, req) {
					req.updateHandler.setWorking(false);
					//if something changed while this request was processing we need to generate new image and dont update preview
					if(!req.updateHandler.checkFormChange()){
						if (json_imgObject.src) {
							//log("src:"+json_imgObject.src);
							req.updateHandler.updateImage(json_imgObject.src,req.params,json_imgObject.data);
						} else if (json_imgObject.error) {
							req.updateHandler.failed(json_imgObject.error);
						} else {
							req.updateHandler.failed("bad response from server");
						}
					}
				},
				error: function(req,textStatus) {
					//if (req.status) {
						log("error:"+req.status+":"+req.responseText);
						req.updateHandler.failed("http error:"+req.status);
					//}
				}
			});
		}
		

	};
	//log ("done update handler");
	return ret;

}

String.prototype.startsWith = function(str)
{return (this.match("^"+str)==str)};

function log(msg) {
	setTimeout(function() {
		throw new Error(msg);
	}, 0);
}
function logProperties(msg,obj) {
for (var i=0; i < obj.length;i++) {
	element = obj[i];
	name=element.name;
	value= element.value;
	log(msg+":"+name+"="+value);
}
}


function setupBoxes() {
	//log("setup boxes");
	$(".box_title_link, .group_title").find('a').click(function(e){
		e.preventDefault();
	});
	//show/hide based on if we have 'active' class on the title
	$(".box_inner, .box_group").each(function(){
		var isActive = $(this).parent().find(".box_title_link, .group_title").eq(0).hasClass('active');
		if(isActive)
			$(this).show();
		else
			$(this).hide();
	});
	//hide summary for now
	$(".box_summary").hide();
	
	//click handler
	$(".box_title_link, .group_title").click(function(){
		var fn = function(p,hidden){
			p.toggleClass("active");
			var isActive = p.hasClass('active');
			if(isActive)
				p.find('img').prop('src', "http://cdn1.ftimg.com/images/minus.png");
			else
				p.find('img').prop('src', "http://cdn1.ftimg.com/images/plus.png");
			//need to find closest .box_title now since .box_title_link is a child of it
			if(hidden){//for other frames in animator set css because slideToggle does not work when in hidden div
				if(isActive)
					p.closest(".box_title, .group_title").next().css("display","block");
				else
					p.closest(".box_title, .group_title").next().css("display","none");
			}
			else
				p.closest(".box_title, .group_title").next().slideToggle("fast");
		}
		var p = $(this).closest(".box_title_link, .group_title");
		fn(p);
		var isActive = p.hasClass('active');
	
		//if we on animator page
		var curFrame = $("#currentFrameId").length? parseInt($("#currentFrameId").val()) : false;
		if(typeof(curFrame)=='number'){
			var classList = p.attr('class').split(/\s+/);
			var clazz = undefined;
			$.each( classList, function(i, item){
				if (item.indexOf('ft_') == 0) {
					clazz=item;
					return false;
				}
			});
			if(clazz){
				var otherFrames=$("."+clazz).not(p).filter(function(i){
					if(isActive)
						return !$(this).hasClass('active');
					else
						return $(this).hasClass('active');
				});
				$.each(otherFrames,function(i,f){
					fn($(f), true);
				});
			}
		}
	});
}
//el - a parrent element withing which to take parameters, can be a form or a div(in case for animator)
//exclude - an object with names to be excluded 
//eg exclude = {url:1, msSleep:1};
//replaceParam - sometimes we want to strip something from param name, eg "frame0", or "frame\d", ie can use regex here
//retruns params with & at the end, as most of the time we need it anyway

function buildParams(el, exclude, replaceParam){
	var params = "";
	var inputs = $(":input", $(el)).filter(function(index){
		return !exclude[$(this).attr('name')];
	});//find all inputs within el and filter them
	
	$.each(inputs,function(i,v){
		var name = $(v).attr('name');
		var value = $(v).val();
		var add=true;

		if (name && name !=""){
		 	if(replaceParam){
				var re = new RegExp(replaceParam);
				name=name.replace(re,"");
			}
			if (name == "ext")
				value="png";
			else if (name == "extAnim")
				value="gif";
			else if ($(v).prop('type')=="checkbox") {
				value = $(v).prop('checked')?"on":"off";
			}
			else if ($(v).prop('type')=="radio") {
				if (!$(v).prop('checked'))
					add=false;
			}
			if (add)
				params+=name+"="+encodeURIComponent(value)+"&";
			}
	});
	return params;
}
//$(document).ready(setupBoxes);
function dcf(fn, fni) {
window.setTimeout('cf("'+fn+'","'+fni+'");',50);
}
function cf(fn,fni) {
var y="";
n=document.getElementById(fn);
x=n.value;
for(i=0;i<x.length;i++){
 if(x.charAt(i)==' ')y=y+'+';
 else y=y+x.charAt(i);
}

var previewW = (typeof(window.dontUseMeAskCameron)!='undefined')? 140 : 330;
var previewH = (typeof(window.dontUseMeAskCameron)!='undefined')? 32 : 75;

if(document.images)if (document.images[n])document.images[n].src='http://cdn1.ftimg.com/fonts/preview/'+previewW+'x'+previewH+'/'+y+'.png';
else document.getElementById(fni).src ='http://cdn1.ftimg.com/fonts/preview/'+previewW+'x'+previewH+'/'+y+'.png';
}
;

var FontsManager = function(opts){
	var queue = [];
	var count = 0;
	var defaults = {
		maxCalls:5
	};
	var options = $.extend({},defaults,opts);
	var isReady = function(){
		return count<options.maxCalls;
	};
	this.callCompleted = function(id){
		count--;
		queue[id]=undefined;
		setTimeout(function(){
			if(isReady()){
				//run from the beginning
				var i=0;
				while(i<queue.length && typeof(queue[i])=='undefined')
					i++;
				if(i<queue.length){
					queue[i]();
				}
				//setTimeout(function(){queue.shift()();},0);
			}
		},10);
		//console.log('complete:'+count+";"+queue.length);
	};
	
	this.run = function(id,fn){
		var runFn = function(){
			count++;
			fn();
		};
		if(isReady())
			runFn();
		else
			queue[id] = runFn;//overwrite with latest
		//console.log('run:'+count+";"+queue.length);
	};
};

(function($){
	//fontManager
	$.widget("ft.fontmanager", {
		options: {
			idPrepend: "font_"
			,oldvalue: null
			,statusImageValue: "http://cdn1.ftimg.com/x.gif"
			,loadingImg: "http://cdn1.ftimg.com/running.gif"
			,errorMessageValue: null
			,url: ''
			,disabled: false
			,maxHttpRequestTime: 20000
			,gettingNewImageLabel: ""//Getting new image
			,inputs:[]
			,conditionalInputs:{
				"script":{
					"banner":{colorTextR:0,colorTextG:0,colorTextB:204,sunkenText:false,textMode:1,textBorder:0,halignText:0,valignText:0}
					,"plain-logo":{colorTextR:0,colorTextG:0,colorTextB:204}
				}
			}
			,getImgOnInit: false
			,defaultText:"abc"
			,fontname:""
			,fontsManager:undefined
		},
		
		_create: function() {
			this._initFontManager();
		},
		
		_initFontManager: function(){
			var o = this.options;

			this.statusDiv = this._initSiblingsDiv("statusDiv", "fontStatusMessage");
			this.errorsDiv = this._initSiblingsDiv("errorsDiv", "fontErrorsMessage");		
			this.imageLoaded = true;
			this.working = false;
			
			$(this.widget()).bind('fontChanged',{self:this}, function(ev){ev.data.self._checkFrame();});
			
			this._initInputs();
			
			
			this._registerChangeEvents();
			this._initPreviewImage();//calls this._checkFrame();
		},
		_initInputs: function(clazz){
			var self = this;
			var o = this.options;
			this.inputs = $([]);
			$.each(o.inputs, function(i,v){
				var jq = $(v);
				if(jq.length)
					self.inputs = self.inputs.add(jq);
			});
		},
		_initSiblingsDiv: function(id,clazz){
			var ret = $(this.element).siblings(clazz);
			if(!ret.length){
				ret = $("<div id=\""+this.options.idPrepend+id+"\" class=\""+clazz+"\"></div>");
				$(this.element).closest('div').append(ret);
			}
			return ret;
		},
		_registerChangeEvents: function (){
			var self = this;
			this.fontmanagerCount = $(":ft-fontmanager").length;
			
			$.each(this.inputs, function(i,v){
				self._registerChangeEvent($(v));
			});
			//if it is a select
			this.inputs.filter('select').each(function(){
				self._registerKeyUpEvent($(this));
			});
			
		},
		_registerChangeEvent: function (el){
			var o = this.options;
			
			el.bind('change.font.changed',{fm:this, fm_count:this.fontmanagerCount}, function(event){
				if(o.disabled)
					return false;

				var fm = event.data.fm;
				
				if(o.fontsManager){
					//console.log('change - run now');
					o.fontsManager.run(event.data.fm_count, function(){$(fm.widget()).trigger('fontChanged');});
				}
				else{
					var n = parseInt($(this).attr("delaycheck")) + event.data.fm_count*100;
					if(!n)
						n = event.data.fm_count*100;
					//totalcalls++;
					//console.log("fm:"+event.data.fm_count+";n="+n+";calls="+totalcalls);
					if(n){
						setTimeout(function(){$(fm.widget()).trigger('fontChanged');},n);
					}
					else{
						$(fm.widget()).trigger('fontChanged');
					}
				}
				//fm._devChange(this);
			});
			
			//for some types we want other than basic 'change' handler
			var type = el.prop('type');
			switch (type){
				case "textarea":
				case "text":
					//console.log($(el).attr('id') + " registering keypress event");
					this._registerKeyUpEvent(el);
					break;
			}			
		},
		_registerKeyUpEvent: function (el){
			var o = this.options;
			el.unbind('keyup.font.changed').bind('keyup.font.changed', {fm:this}, function(event){
				//log("key pressed"+$(this).attr('id'));
				if(o.disabled)
					return false;
				//setTimeout(function(){$(event.data.fm.widget()).trigger('fontChanged');}, event.data.fm_count*50);
				//event.data.fm._devChange(this);
				
				//this is needed because we bind multiple keyups to this but only the last one executes
				$(this).trigger('change.font.changed');
			});			
		},

		_initPreviewImage: function(){
			var o = this.options;
			var self = this;
			this.previewImage = $(this.element);
			this.statusImage = $("#"+this.options.idPrepend+"statusImage");
			//this.errorMessage = $("#"+this.options.idPrepend+"errorMessage");
			
			if (this.previewImage.length){
				this.previewImage.unbind("load error").bind({
					load: function() {
						self._imageLoaded();
					},
					error: function() {
						self._imageErrored();
					}
				});
				if(o.url)
					this._setUrl(o.url);
			}
			
			if (this.statusImage.length){
				this.statusImage.prop('src',o.statusImageValue);
			}
			//if (this.errorMessage.length)
			//	this.errorMessage.html(o.errorMessageValue);
			
			if(o.getImgOnInit){
				//this._checkFrame();
				if(o.fontsManager)
					o.fontsManager.run(this.fontmanagerCount,function(){$(self.element).trigger('fontChanged');});
				else
					$(this.element).trigger('fontChanged');
			}
				
		},
		
		_imageLoaded: function (){
			var o = this.options;
			this._clearStatus();
			this.imageLoaded=true;
			o.statusImageValue = "http://cdn1.ftimg.com/x.gif";
			if (this.statusImage.length)
				this.statusImage.prop('src',o.statusImageValue);
		},
		_clearStatus: function (){
			this.options.errorMessageValue = "";
			//if (this.errorMessage.length)
			//	this.errorMessage.html(this.options.errorMessageValue);
			if (this.errorsDiv.length)
				this.errorsDiv.html(this.options.errorMessageValue).css({'display':'none'});
		},
		_setStatus: function (str){
			this.options.errorMessageValue = str;
			//if (this.errorMessage.length)
			//	this.errorMessage.html("<font size='-1' color='red'>"+this.options.errorMessageValue+"</font>");
			if (this.errorsDiv.length)
				this.errorsDiv.html("<font size='-1' color='red'>"+">>> " + this.options.errorMessageValue+"</font>").css({'display':'block'});
		},
		_failed: function (str){
			var o = this.options;
			this._setStatus(str);
			this.imageLoaded=true;
			o.statusImageValue = "http://cdn1.ftimg.com/fail.gif";
			if (this.statusImage.length)
				this.statusImage.prop('src',o.statusImageValue);
		},
		_imageErrored: function (str){
			var o = this.options;
			this._setStatus("Image Errored: " + str);
			this.imageLoaded=true;
			o.statusImageValue = "http://cdn1.ftimg.com/fail.gif";
			if (this.statusImage.length)
				this.statusImage.prop('src',o.statusImageValue);
		},
		_outdated: function(){
			var reqAvail = this._isHttpRequestAvailable();
			var imageOutdated = this._isImageOutdated();
			return (reqAvail && imageOutdated);
		},
		//return true if new image is generated, flase otherwise
		_checkFrame: function (verification_call){
			if(this._outdated()){
				//console.log("reqAvail && imageOutdated");
				this._getNewImage(verification_call);
				return true;
			}
			else if(this.options.fontsManager && !verification_call)
				this.options.fontsManager.callCompleted(this.fontmanagerCount);
			
			return false;
		},		
		_isHttpRequestAvailable: function (){			
			var ms = this.httpRequestStartTime ? ((new Date().getTime())-this.httpRequestStartTime) : 0;
			//log("ms="+ms);
			if(!this.working || ms >= this.options.maxHttpRequestTime){
				return true;
			}
			return false;
		},
		_isImageOutdated: function (){
			var o = this.options;
			this.currentParams = "/net-fu/image_output.cgi?";
			this.currentParams += this._buildParams();
			this.currentParams += "fontname="+encodeURIComponent(this.options.fontname)+"&"
			this.currentParams += "imageoutput=true";
			//this.currentParams = this._buildParams();
			//log("currentParams:"+this.currentParams);
			//log("oldvalue     :"+this.options.oldvalue);
			if(this.currentParams != this.options.oldvalue){
				return true;
			}
			return false;
		},
		_buildParams:function(){
			var self = this;
			var params = "";
			var replaceParam = this.options.idPrepend;
			$.each(this.inputs,function(i,v){
				var name = $(v).attr('name');
				var value = $(v).val();
				var add=true;

				if (name && name !=""){
				 	if(replaceParam){
						var re = new RegExp(replaceParam);
						name=name.replace(re,"");
					}
					if (name == "ext")
						value="png";
					else if (name == "extAnim")
						value="gif";
					else if ($(v).prop('type')=="checkbox") {
						value = $(v).prop('checked')?"on":"off";
					}
					else if ($(v).prop('type')=="radio") {
						if (!$(v).prop('checked'))
							add=false;
					}
					if (add)
						if(name == "text" && value=='')
							value = self.options.defaultText;
						params+=name+"="+encodeURIComponent(value);
						params+="&textBorder=0";
						params+="&"+self._processConditionalInputs(name,value);
					}
			});
			return params;
		},
		_processConditionalInputs:function(name, value){
			var ret = "";
			
			if(this.options.conditionalInputs[name]){
				var conditionalValues = this.options.conditionalInputs[name];
				if (conditionalValues[value]){
					var inputs = conditionalValues[value];
					$.each(inputs, function(inp,val){
						ret+=inp+"="+encodeURIComponent(val)+"&";
					});
				}
			}
			return ret;
		},
		_getNewImage: function (verification_call){
			var self = this;
			var o = this.options;
			//log("getting new image");
			
			var jqxhr = $.ajax({type:"get",
				url:this.currentParams,
				async: true,
				beforeSend: function(req){
					self.imageLoaded=false;
					self._setWorking(true);
					self.httpRequestStartTime = new Date().getTime();
				},
				timeout:o.maxHttpRequestTime,
				cache:false,
				dataType: "json",
				success: function (json_imgObject, textStatus, req) {
					self._setWorking(false);
					//console.log("getNewImage");
					//if something changed while this request was processing we need to generate new image and dont update preview
					if(!self._checkFrame(true)){
						if (json_imgObject.src) {
							self.options.url=json_imgObject.src;
							self._setUrl(self.options.url);
						} else if (json_imgObject.error) {
							self._failed(json_imgObject.error);
						} else {
							self._failed("bad response from server");
						}
					}
				},
				error: function(req,textStatus,exc) {
					self._setWorking(false);
					//console.log("error:"+textStatus+":"+exc);
					self._failed("error:"+textStatus);
				}
			});
			if(!verification_call && o.fontsManager){
				jqxhr.always(function(){o.fontsManager.callCompleted(this.fontmanagerCount);});
			}
			
			
			o.statusImageValue = o.loadingImg;
			if(this.statusImage.length){
				this.statusImage.prop("src", o.statusImageValue);
			}
			
			this._clearStatus();
			o.oldvalue=this.currentParams;
		},
		_setWorking: function (isWorking){
			var o = this.options;
			//url is no longer valid
			if(isWorking){
				this.working = true;
				this.statusDiv.html(o.gettingNewImageLabel).css({'display':'block'});
			}
			else{
				this.working = false;
				this.statusDiv.html("").css({'display':'none'});
			}		
		},
		_setUrl: function (value){
			var o = this.options;
			o.url = value;
			if(this.previewImage.length)
				this.previewImage.prop("src", o.url);
		},

		
		_setOption: function( key, value ) {
			$.Widget.prototype._setOption.apply( this, arguments );
			if(key=="url"){
				this._setUrl(value);
			}
		},

		hasError: function(){
			if(this.errorsDiv.html()!="")
				return true;
			return false;
		},
		recheckFont: function(){
			this.options.oldvalue = null;
			this._checkFrame();
		}
	});

})(jQuery);

$(document).ready(function(){
	//Set a cookie to remember number of fonts per page on page refresh
	$(".ft-font-controls-drop-down").show();
	$(".ft-font-controls").find("select").bind('change',function(){
		var fontsPp = $(this).val();
		$.cookie('fontsPp', null);
		var domain = document.domain;
		var pos = domain.indexOf('flamingtext');
		if (pos > -1)
		{
		domain = domain.substring(pos);
		}
		else{domain = 'flamingtext.com'}
		$.cookie('fontsPp', fontsPp, {path: '/', domain: '.' + domain});
		$(this).closest('form').submit();
	});
	//Set a cookie to remember the preview string to use
	$('#font_text').bind('change',function(){
		var previewString = $(this).val();
		$.cookie('previewString', null);
		var domain = document.domain;
		var pos = domain.indexOf('flamingtext');
		if (pos > -1)
			domain = domain.substring(pos);
		else
			domain = 'flamingtext.com';
		$.cookie('previewString', escape(previewString), {path: '/', domain: '.' + domain});
	});
	
	if($('#font_text').length){
		var font_text = $.cookie('previewString');
		if(font_text)
			$('#font_text').val(unescape(font_text));
	}
	
	$(".ft-font-specific-logo-suggestion-img").bind('load',function(){
		
		$(this).siblings(".ft-font-specific-loadingDiv").remove();
	});
	
	$(".ft-font-preview-size").find('a').click(function(e){e.preventDefault();});
});

function dcp(pn, pni) {
window.setTimeout('cp("'+pn+'","'+pni+'");',50);
}
function cp(pn,pni) {
n=document.getElementById(pn);
x=n.options[n.selectedIndex].value;
if(document.images){
r='';
for(i=0;i<x.length;i++){
c=x.charAt(i);
if(c==' ')r+='_';
else if(c=='(')r+='_';
else if(c==')')r+='_';
else if(c=='$')r+='_';
else if(c=='#')r+='_';
else if(c=='?')r+='_';
else if(c=='%%')r+='_';
else if(c=='&')r+='_';
else if(c=='\'')r+='_';
else if(c=='+')r+='_';
else r+=c;
}
var previewW = (typeof(window.dontUseMeAskCameron)!='undefined')? 140 : 167;
var previewH = (typeof(window.dontUseMeAskCameron)!='undefined')? 28 : 28;
document.images[pni].src='http://cdn1.ftimg.com/images/patterns/'+previewW+'x'+previewH+'/'+r+'.png';
}}
;
function hidden_cp(pn,pni) {
	n=document.getElementById(pn);
	x=n.value;
	if(document.images){
		r='';
		for(i=0;i<x.length;i++){
			c=x.charAt(i);
			if(c==' ')r+='_';
			else if(c=='(')r+='_';
			else if(c==')')r+='_';
			else if(c=='$')r+='_';
			else if(c=='#')r+='_';
			else if(c=='?')r+='_';
			else if(c=='%%')r+='_';
			else if(c=='&')r+='_';
			else if(c=='\'')r+='_';
			else if(c=='+')r+='_';
			else r+=c;
		}
		var previewW = (typeof(window.dontUseMeAskCameron)!='undefined')? 140 : 167;
		var previewH = (typeof(window.dontUseMeAskCameron)!='undefined')? 28 : 28;
		document.images[pni].src='http://cdn1.ftimg.com/images/patterns/'+previewW+'x'+previewH+'/'+r+'.png';
	}
}
function dcg(gn, gni) {
window.setTimeout('cg("'+gn+'","'+gni+'");',50);
}
function cg(gn,gni) {
n=document.getElementById(gn);
x=n.options[n.selectedIndex].value;
if(document.images){
r='';
for(i=0;i<x.length;i++){
c=x.charAt(i);
if(c==' ')r+='_';
else if(c=='(')r+='_';
else if(c==')')r+='_';
else if(c=='$')r+='_';
else if(c=='#')r+='_';
else if(c=='?')r+='_';
else if(c=='%%')r+='_';
else if(c=='&')r+='_';
else if(c=='\'')r+='_';
else if(c=='+')r+='_';
else r+=c;
}

var previewW = (typeof(window.dontUseMeAskCameron)!='undefined')? 140 : 167;
var previewH = (typeof(window.dontUseMeAskCameron)!='undefined')? 28 : 28;
document.images[gni].src='http://cdn1.ftimg.com/images/gradients/'+previewW+'x'+previewH+'/'+r+'.png';
}}
;
function hidden_cg(gn,gni) {
	n=document.getElementById(gn);
	x=n.value;
	if(document.images){
		r='';
		for(i=0;i<x.length;i++){
			c=x.charAt(i);
			if(c==' ')r+='_';
			else if(c=='(')r+='_';
			else if(c==')')r+='_';
			else if(c=='$')r+='_';
			else if(c=='#')r+='_';
			else if(c=='?')r+='_';
			else if(c=='%%')r+='_';
			else if(c=='&')r+='_';
			else if(c=='\'')r+='_';
			else if(c=='+')r+='_';
			else r+=c;
		}
		var previewW = (typeof(window.dontUseMeAskCameron)!='undefined')? 140 : 167;
		var previewH = (typeof(window.dontUseMeAskCameron)!='undefined')? 28 : 28;
		document.images[gni].src='http://cdn1.ftimg.com/images/gradients/'+previewW+'x'+previewH+'/'+r+'.png';
	}
}
// color.js

// convert 0 .. 255 to 00->FF
function getHex2(v) {
d = parseInt(v);
if (d < 0 || d > 255)
	return "00";
return (d<16?"0":"")+d.toString(16);
}

function rgb(r,g,b) {
return getHex2(r)+getHex2(g)+getHex2(b);
}

function updateColor(nn,from_cp) {
	var r = $('#'+nn+'R').val();
	var g = $('#'+nn+'G').val();
	var b = $('#'+nn+'B').val();
	$('#'+nn+' div').css('background-color', "rgb("+r+","+g+","+b+")");
	//$('#'+nn).ColorPickerSetColor({r:r ,g:g ,b:b });

	if(!from_cp){
		if ($('#'+nn).data('colorpickerId')) {
			var cal = $('#' + $('#'+nn).data('colorpickerId'));
			var cp_r = $('.colorpicker_rgb_r input', cal).val();
			var cp_g = $('.colorpicker_rgb_g input', cal).val();
			var cp_b = $('.colorpicker_rgb_b input', cal).val();

			var new_r = $('#'+nn+'R').val();
			var new_g = $('#'+nn+'G').val();
			var new_b = $('#'+nn+'B').val();
			//log("r:"+r+",new_r:"+new_r+",cp_new_r:"+cp_r);
			if(r==new_r && g==new_g && b==new_b
				&& (r!=cp_r || g!=cp_g || b!=cp_b)
				){
				$('#'+nn).ColorPickerSetColor({r:r ,g:g ,b:b });
			}
		}
	};
}

function cs(nn,frameNum) {
var r=document.getElementById(nn+'R').value;
var g=document.getElementById(nn+'G').value;
var b=document.getElementById(nn+'B').value;
var c = rgb(r,g,b);
document.getElementById(nn+'Background').style.backgroundColor="#"+c;

$(document).ready(function(){

	$('#'+nn+'R').change(function(evt, from_cp) {updateColor(nn, from_cp);});
	$('#'+nn+'G').change(function(evt, from_cp) {updateColor(nn, from_cp);});
	$('#'+nn+'B').change(function(evt, from_cp) {updateColor(nn, from_cp);});

	setTimeout(function(){
//	fnQ.push(function(){
	$('#'+nn).ColorPicker({
        	color: c,
        	onChange: function (hsb, hex, rgb) {
			$('#'+nn+' div').css('backgroundColor', '#' + hex);
			$('#'+nn+"R").val(rgb.r).trigger('change',true);
			$('#'+nn+"G").val(rgb.g).trigger('change',true);
			$('#'+nn+"B").val(rgb.b).trigger('change',true);
        	},
		onRestore: function (hsb, hex, rgb) {
			$('#'+nn+' div').css('backgroundColor', '#' + hex);
			$('#'+nn+"R").val(rgb.r).trigger('change',true);
			$('#'+nn+"G").val(rgb.g).trigger('change',true);
			$('#'+nn+"B").val(rgb.b).trigger('change',true);
        	}
	});
	},frameNum*1000);
	//});
});

};
/*!
 *
 * Color picker
 * Author: Stefan Petre www.eyecon.ro
 * 
 * Licensed under the MIT license
 * 
 * Modified: Cameron Gregory, http:/www.flamingtext.com/
 */
(function ($) {
	var ColorPicker = function () {
		var
			ids = {},
			inAction,
			charMin = 65,
			visible,
			tpl = '<div class="colorpicker"><div class="colorpicker_color"><div><div></div></div></div><div class="colorpicker_hue"><div></div></div><div class="colorpicker_new_color"></div><div class="colorpicker_current_color"></div><div class="colorpicker_hex"><input type="text" maxlength="6" size="6" /></div><div class="colorpicker_rgb_r colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_rgb_g colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_rgb_b colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_h colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_s colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_b colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_submit"></div></div>',
			defaults = {
				eventName: 'click',
				onShow: function () {},
				onBeforeShow: function(){},
				onHide: function () {},
				onChange: function () {},
				onSubmit: function () {},
				onRestore: function () {},
				color: 'ff0000',
				livePreview: true,
				flat: false,
				stopNextShow: false
			},
			fillRGBFields = function  (hsb, cal) {
				var rgb = HSBToRGB(hsb);
				$(cal).data('colorpicker').fields
					.eq(1).val(rgb.r).end()
					.eq(2).val(rgb.g).end()
					.eq(3).val(rgb.b).end();
			},
			fillHSBFields = function  (hsb, cal) {
				$(cal).data('colorpicker').fields
					.eq(4).val(hsb.h).end()
					.eq(5).val(hsb.s).end()
					.eq(6).val(hsb.b).end();
			},
			fillHexFields = function (hsb, cal) {
				$(cal).data('colorpicker').fields
					.eq(0).val(HSBToHex(hsb)).end();
			},
			setSelector = function (hsb, cal) {
				$(cal).data('colorpicker').selector.css('backgroundColor', '#' + HSBToHex({h: hsb.h, s: 100, b: 100}));
				$(cal).data('colorpicker').selectorIndic.css({
					left: parseInt(150 * hsb.s/100, 10),
					top: parseInt(150 * (100-hsb.b)/100, 10)
				});
			},
			setHue = function (hsb, cal) {
				$(cal).data('colorpicker').hue.css('top', parseInt(150 - 150 * hsb.h/360, 10));
			},
			setCurrentColor = function (hsb, cal) {
				$(cal).data('colorpicker').currentColor.css('backgroundColor', '#' + HSBToHex(hsb));
			},
			setNewColor = function (hsb, cal) {
				$(cal).data('colorpicker').newColor.css('backgroundColor', '#' + HSBToHex(hsb));
			},
			keyDown = function (ev) {
				var pressedKey = ev.charCode || ev.keyCode || -1;
				if ((pressedKey > charMin && pressedKey <= 90) || pressedKey == 32) {
					return false;
				}
				var cal = $(this).parent().parent();
				if (cal.data('colorpicker').livePreview === true) {
					change.apply(this);
				}
			},
			change = function (ev) {
				var cal = $(this).parent().parent(), col;
				if (this.parentNode.className.indexOf('_hex') > 0) {
					cal.data('colorpicker').color = col = HexToHSB(fixHex(this.value));
				} else if (this.parentNode.className.indexOf('_hsb') > 0) {
					cal.data('colorpicker').color = col = fixHSB({
						h: parseInt(cal.data('colorpicker').fields.eq(4).val(), 10),
						s: parseInt(cal.data('colorpicker').fields.eq(5).val(), 10),
						b: parseInt(cal.data('colorpicker').fields.eq(6).val(), 10)
					});
				} else {
					cal.data('colorpicker').color = col = RGBToHSB(fixRGB({
						r: parseInt(cal.data('colorpicker').fields.eq(1).val(), 10),
						g: parseInt(cal.data('colorpicker').fields.eq(2).val(), 10),
						b: parseInt(cal.data('colorpicker').fields.eq(3).val(), 10)
					}));
				}
				if (ev) {
					fillRGBFields(col, cal.get(0));
					fillHexFields(col, cal.get(0));
					fillHSBFields(col, cal.get(0));
				}
				setSelector(col, cal.get(0));
				setHue(col, cal.get(0));
				setNewColor(col, cal.get(0));
				cal.data('colorpicker').onChange.apply(cal, [col, HSBToHex(col), HSBToRGB(col)]);
			},
			blur = function (ev) {
				var cal = $(this).parent().parent();
				cal.data('colorpicker').fields.parent().removeClass('colorpicker_focus');
			},
			focus = function () {
				charMin = this.parentNode.className.indexOf('_hex') > 0 ? 70 : 65;
				$(this).parent().parent().data('colorpicker').fields.parent().removeClass('colorpicker_focus');
				$(this).parent().addClass('colorpicker_focus');
			},
			downIncrement = function (ev) {
				var field = $(this).parent().find('input').focus();
				var current = {
					el: $(this).parent().addClass('colorpicker_slider'),
					max: this.parentNode.className.indexOf('_hsb_h') > 0 ? 360 : (this.parentNode.className.indexOf('_hsb') > 0 ? 100 : 255),
					y: ev.pageY,
					field: field,
					val: parseInt(field.val(), 10),
					preview: $(this).parent().parent().data('colorpicker').livePreview					
				};
				$(document).bind('mouseup', current, upIncrement);
				$(document).bind('mousemove', current, moveIncrement);
			},
			moveIncrement = function (ev) {
				ev.data.field.val(Math.max(0, Math.min(ev.data.max, parseInt(ev.data.val + ev.pageY - ev.data.y, 10))));
				if (ev.data.preview) {
					change.apply(ev.data.field.get(0), [true]);
				}
				return false;
			},
			upIncrement = function (ev) {
				change.apply(ev.data.field.get(0), [true]);
				ev.data.el.removeClass('colorpicker_slider').find('input').focus();
				$(document).unbind('mouseup', upIncrement);
				$(document).unbind('mousemove', moveIncrement);
				return false;
			},
			downHue = function (ev) {
				var current = {
					cal: $(this).parent(),
					y: $(this).offset().top
				};
				current.preview = current.cal.data('colorpicker').livePreview;
				//cam
				ev.data=current;
				moveHue(ev);
				$(document).bind('mouseup', current, upHue);
				$(document).bind('mousemove', current, moveHue);
			},
			moveHue = function (ev) {
				change.apply(
					ev.data.cal.data('colorpicker')
						.fields
						.eq(4)
						.val(parseInt(360*(150 - Math.max(0,Math.min(150,(ev.pageY - ev.data.y))))/150, 10))
						.get(0),
					[ev.data.preview]
				);
				return false;
			},
			upHue = function (ev) {
				fillRGBFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
				fillHexFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
				$(document).unbind('mouseup', upHue);
				$(document).unbind('mousemove', moveHue);
				return false;
			},
			downSelector = function (ev) {
				var current = {
					cal: $(this).parent(),
					pos: $(this).offset()
				};
				current.preview = current.cal.data('colorpicker').livePreview;
				ev.data = current;
				moveSelector(ev);

				$(document).bind('mouseup', current, upSelector);
				$(document).bind('mousemove', current, moveSelector);
			},
			moveSelector = function (ev) {
				change.apply(
					ev.data.cal.data('colorpicker')
						.fields
						.eq(6)
						.val(parseInt(100*(150 - Math.max(0,Math.min(150,(ev.pageY - ev.data.pos.top))))/150, 10))
						.end()
						.eq(5)
						.val(parseInt(100*(Math.max(0,Math.min(150,(ev.pageX - ev.data.pos.left))))/150, 10))
						.get(0),
					[ev.data.preview]
				);
				return false;
			},
			upSelector = function (ev) {
				fillRGBFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
				fillHexFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
				$(document).unbind('mouseup', upSelector);
				$(document).unbind('mousemove', moveSelector);
				return false;
			},
			enterSubmit = function (ev) {
				$(this).addClass('colorpicker_focus');
			},
			leaveSubmit = function (ev) {
				$(this).removeClass('colorpicker_focus');
			},
			clickSubmit = function (ev) {
				var cal = $(this).parent();
				var col = cal.data('colorpicker').color;
				cal.data('colorpicker').origColor = col;
				setCurrentColor(col, cal.get(0));
				cal.data('colorpicker').onSubmit(col, HSBToHex(col), HSBToRGB(col), cal.data('colorpicker').el);
			},
			show = function (ev) {
				var cal = $('#' + $(this).data('colorpickerId'));
				cal.data('colorpicker').source=ev.target;
				if (cal.data('colorpicker').stopNextShow==true) {
					cal.data('colorpicker').stopNextShow=false;
					return;
				}
				cal.data('colorpicker').onBeforeShow.apply(this, [cal.get(0)]);
				var pos = $(this).offset();
				var viewPort = getViewport();
				var top = pos.top + this.offsetHeight;
				var left = pos.left;
				if (top + 176 > viewPort.t + viewPort.h) {
					top -= this.offsetHeight + 176;
				}
				if (left + 356 > viewPort.l + viewPort.w) {
					left -= 356;
				}
				cal.css({left: left + 'px', top: top + 'px'});
				if (cal.data('colorpicker').onShow.apply(this, [cal.get(0)]) != false) {
					cal.show();
				}
				$(document).bind('mousedown', {cal: cal}, hide);
				return false;
			},
			hide = function (ev) {
				if (ev.data.cal.data('colorpicker').source == ev.target) {
					ev.data.cal.data('colorpicker').stopNextShow = true;
				}
				if (!isChildOf(ev.data.cal.get(0), ev.target, ev.data.cal.get(0))) {
					if (ev.data.cal.data('colorpicker').onHide.apply(this, [ev.data.cal.get(0)]) != false) {
						ev.data.cal.hide();
					}
					$(document).unbind('mousedown', hide);
				}
			},
			isChildOf = function(parentEl, el, container) {
				if (parentEl == el) {
					return true;
				}
				if (parentEl.contains) {
					return parentEl.contains(el);
				}
				if ( parentEl.compareDocumentPosition ) {
					return !!(parentEl.compareDocumentPosition(el) & 16);
				}
				var prEl = el.parentNode;
				while(prEl && prEl != container) {
					if (prEl == parentEl)
						return true;
					prEl = prEl.parentNode;
				}
				return false;
			},
			getViewport = function () {
				var m = document.compatMode == 'CSS1Compat';
				return {
					l : window.pageXOffset || (m ? document.documentElement.scrollLeft : document.body.scrollLeft),
					t : window.pageYOffset || (m ? document.documentElement.scrollTop : document.body.scrollTop),
					w : window.innerWidth || (m ? document.documentElement.clientWidth : document.body.clientWidth),
					h : window.innerHeight || (m ? document.documentElement.clientHeight : document.body.clientHeight)
				};
			},
			fixHSB = function (hsb) {
				return {
					h: Math.min(360, Math.max(0, hsb.h)),
					s: Math.min(100, Math.max(0, hsb.s)),
					b: Math.min(100, Math.max(0, hsb.b))
				};
			}, 
			fixRGB = function (rgb) {
				return {
					r: Math.min(255, Math.max(0, rgb.r)),
					g: Math.min(255, Math.max(0, rgb.g)),
					b: Math.min(255, Math.max(0, rgb.b))
				};
			},
			fixHex = function (hex) {
				var len = 6 - hex.length;
				if (len > 0) {
					var o = [];
					for (var i=0; i<len; i++) {
						o.push('0');
					}
					o.push(hex);
					hex = o.join('');
				}
				return hex;
			}, 
			HexToRGB = function (hex) {
				var hex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16);
				return {r: hex >> 16, g: (hex & 0x00FF00) >> 8, b: (hex & 0x0000FF)};
			},
			HexToHSB = function (hex) {
				return RGBToHSB(HexToRGB(hex));
			},
			RGBToHSB = function (rgb) {
				var hsb = {
					h: 0,
					s: 0,
					b: 0
				};
				var min = Math.min(rgb.r, rgb.g, rgb.b);
				var max = Math.max(rgb.r, rgb.g, rgb.b);
				var delta = max - min;
				hsb.b = max;
				if (max != 0) {
					
				}
				hsb.s = max != 0 ? 255 * delta / max : 0;
				if (hsb.s != 0) {
					if (rgb.r == max) {
						hsb.h = (rgb.g - rgb.b) / delta;
					} else if (rgb.g == max) {
						hsb.h = 2 + (rgb.b - rgb.r) / delta;
					} else {
						hsb.h = 4 + (rgb.r - rgb.g) / delta;
					}
				} else {
					hsb.h = -1;
				}
				hsb.h *= 60;
				if (hsb.h < 0) {
					hsb.h += 360;
				}
				hsb.s *= 100/255;
				hsb.b *= 100/255;
                                if(rgb.r==rgb.g && rgb.r==rgb.b){
                                        hsb.h=237;
				}
				return hsb;
			},
			HSBToRGB = function (hsb) {
				var rgb = {};
				var h = Math.round(hsb.h);
				var s = Math.round(hsb.s*255/100);
				var v = Math.round(hsb.b*255/100);
				if(s == 0) {
					rgb.r = rgb.g = rgb.b = v;
				} else {
					var t1 = v;
					var t2 = (255-s)*v/255;
					var t3 = (t1-t2)*(h%60)/60;
					if(h==360) h = 0;
					if(h<60) {rgb.r=t1;	rgb.b=t2; rgb.g=t2+t3}
					else if(h<120) {rgb.g=t1; rgb.b=t2;	rgb.r=t1-t3}
					else if(h<180) {rgb.g=t1; rgb.r=t2;	rgb.b=t2+t3}
					else if(h<240) {rgb.b=t1; rgb.r=t2;	rgb.g=t1-t3}
					else if(h<300) {rgb.b=t1; rgb.g=t2;	rgb.r=t2+t3}
					else if(h<360) {rgb.r=t1; rgb.g=t2;	rgb.b=t1-t3}
					else {rgb.r=0; rgb.g=0;	rgb.b=0}
				}
				return {r:Math.round(rgb.r), g:Math.round(rgb.g), b:Math.round(rgb.b)};
			},
			RGBToHex = function (rgb) {
				var hex = [
					rgb.r.toString(16),
					rgb.g.toString(16),
					rgb.b.toString(16)
				];
				$.each(hex, function (nr, val) {
					if (val.length == 1) {
						hex[nr] = '0' + val;
					}
				});
				return hex.join('');
			},
			HSBToHex = function (hsb) {
				return RGBToHex(HSBToRGB(hsb));
			},
			restoreOriginal = function () {
				var cal = $(this).parent();
				var col = cal.data('colorpicker').origColor;
				cal.data('colorpicker').color = col;
				fillRGBFields(col, cal.get(0));
				fillHexFields(col, cal.get(0));
				fillHSBFields(col, cal.get(0));
				setSelector(col, cal.get(0));
				setHue(col, cal.get(0));
				setNewColor(col, cal.get(0));
				cal.data('colorpicker').onRestore.apply(cal, [col, HSBToHex(col), HSBToRGB(col)]);

			};
		return {
			init: function (opt) {
				opt = $.extend({}, defaults, opt||{});
				if (typeof opt.color == 'string') {
					opt.color = HexToHSB(opt.color);
				} else if (opt.color.r != undefined && opt.color.g != undefined && opt.color.b != undefined) {
					opt.color = RGBToHSB(opt.color);
				} else if (opt.color.h != undefined && opt.color.s != undefined && opt.color.b != undefined) {
					opt.color = fixHSB(opt.color);
				} else {
					return this;
				}
				return this.each(function () {
					if (!$(this).data('colorpickerId')) {
						var options = $.extend({}, opt);
						options.origColor = opt.color;
						var id = 'collorpicker_' + parseInt(Math.random() * 1000);
						$(this).data('colorpickerId', id);
						var cal = $(tpl).attr('id', id);
						if (options.flat) {
							cal.appendTo(this).show();
						} else {
							cal.appendTo(document.body);
						}
						options.fields = cal
											.find('input')
												.bind('keyup', keyDown)
												.bind('change', change)
												.bind('blur', blur)
												.bind('focus', focus);
						cal
							.find('span').bind('mousedown', downIncrement).end()
							.find('>div.colorpicker_current_color').bind('click', restoreOriginal);
						options.selector = cal.find('div.colorpicker_color').bind('mousedown', downSelector);
						options.selectorIndic = options.selector.find('div div');
						options.el = this;
						options.hue = cal.find('div.colorpicker_hue div');
						cal.find('div.colorpicker_hue').bind('mousedown', downHue);
						options.newColor = cal.find('div.colorpicker_new_color');
						options.currentColor = cal.find('div.colorpicker_current_color');
						cal.data('colorpicker', options);
						cal.find('div.colorpicker_submit')
							.bind('mouseenter', enterSubmit)
							.bind('mouseleave', leaveSubmit)
							.bind('click', clickSubmit);
						fillRGBFields(options.color, cal.get(0));
						fillHSBFields(options.color, cal.get(0));
						fillHexFields(options.color, cal.get(0));
						setHue(options.color, cal.get(0));
						setSelector(options.color, cal.get(0));
						setCurrentColor(options.color, cal.get(0));
						setNewColor(options.color, cal.get(0));
						if (options.flat) {
							cal.css({
								position: 'relative',
								display: 'block'
							});
						} else {
							$(this).bind(options.eventName, show);
						}
					}
				});
			},
			showPicker: function() {
				return this.each( function () {
					if ($(this).data('colorpickerId')) {
						show.apply(this);
					}
				});
			},
			hidePicker: function() {
				return this.each( function () {
					if ($(this).data('colorpickerId')) {
						$('#' + $(this).data('colorpickerId')).hide();
					}
				});
			},
			setColor: function(col) {
				if (typeof col == 'string') {
					col = HexToHSB(col);
				} else if (col.r != undefined && col.g != undefined && col.b != undefined) {
					col = RGBToHSB(col);
				} else if (col.h != undefined && col.s != undefined && col.b != undefined) {
					col = fixHSB(col);
				} else {
					return this;
				}
				return this.each(function(){
					if ($(this).data('colorpickerId')) {
						var cal = $('#' + $(this).data('colorpickerId'));
						cal.data('colorpicker').color = col;
						cal.data('colorpicker').origColor = col;
						fillRGBFields(col, cal.get(0));
						fillHSBFields(col, cal.get(0));
						fillHexFields(col, cal.get(0));
						setHue(col, cal.get(0));
						setSelector(col, cal.get(0));
						setCurrentColor(col, cal.get(0));
						setNewColor(col, cal.get(0));
					}
				});
			}
		};
	}();
	$.fn.extend({
		ColorPicker: ColorPicker.init,
		ColorPickerHide: ColorPicker.hidePicker,
		ColorPickerShow: ColorPicker.showPicker,
		ColorPickerSetColor: ColorPicker.setColor
	});
})(jQuery);

// hello

/**
 *
 * Zoomimage
 * Author: Stefan Petre www.eyecon.ro
 * 
 * @requires jquery
 * Modified: Cameron Gregory, http:/www.flamingtext.com/
 * 
 */
(function($){
	var EYE = window.EYE = function() {
		var _registered = {
			init: []
		};
		return {
			init: function() {
				$.each(_registered.init, function(nr, fn){
					fn.call();
				});
			},
			extend: function(prop) {
				for (var i in prop) {
					if (prop[i] != undefined) {
						this[i] = prop[i];
					}
				}
			},
			register: function(fn, type) {
				if (!_registered[type]) {
					_registered[type] = [];
				}
				_registered[type].push(fn);
			}
		};
	}();
	$(EYE.init);
})(jQuery);
/**
 *
 * Utilities
 * Author: Stefan Petre www.eyecon.ro
 * @requires jquery, EYE
 * 
 * Modified: Cameron Gregory, http:/www.flamingtext.com/
 */
(function($) {
EYE.extend({
	getPosition : function(e, forceIt)
	{
		var x = 0;
		var y = 0;
		var es = e.style;
		var restoreStyles = false;
		if (forceIt && jQuery.curCSS(e,'display') == 'none') {
			var oldVisibility = es.visibility;
			var oldPosition = es.position;
			restoreStyles = true;
			es.visibility = 'hidden';
			es.display = 'block';
			es.position = 'absolute';
		}
		var el = e;
		if (el.getBoundingClientRect) { // IE
			var box = el.getBoundingClientRect();
			x = box.left + Math.max(document.documentElement.scrollLeft, document.body.scrollLeft) - 2;
			y = box.top + Math.max(document.documentElement.scrollTop, document.body.scrollTop) - 2;
		} else {
			x = el.offsetLeft;
			y = el.offsetTop;
			el = el.offsetParent;
			if (e != el) {
				while (el) {
					x += el.offsetLeft;
					y += el.offsetTop;
					el = el.offsetParent;
				}
			}
			if (jQuery.browser.safari && jQuery.curCSS(e, 'position') == 'absolute' ) {
				x -= document.body.offsetLeft;
				y -= document.body.offsetTop;
			}
			el = e.parentNode;
			while (el && el.tagName.toUpperCase() != 'BODY' && el.tagName.toUpperCase() != 'HTML') 
			{
				if (jQuery.curCSS(el, 'display') != 'inline') {
					x -= el.scrollLeft;
					y -= el.scrollTop;
				}
				el = el.parentNode;
			}
		}
		if (restoreStyles == true) {
			es.display = 'none';
			es.position = oldPosition;
			es.visibility = oldVisibility;
		}
		return {x:x, y:y};
	},
	getSize : function(e)
	{
		var w = parseInt(jQuery.curCSS(e,'width'), 10);
		var h = parseInt(jQuery.curCSS(e,'height'), 10);
		var wb = 0;
		var hb = 0;
		if (jQuery.curCSS(e, 'display') != 'none') {
			wb = e.offsetWidth;
			hb = e.offsetHeight;
		} else {
			var es = e.style;
			var oldVisibility = es.visibility;
			var oldPosition = es.position;
			es.visibility = 'hidden';
			es.display = 'block';
			es.position = 'absolute';
			wb = e.offsetWidth;
			hb = e.offsetHeight;
			es.display = 'none';
			es.position = oldPosition;
			es.visibility = oldVisibility;
		}
		return {w:w, h:h, wb:wb, hb:hb};
	},
	getClient : function(e)
	{
		var h, w;
		if (e) {
			w = e.clientWidth;
			h = e.clientHeight;
		} else {
			var de = document.documentElement;
			w = window.innerWidth || self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth;
			h = window.innerHeight || self.innerHeight || (de&&de.clientHeight) || document.body.clientHeight;
		}
		return {w:w,h:h};
	},
	getScroll : function (e)
	{
		var t=0, l=0, w=0, h=0, iw=0, ih=0;
		if (e && e.nodeName.toLowerCase() != 'body') {
			t = e.scrollTop;
			l = e.scrollLeft;
			w = e.scrollWidth;
			h = e.scrollHeight;
		} else  {
			if (document.documentElement) {
				t = document.documentElement.scrollTop;
				l = document.documentElement.scrollLeft;
				w = document.documentElement.scrollWidth;
				h = document.documentElement.scrollHeight;
			} else if (document.body) {
				t = document.body.scrollTop;
				l = document.body.scrollLeft;
				w = document.body.scrollWidth;
				h = document.body.scrollHeight;
			}
			if (typeof pageYOffset != 'undefined') {
				t = pageYOffset;
				l = pageXOffset;
			}
			iw = self.innerWidth||document.documentElement.clientWidth||document.body.clientWidth||0;
			ih = self.innerHeight||document.documentElement.clientHeight||document.body.clientHeight||0;
		}
		return { t: t, l: l, w: w, h: h, iw: iw, ih: ih };
	},
	getMargins : function(e, toInteger)
	{
		var t = jQuery.curCSS(e,'marginTop') || '';
		var r = jQuery.curCSS(e,'marginRight') || '';
		var b = jQuery.curCSS(e,'marginBottom') || '';
		var l = jQuery.curCSS(e,'marginLeft') || '';
		if (toInteger)
			return {
				t: parseInt(t, 10)||0,
				r: parseInt(r, 10)||0,
				b: parseInt(b, 10)||0,
				l: parseInt(l, 10)
			};
		else
			return {t: t, r: r,	b: b, l: l};
	},
	getPadding : function(e, toInteger)
	{
		var t = jQuery.curCSS(e,'paddingTop') || '';
		var r = jQuery.curCSS(e,'paddingRight') || '';
		var b = jQuery.curCSS(e,'paddingBottom') || '';
		var l = jQuery.curCSS(e,'paddingLeft') || '';
		if (toInteger)
			return {
				t: parseInt(t, 10)||0,
				r: parseInt(r, 10)||0,
				b: parseInt(b, 10)||0,
				l: parseInt(l, 10)
			};
		else
			return {t: t, r: r,	b: b, l: l};
	},
	getBorder : function(e, toInteger)
	{
		var t = jQuery.curCSS(e,'borderTopWidth') || '';
		var r = jQuery.curCSS(e,'borderRightWidth') || '';
		var b = jQuery.curCSS(e,'borderBottomWidth') || '';
		var l = jQuery.curCSS(e,'borderLeftWidth') || '';
		if (toInteger)
			return {
				t: parseInt(t, 10)||0,
				r: parseInt(r, 10)||0,
				b: parseInt(b, 10)||0,
				l: parseInt(l, 10)||0
			};
		else
			return {t: t, r: r,	b: b, l: l};
	},
	traverseDOM : function(nodeEl, func)
	{
		func(nodeEl);
		nodeEl = nodeEl.firstChild;
		while(nodeEl){
			EYE.traverseDOM(nodeEl, func);
			nodeEl = nodeEl.nextSibling;
		}
	},
	getInnerWidth :  function(el, scroll) {
		var offsetW = el.offsetWidth;
		return scroll ? Math.max(el.scrollWidth,offsetW) - offsetW + el.clientWidth:el.clientWidth;
	},
	getInnerHeight : function(el, scroll) {
		var offsetH = el.offsetHeight;
		return scroll ? Math.max(el.scrollHeight,offsetH) - offsetH + el.clientHeight:el.clientHeight;
	},
	getExtraWidth : function(el) {
		if($.boxModel)
			return (parseInt($.curCSS(el, 'paddingLeft'))||0)
				+ (parseInt($.curCSS(el, 'paddingRight'))||0)
				+ (parseInt($.curCSS(el, 'borderLeftWidth'))||0)
				+ (parseInt($.curCSS(el, 'borderRightWidth'))||0);
		return 0;
	},
	getExtraHeight : function(el) {
		if($.boxModel)
			return (parseInt($.curCSS(el, 'paddingTop'))||0)
				+ (parseInt($.curCSS(el, 'paddingBottom'))||0)
				+ (parseInt($.curCSS(el, 'borderTopWidth'))||0)
				+ (parseInt($.curCSS(el, 'borderBottomWidth'))||0);
		return 0;
	},
	isChildOf: function(parentEl, el, container) {
		if (parentEl == el) {
			return true;
		}
		if (!el || !el.nodeType || el.nodeType != 1) {
			return false;
		}
		if (parentEl.contains && !$.browser.safari) {
			return parentEl.contains(el);
		}
		if ( parentEl.compareDocumentPosition ) {
			return !!(parentEl.compareDocumentPosition(el) & 16);
		}
		var prEl = el.parentNode;
		while(prEl && prEl != container) {
			if (prEl == parentEl)
				return true;
			prEl = prEl.parentNode;
		}
		return false;
	},
	centerEl : function(el, axis)
	{
		var clientScroll = EYE.getScroll();
		var size = EYE.getSize(el);
		if (!axis || axis == 'vertically')
			$(el).css(
				{
					top: clientScroll.t + ((Math.min(clientScroll.h,clientScroll.ih) - size.hb)/2) + 'px'
				}
			);
		if (!axis || axis == 'horizontally')
			$(el).css(
				{
					left: clientScroll.l + ((Math.min(clientScroll.w,clientScroll.iw) - size.wb)/2) + 'px'
				}
			);
	}
});
if (!$.easing.easeout) {
	$.easing.easeout = function(p, n, firstNum, delta, duration) {
		return -delta * ((n=n/duration-1)*n*n*n - 1) + firstNum;
	};
}
	
})(jQuery);
(function($){
	getImageCache = function(script){
		var cache = false;
		var pos = window.location.search.indexOf("imageCache=");
		if(pos!=-1){
			var val = window.location.search.substring(pos+11);
			var ampersand = val.indexOf('&');
			if(ampersand != -1){
				val = val.substring(0,ampersand);
			}
			if(val=="true")
				return true;
			return false;
		}
		var logos = ['aurora-logo'
			,'bad-oil-logo'
			,'burnt-paper-logo'
			,'chalk-logo'
			,'chip-away-logo'
			,'chrominium-logo'
			,'colored-logo'
			,'dracula-logo'
			,'electricity-logo'
			,'feurio-logo'
			,'fire-logo'
			,'flammen-logo'
			,'flash-fire-logo'
			,'frosty-logo'
			,'gas-flame-logo'
			,'harry-potter-logo'
			,'ice-logo'
			,'ice-cube-logo'
			,'ice-fire-logo'
			,'lava-logo'
			,'liquid-water-logo'
			,'molten-logo'
			,'mosaic-logo'
			,'mud-logo'
			,'oil-spill-logo'
			,'old-photo-logo'
			,'old-stone-logo'
			,'plasma-logo'
			,'slime-logo'
			,'smokey-logo'
			,'solid-noise-logo'
			,'sound-blast-logo'
			,'star-wars-logo'
			,'starburst-logo'
			,'starscape-logo'
			,'textured-logo'
			,'warp-logo'
			,'watercolor-logo'
		];
		var re = new RegExp(logos.join("|"));

		if(script && !script.match(re))
			cache = true;
		return cache;
	};


	//AnimPreset widget
	$.widget( "ui.animPreset", {
		options: {
			value: "none"
			,frameControlID: "frameControl"
			,idPrepend: "1-frame"
		},
		
		_create: function() {
			var o = this.options;
			this.frameControl = $("#"+o.frameControlID).frameControl();
			this.value = this.widget().val() || o.value;
			
			var preset = this.value;
				switch (preset){
					case "letters":
						this._letters();break;
					case "letterSpacing":
						this._letterSpacing();break;
					case "letterRotate": //need around 50 frames for good looking rotation
						this._letterRotate();break;
					case "shake":
						this._shake();break;
					case "shadowOpacity":
						this._shadowOpacity();break;
					case "flashFire":
						this._flashFire();break;
					case "bounce":
						this._bounce();break;
					case "randomPreset":
						this._randomPreset();break;
					case "tileSizeIncrease":
						this._tileSizeIncrease();break;
					case "tileSizeDecrease":
						this._tileSizeDecrease();break;
					case "iceCube":
						this._iceCube();break;
					case "burntPaper":
						this._burntPaper();break;
					case "amazing3d":
						this._amazing3d();break;
					case "none":
						break;
				};
			//refresh frameControl
			this._initImageCache();
			this.frameControl.frameControl();
		},
		_initImageCache:function(){
			var script = $("#"+this.options.idPrepend+"0_script").val();
			var cache = getImageCache(script);
			$("#1-imageCache").prop("checked", cache);
		},
		_letters: function(){
			var o = this.options;
			$("#"+o.idPrepend+"0_text").paramGenerator({
				numFrames: "length"
				,fn: function(ev, ui){
					var initValue = ui.val;
					var lettersPerFrame = Math.ceil(initValue.length/ui.frames);
					var excess = lettersPerFrame*ui.frames - initValue.length;
					var cutDownMultiple = Math.floor(ui.frames/excess);
					//ui.frames = 
					var prevEnd=0;
					for (var i=0; i<ui.frames; i++){
						var letters = lettersPerFrame;
						if(excess && i%cutDownMultiple == 0){
							letters--;
							excess--;
						}
						var end = prevEnd = prevEnd+letters;
						end = end <initValue.length? end: initValue.length;
						//var end = (i+1)*letters <initValue.length? (i+1)*letters : initValue.length;						
						$("#"+o.idPrepend+i+"_"+ui.param).val(initValue.substring(0,end));
						
					}
				}
			});
		
		},
		_letterSpacing: function(){
			var o = this.options;
			$("#"+o.idPrepend+"0_letterSpacing").paramGenerator({
				numFrames: 10
				,fn: function(ev, ui){
					var initValue = -35;
					var multiple=5;
					for (var i=0; i<ui.frames; i++){
						var val  = initValue + i*multiple;
						$("#"+o.idPrepend+i+"_"+ui.param).val(val);
					}
				}
			});
		
		},
		_letterRotate: function(){
			var getRadian = function getRadian(deg) {
				return Math.PI * deg / 180;
			}
			var o = this.options;
			$("#"+o.idPrepend+"0_letterSpacing").paramGenerator({
				numFrames: 20 //need around 20 for better animation
				,fn: function(ev, ui){
					var reversed = -80;
					var rotateTotalAngle = 180;//can change this to 360, but really need more frames for this to look better
					
					var rotateFrameAngle = rotateTotalAngle/ui.frames;
					for (var i=0; i<ui.frames; i++){
						var a = getRadian(i*rotateFrameAngle);
						var val = Math.round(reversed*Math.sin(a))+8; //round for 'cleaner' user view.
						$("#"+o.idPrepend+i+"_"+ui.param).val(val);
					}
				}
			});
		
		},


		_shake: function(){
			
		},
		_shadowOpacity: function(){
			var o = this.options;
			$("#"+o.idPrepend+"0_shadowOpacity").paramGenerator({
				numFrames: 10 
				,fn: function(ev, ui){
					var minOpacity = 0, maxOpacity=100;
					var range = maxOpacity-minOpacity;
					var increment = range/ui.frames;
					for (var i=0; i<ui.frames; i++){
						var val = i*increment;
						$("#"+o.idPrepend+i+"_shadowType1").trigger('click');//prop('checked',true);
						$("#"+o.idPrepend+i+"_"+ui.param).val(val);
					}
				}
			});
		},
		_flashFire: function(){
			var o = this.options;
			$("#"+o.idPrepend+"0_spread").paramGenerator({
				numFrames: 10 
				,fn: function(ev, ui){
					var minSpread = 0.5, maxSpread=9.5;
					var range = maxSpread-minSpread;
					var increment = range/(ui.frames-1);
					for (var i=0; i<ui.frames; i++){
						var val = minSpread + i*increment;
						$("#"+o.idPrepend+i+"_"+ui.param).val(val);
					}
				}
			});
		},
		_bounce: function(){
			
		}
		,_randomPreset: function(){
			$("#totalFrames").val(5);
		}
		,_tileSizeIncrease:function(){
			var o = this.options;
			$("#"+o.idPrepend+"0_tileSize").paramGenerator({
				numFrames: 15
				,fn: function(ev, ui){
					var minSize = 1, maxSize=50;
					var range = maxSize-minSize;
					var increment = Math.floor(range/ui.frames);
					for (var i=0; i<ui.frames; i++){
						var val = (i+1)*increment;
						$("#"+o.idPrepend+i+"_"+ui.param).val(val);
						$("#"+o.idPrepend+i+"_fontsize").val(130);
					}
				}
			});
		}
		,_tileSizeDecrease:function(){
			var o = this.options;
			$("#"+o.idPrepend+"0_tileSize").paramGenerator({
				numFrames: 15
				,fn: function(ev, ui){
					var minSize = 1, maxSize=50;
					var range = maxSize-minSize;
					var increment = Math.floor(range/ui.frames);
					for (var i=0; i<ui.frames; i++){
						var val = (ui.frames-i)*increment;
						$("#"+o.idPrepend+i+"_"+ui.param).val(val);
						$("#"+o.idPrepend+i+"_fontsize").val(130);
					}
				}
			});
		}
		,_iceCube:function(){
			var o = this.options;
			$("#"+o.idPrepend+"0_growEffect").paramGenerator({
				numFrames: 15
				,fn: function(ev, ui){
					var minSize = -8, maxSize=12;
					var range = maxSize-minSize;
					var increment = 2;//Math.floor(range/ui.frames);
					for (var i=0; i<12; i++){
						var val = minSize+i*increment;
						if(val>maxSize)
							val=maxSize;
						$("#"+o.idPrepend+i+"_"+ui.param).val(val);
					}
					for (var i=0; i<12; i++){
						var val =0;
						if(i>6)
							val=i-6;
						$("#"+o.idPrepend+i+"_icicle").val(val);
					}
					//13
					$("#"+o.idPrepend+"12_growEffect").val(2);
					$("#"+o.idPrepend+"12_cubeDim").val(24);
					//14
					$("#"+o.idPrepend+"13_growEffect").val(-3);
					$("#"+o.idPrepend+"13_cubeDim").val(40);
					//15
					$("#"+o.idPrepend+"14_growEffect").val(-9);
					$("#"+o.idPrepend+"14_cubeDim").val(1);
					
					for (var i=0; i<ui.frames; i++){
						$("#"+o.idPrepend+i+"_fontsize").val(95);
						$("#"+o.idPrepend+i+"_fontname").val("victoriassecret").trigger('change');
						if(i>11)
							$("#"+o.idPrepend+i+"_icicle").val(5);
					}

				}
			});
		}
		,_burntPaper:function(){
			var o = this.options;
			var self = this;
			$("#"+o.idPrepend+"0_burnSize").paramGenerator({
				numFrames: 10
				,fn: function(ev, ui){
					for (var i=0; i<ui.frames; i++){
						self._setVal(ui.frames,i,"burnSize",0,100);
						self._setVal(ui.frames,i,"growSelection",24,0);
					}
				}
			});
		}
		,_amazing3d:function(){
			var o = this.options;
			var self = this;
			$("#"+o.idPrepend+"0_height").paramGenerator({
				numFrames: 7
				,fn: function(ev, ui){
					for (var i=0; i<ui.frames; i++){
						self._setVal(ui.frames,i,"height",60,3);
						self._setVal(ui.frames,i,"rotation",-45,-5);
						self._setVal(ui.frames,i,"shadowYOffset",2,20);
						self._setVal(ui.frames,i,"colorCenterR",32,0);
						self._setVal(ui.frames,i,"colorCenterG",65,0);
						self._setVal(ui.frames,i,"colorCenterB",94,0);
						self._setVal(ui.frames,i,"lineSpacing",-65,-11);
						$("#"+o.idPrepend+i+"_fontname_tagname").val("M").trigger('change');
						$("#"+o.idPrepend+i+"_fontname").val("Mixed up").trigger('change');
					}
					$("#"+o.idPrepend+"6_msSleep").val(800);
				}
			});
		}
		,_setVal:function(frames,i,param,start,end){
			var o = this.options;
			
			var range = Math.abs(start - end);
			var increment = Math.floor(range/(frames-1)) * i;
			
			var increase = end>start;
			if(!increase)
				increment = -increment;
			val = end - increment;
			$("#"+o.idPrepend+(frames-i-1)+"_"+param).val(val).trigger('change');
		}
	});
	
	/*use this to generate values for a given field
	numFrames  - required
	fn - function specifying how to generate values for this field over numFrames
	values - object to specify values directly for specific frames
	
	NOTE: 
	- fn is optional, so can generate values using values object
	- values is optional, ie dont have to use it(can use just fn)
	- if both are specified
		fn is run first
		values override
	
	eg:
		$("[id$=frame0_text]").paramGenerator({
				numFrames: "length" //can specify number or string "length"
				,fn: function(ev, ui){
					//available values:
					//ui.frames - same as numFrames
					//ui.param - field, eg "text"
					//ui.val - original value of the element
					
					var initValue = ui.val;
					for (var i=0; i<ui.frames; i++){
						$("[id$=frame"+i+"_"+ui.param+"]").val(initValue.substring(0,i+1));
					}
				}
				,values: { //object to override particular frames
					frame1: "override"
					,frame3: "too"
				}
			});
	
	*/
	$.widget( "ui.paramGenerator", {
		options: {
			param: null	//eg fontsize
			,numFrames: 1 //can be number or string "length" (useful when generating values based on lenght of the parameter)
			,fn: null //
			,values: null //eg {frame0:1,frame5:14}
			,totalFramesID : 'totalFrames'
			,maxFrames:20
		},
		
		_create: function() {
			var self = this;
			var o = this.options;
			self._initVars();
			
			if ($.isFunction(this.options.fn)){
				self._trigger('fn', null, self._ui());
			}
			self._populateValues();
		},
		_initVars: function(){
			var id = this.widget().attr("id");
			var field = id.match(new RegExp("_(.*)$"));			
			this.param = field.pop() || this.options.param; //can come from option
			
			this.totalFrames = $("#"+this.options.totalFramesID);
			this.value = this.widget().val();
			this._numFrames();
		},
		_numFrames: function(){
			var x = this.options.numFrames;
			if (typeof x == "number"){
				this.frames = x;
			}
			else if(typeof x == "string"){
				if(x === "length"){
					this.frames = this.value.length<=this.options.maxFrames ? this.value.length : this.options.maxFrames;
				}
			}
			
			this.totalFrames.val(this.frames);
		},
		
		_ui: function(){
			return {
				frames: this.frames
				,param: this.param
				,val: this.value
			};		
		},
		_populateValues: function(){
			var v = this.options.values;
			var param = this.param;
			if(v==null){
				//not specified, do nothing
			}
			else if( $.isPlainObject(v) ){
				$.each(v, function(key, value) {
					$("[id$="+key+"_"+param+"]").val(value);
				});
			}
			else{
				//error, TODO: handle
			}
		}
		
	});

	//AnimPreset widget
	$.widget( "ui.animPresetController", {
		options: {
			img: "<img src=\"http://cdn1.ftimg.com/images/animate.png\" alt=\"Animate\" title=\"Animate\">"
			,animatorCgi: "/logo/animate.cgi" // usually overridden in dynamic.c
			,animPresets: {
				animate:{ui:"Animate",avail:true}
				,letters:{ui:"Type Letters",avail:false}
				,letterSpacing:{ui:"Moving Letters", avail: false}
				,letterRotate:{ui:"Rotating Letters", avail: false}
				,shadowOpacity:{ui:"Shadow Opacity", avail: false}
				,flashFire:{ui:"Flash Fire", avail: false}
				//,randomPreset:{ui:"Random", avail: false, imageCache: false}
				,tileSizeIncrease:{ui:"Increasing Tile Size", avail: false}
				,tileSizeDecrease:{ui:"Decreasing Tile Size", avail: false}
				,iceCube:{ui:"Ice Cube", avail: false}
				,burntPaper:{ui:"Burning Paper", avail: false}
				,amazing3d:{ui:"Turning 3D", avail: false}
			}
			,idPrefix:"1-frame0_"
		},
		_create: function() {
			var self = this;
			this.widget().html($(this.options.img));
			this.button = this.widget().children().eq(0);
			
			//var inputs = $(':input');//so that we can re-use this(faster)
			//var hidden = $(':hidden');
			
			this.animPresets = this.options.animPresets;
			this._setContext();
			this._enablePresets();
			this._buildUI();
			this._handleClick();
			
		},
		_setContext:function(){
			this.context = undefined;
			var prefix = this.options.idPrefix;
			if(prefix.charAt(prefix.length-1)=="_")
				prefix = prefix.substring(0,prefix.length-1);
			this.context = $("#"+prefix);
			this.animateMode = true;
			if(!this.context.length){
				this.animateMode = false;
				this.context=this.widget().closest("form");//we allow this to be on first frame of animator
			}
		},
		_buildUI:function(){
			this.preview = $("<div class=\"animPresetControllerPreview\"></div>").appendTo('body');
			//this.preview = $("<div class=\"animPresetControllerPreview\"></div>").appendTo(this.widget());
			this.preview.css("left","-1000px");
			
			this.list = $("<ul></ul>").appendTo(this.preview);
			var self = this;
			
			var liWidth=0;
			$.each(this.animPresets, function(k,v){
				if(v.avail){
					var li =  $("<li presetValue=\""+k+"\"></li>");
					//can add preview image here
					$("<div class=\"animPresetControllerTitle\">"+v.ui+"</div>").appendTo(li);
					//can add description here
					li.click(function(){
						var params = buildParams(self.context,{frame0_url:1},"frame\\d_");//method defined in dynamicform.js
						params = params + "animPreset="+encodeURIComponent($(this).attr('presetValue'));
						if("imageCache" in v && typeof v.imageCache=='boolean')
							params = params + "&imageCache="+(v.imageCache? "1":"0");
						//log(params);
						window.location.href = self.options.animatorCgi +'?'+params;
					});
					self.list.append(li);
					liWidth = (liWidth>li.outerWidth())?liWidth:li.outerWidth();
				}
			});
			this.preview.detach();
			this.preview.appendTo(this.widget());
			
			this.list.children().css('width',liWidth+"px");
			this.preview.css("left","-"+(liWidth-24)+"px");
		},
		_handleClick: function(){			
			var on_button=false;
			var self = this;
			
			this.button.bind('mousedown',function(e){
				e.preventDefault();
				if (!$(this).hasClass('down')) {
					$(this).addClass('down');
						self.preview.css({visibility:'visible'});//show();						
						on_button = true;
					} else {
						$(this).removeClass('down');
						self.preview.css({visibility:'hidden'});//hide();
					}
			}).hover(function() {
				on_button = true;
			}).mouseout(function() {
				on_button = false;
			});
			
			$(document).click(function(evt) {
				if(!on_button) {
					self.button.removeClass('down');
					self.preview.css({visibility:'hidden'});//hide();
				}
				on_button = false;
			});
		},
		_enablePresets: function(){
			var inputs = $(':input',this.context);
			var hidden = $(':hidden',this.context);
			this._setAvailable(this.animPresets.letters,inputs,"text");
			this._setAvailable(this.animPresets.letterSpacing,inputs,"letterSpacing");
			this._setAvailable(this.animPresets.letterRotate,inputs,"letterSpacing");
			this._setAvailable(this.animPresets.shadowOpacity,inputs,"shadowOpacity");
			
			
			
			//this.animPresets.letters.avail = inputs.filter($("[id$=text]")).length>0;
			//this.animPresets.letterSpacing.avail = inputs.filter($("[id$=letterSpacing]")).length>0;
			//this.animPresets.letterRotate.avail = inputs.filter($("[id$=letterSpacing]")).length>0;
			//this.animPresets.shadowOpacity.avail = inputs.filter($("[id$=shadowOpacity]")).length>0;
			this.animPresets.flashFire.avail = this._equalScript("flash-fire-logo",hidden);
			this._enablePresetRandom();
			
			this._setAvailable(this.animPresets.tileSizeIncrease,inputs,"tileSize");
			this._setAvailable(this.animPresets.tileSizeDecrease,inputs,"tileSize");
			
			this.animPresets.iceCube.avail = this._equalScript("ice-cube-logo",hidden);
			this.animPresets.burntPaper.avail = this._equalScript("burnt-paper-logo",hidden);
			this.animPresets.amazing3d.avail = this._equalScript("amazing-3d-logo",hidden);
		},
		_equalScript:function(script,input){
			return !!(this.animateMode? (input.filter("#"+this.options.idPrefix+"script").val()==script)
								:
								(input.filter("[name=script]").val()==script));
		},
		_setAvailable:function(preset,context,field){
			var element = context.filter("#"+this.options.idPrefix+field);
			if(element.length)
				preset.avail = true;
		}
		,_enablePresetRandom: function(){
			if(!("randomPreset" in this.animPresets))
				return;
			var hidden = $(':hidden',this.context);
			var script = "";
			if(this.animateMode)
				script = hidden.filter("#"+this.options.idPrefix+"script").val();
			else
				script = hidden.filter("[name=script]").val();
			
			this.animPresets.randomPreset.avail = !getImageCache(script);
		}
	});

	
})(jQuery);
function log(msg) {
	setTimeout(function() {
		throw new Error(msg);
	}, 0);
};
(function($){
	//datapicker widget
	$.widget( "ui.datapicker", {
		options:{
			tags:{
				names:{type:"list"
					,values:[
						{name:"new",title:"New"}
					]
					,showInLeftPanel:true
				}
				,alphabetical:{type:"table"
					, values:[
						{name: "a", title:"A"}
						,{name: "b", title:"B"}
						,{name: "c", title:"C"}
						,{name: "d", title:"D"}
						,{name: "e", title:"E"}
						,{name: "f", title:"F"}
						,{name: "g", title:"G"}
						,{name: "h", title:"H"}
						,{name: "i", title:"I"}
						,{name: "j", title:"J"}
						,{name: "k", title:"K"}
						,{name: "l", title:"L"}
						,{name: "m", title:"M"}
						,{name: "n", title:"N"}
						,{name: "o", title:"O"}
						,{name: "p", title:"P"}
						,{name: "q", title:"Q"}
						,{name: "r", title:"R"}
						,{name: "s", title:"S"}
						,{name: "t", title:"T"}
						,{name: "u", title:"U"}
						,{name: "v", title:"V"}
						,{name: "w", title:"W"}
						,{name: "x", title:"X"}
						,{name: "y", title:"Y"}
						,{name: "z", title:"Z"}
						,{name: "0", title:"#"}
					]
					, columns:5
					,showInTopPanel:true
					,showInLeftPanel:false
				}
			}
			,position:function(e,ui){
				//default is center of the screen	
				var p = ui.main;
				var pWidth = p.outerWidth();
				var pHeight = p.outerHeight();
				var top = ($(window).height() -pHeight)/2 + $(window).scrollTop() + "px";
				var left = ($(window).width() -pWidth)/2 + $(window).scrollLeft() + "px";
				p.css({
					top	:top
					,left	:left
				});
			
			} //where to display this widget, use ui.main to update top/left
			,ui:{
				header:"Data Picker"
				,showOutline:false
				,min_width:200
				,footer:{
					autocloseLabel:"Auto Close"
					,okayLabel:"Okay"
					,cancelLabel:"Cancel"
				}
				,previousTagLabel: "Previous"
				,topPanel:{
					show:false
					,showAlphabet:true
					,search:{
						enabled:true
						,searchLabel:"Search"
						,goLabel: "Go"
						,runAsYouType:true
						,searchAll:true//if false searches withing current tag; TODO: ui element(checkbox) to change this value
					}
					,closeLabel: "Close"
				}
				,leftPanel:{
					specialTags:{
						previous:{enabled:false,tagname:"dp_tag_previous",ui:"Previous"}
						,search:{enabled:true,tagname:"dp_tag_search",ui:"Search"}
					}
				}
				,rightPanel:{
					containerClass:"dp_div"
					,pagination:{
						itemsPerPage:10
						,pageLinks:5// so will show  something like: << < 7 8 9 10 11 > >>
					}
				}
			}
			//,showPreviousTag:true
			//,previousTagName: "dp_tag_previous"
			,controlElement:null //element that opens/closes this dialog
			,init:function(){}//to be defined in specific implementations
			,select:function(){}//to be defined in specific implementations
			,cancel:function(){}//to be defined in specific implementations
			,close:function(){}//to be defined in specific implementations
			,failed:function(){}//to be defined in specific implementations
			,autoclose:true
			,cacheAjaxResults:false //TODO
			,origValue:undefined//original value
			,initialTag:undefined//tag to select on init
		}
		,_create: function(){
			//list and describe variables here
			this.preview = undefined;//jquery object representing whole datapicker
			this.preview_outline = undefined;//jquery object representing outline (child of this.preview)
			this.preview_container = undefined;//jquery object representing container (child of this.preview_outline)
			this.preview_header = undefined;//jquery object representing header (child of this.preview_container)
			this.preview_body = undefined;//jquery object representing body (child of this.preview_container)
			this.preview_footer = undefined;//jquery object representing footer (child of this.preview_container)
			
			this.left_panel = undefined;//jquery object representing left panel of the body (child of this.preview_body)
			this.right_panel = undefined;//jquery object representing right panel of the body (child of this.preview_body)
			
			this.tags = undefined; //jquery object representing all the tags
			this.autoclose;//booolean if autoclose is set
			
			this.selectedTag = undefined;//currently selected tag
			this.previousTag = undefined;//previously selected tag
			this.selectedItem = undefined;//currently selected item
			this.prevItem = undefined;//previously selected item
			//this.previousItems = $([]);//jquery object representing previously selected items
			
			this.origValue = (this.options.origValue)? this.options.origValue : undefined;// original value
			this.initialTag = (this.options.initialTag)? this.options.initialTag : undefined;// initialTag value
			this.currentTag = this.initialTag;// selectedItem's tag
			this.items = {};//key = category name, value = dom element representing right_panel contents
			this.fn_queue = {};//queue of function to run when item is ready, ie user has to trigger 'item_ready' manually
			this.tagsProcessed = {};//processed tags
			this.working=false;
			
			this.imagebot = (typeof(window.dontUseMeAskCameron)!='undefined')? window.dontUseMeAskCameron : {};
			
			this._buildUI();
			this._cssFix();
			
			//user-specific behaviour(like updating other plugin-related objects, eg hidden field which stores the value of the selected font)
			if ($.isFunction(this.options.init)){
				this._trigger('init', null, this._ui());
			}
		}
		,_init: function(){}
		,_ui: function(){
			var self = this;

			var orig = {
				value:this.prevItem? this.prevItem.attr('dp_value'):this.origValue
				,escapedValue: self._escapedValue(this.prevItem? this.prevItem.attr('dp_value'):this.origValue)
				,tagname: this.initialTag
				,img_url: this.prevItem? this.prevItem.find('img').attr('src'):""
			};
			var selected = {
				value:this.selectedItem? this.selectedItem.attr('dp_value'):this.origValue
				,escapedValue: self._escapedValue(this.selectedItem? this.selectedItem.attr('dp_value'):this.origValue)
				,tagname: this.currentTag
				,img_url: this.selectedItem? this.selectedItem.find('img').attr('src'):""
			};
			
			return {
				main: this.preview
				,selected: selected
				,original: orig
				,controlElement:this.options.controlElement //in case we need to update it as well
				,escapeFn:this._escapedValue
			};
		}
		,_buildUI: function(){
			var o = this.options;
			this._createMain();
			this._createHeader();
			this._createBody();
			this._createFooter();
			
			//this._setWidths();//for cross-browser
			
			this._initControlElement();
			
			//hide now
			this.preview.hide();
			this.preview.css({visibility:'visible'});
		}
		,_cssFix: function(){
			var ie = navigator.appVersion.indexOf("MSIE")!=-1;
			var ieVersion = parseFloat(navigator.appVersion.split("MSIE")[1]);
			var ie9 = ie && ieVersion>=9 && ieVersion<10;
			
			if(ie9){
				this.preview_footer.add(this.preview_header).css({filter:"none"});
			
			}
			
		}
		,_initControlElement: function(){
			var o = this.options;
			var self = this;
			var c = o.controlElement;
			if(typeof(c) !='undefined' && c.length){
				c.addClass("dp_control_element");
				c.click(function(e){
					e.preventDefault();
					
					//is this opened now, get value here, because it will be different after $(document).trigger('click.datapicker')
					var open = self.preview.hasClass('dp_open');
					//this is to make sure click is fired for other(and this one) pickers to close
					$(document).trigger('click.datapicker');
					//this is to prevent form being submitted by input type:image
					e.stopImmediatePropagation();					
					if(open){
						self._close();
					}
					else{
						self._open();
					}
				});
			
			}
		}
		,_close: function(cancelled){
			var self = this;
			var o = this.options;
			if ($.isFunction(o.close)){
				self._trigger('close', null, self._ui());
			}
			
			if(!cancelled)
				this._addToPreviousItems();
			this.initialTag = this.currentTag;
			
			var key = this._getKey(this.currentTag);
			this.items[key].pageWithSelection = this.items[key].pageWithSelectionUnconfirmed;
			
			//this.preview.css({visibility:'hidden'});
			this.preview.hide();
			this.preview.removeClass('dp_open');
			//remove all bound events from the document
			$(document).unbind('.datapicker');
		}
		,_open: function(){
			var self = this;
			var o = this.options;

			//postion on open as window might have moved/resized
			if ($.isFunction(o.position)){
				this._trigger('position', null, this._ui());
			}
			
			if ($.isFunction(o.open)){
				self._trigger('open', null, self._ui());
			}
			
			//this.preview.css({visibility:'visible'});
			this.preview.show();
			this.preview.addClass('dp_open');
			
			$(document).bind('click.datapicker',{dp:self}, function(e){
				if (!$(e.target).parents().andSelf().is(e.data.dp.preview)) {
		                	e.data.dp._close();
		        	}
			});
			$(document).bind('keyup.datapicker',{dp:self}, function(e){
				var dp = e.data.dp;
				if (e.keyCode == 27 && dp.preview.hasClass('dp_open')){
					dp._close();
				}
			});
			
			this._selectTag_string(this.initialTag);
			
		}
		,_cancel:function(){
			var self = this;
			var o = this.options;
			if ($.isFunction(o.cancel)){
				self._trigger('cancel', null, self._ui());
			}
			if(typeof(this.selectedItem) != 'undefined')
				this.selectedItem.removeClass('selectedItem');
			
			//restore orig value here
			this.selectedItem = this.prevItem;
			this.currentTag = this.initialTag;
			
			//ensure we have correct item for selectedItem css class
			this.right_panel.find('.selectedItem').removeClass('selectedItem');
			
			var val = (typeof(this.selectedItem)!='undefined' && this.selectedItem.length)? this.selectedItem.attr('dp_value') : this.origValue;
			if(val){
				var key = this._getKey(this.currentTag);
				var pageWithSelection = this.items[key].pageWithSelection ||0;
				this.items[key].pageWithSelectionUnconfirmed = pageWithSelection;
				var page = this.items[key].pages[pageWithSelection].cache;
								
				this.selectedItem = page.find('[dp_value="'+val+'"]').addClass('selectedItem');
				this.right_panel.find('[dp_value="'+val+'"]').addClass('selectedItem');
			}
			
			
			this._close(true);
		}
		,_failed:function(status,empty,tag){
			var self = this;
			var o = this.options;
			//user-specific behaviour(like updating other plugin-related objects, eg hidden field which stores the value of the selected font)
			if ($.isFunction(o.failed)){
				self._trigger('failed', null, self._ui());
			}
			
			if(typeof empty != 'boolean')
				empty=true;
			if(empty && this.selectedTag.is(tag))
				this._tagListEmpty(tag);
				
			if(tag.attr('tagname')!=o.ui.leftPanel.specialTags.search.tagname)
				throw new Error("datapicker failed: "+status);
		}
		,_showSearchHint:function(tag){
			var key = this._getKey(tag);
			var div = this._tagListEmpty(tag).html("Please type in the search box");
			var emptyDiv = $("<div></div>");
			this.items[key] = {
				pageWithSelection:0//if we have selected item in this tag, this is the page the item is in
				,pageWithSelectionUnconfirmed:0//currently selected item's page
				,currentPage:0//currently displayed page
				,container:emptyDiv
				,pages:[{items:["noresults"],cache:emptyDiv.append(div.clone())}]
			};
		}
		,_saveSearchEmpty:function(status,empty,tag, searchTerm){
			var key = this._getKey(tag, searchTerm);
			var div = this._tagListEmpty(tag);
			var emptyDiv = $("<div></div>");
			this.items[key] = {
				pageWithSelection:0//if we have selected item in this tag, this is the page the item is in
				,pageWithSelectionUnconfirmed:0//currently selected item's page
				,currentPage:0//currently displayed page
				,container:emptyDiv
				,pages:[{items:["noresults"],cache:emptyDiv.append(div.clone())}]
			};
		}
		,_tagListEmpty:function(tag){
			this.shownSearch="";
			var str = "Category empty.";
			if(tag.attr('tagname')==this.options.ui.leftPanel.specialTags.search.tagname)
				str = "No search results";
			var div = $("<div class=\"dp_failed_div\">"+str+"</div>");
			this.right_panel.html(div);
			return div;
		}
		,_createMain: function(){
			var o = this.options;
						
			this.main = $("<div class=\"dp_main\"></div>").appendTo('body');
			this.preview = $("<div class=\"dp_preview_dialog\"></div>").appendTo(this.main);
			//make it draggable, but disallow dragging dp_preview_body because it has scroll bars which need to be dragged
			this.preview.draggable({cancel:".dp_preview_body"});
			
			this._buildOutline();
			this.preview_container = $("<div class=\"dp_preview_dialog_container\"></div>").appendTo(this.preview_outline);
		}
		,_buildOutline:function(){
			var o = this.options;
			this.preview_outline = $("<div class=\"dp_preview_dialog_outline\"></div>").appendTo(this.preview);
			
			//dont show for IE8 and lower
			if(o.ui.showOutline && 
				(this.imagebot.length || (navigator.appVersion.indexOf("MSIE")!=-1 && parseFloat(navigator.appVersion.split("MSIE")[1])<9))
				){
				o.ui.showOutline = false;
			}
			
			if(!o.ui.showOutline){
				this.preview_outline.css({
					padding:'0px'
					,border:'0px'
				});
			}
		}
		,_createHeader: function(){
			var o = this.options;
			var self = this;
			this.preview_header = $("<div class=\"dp_preview_header\">"+o.ui.header+"</div>").appendTo(this.preview_container);
			var close = $("<div class=\"dp_preview_dialog_close\"></div>").appendTo(this.preview_header);
			var img = $("<img src='http://cdn1.ftimg.com/images/stock_delete.png' title='"+o.ui.topPanel.closeLabel+"'/>").appendTo(close);

			close.bind('click.datapicker',{self:self}, function(e){
				e.data.self._close();
			});
			
			
			o.ui.min_width = o.ui.min_width>this.preview_header.width() ? o.ui.min_width : this.preview_header.width();
		}
		,_createBody: function(){
			var o = this.options;
			
			this.preview_body = $("<div class=\"dp_preview_body\"></div>").appendTo(this.preview_container);
			/*this.preview_body.css({
				width:o.css.dimension.width
				,height:o.css.dimension.height
			});
			*/
			this.tags = $([]);
			
			this._createTopPanel();
			this._createLeftPanel();
			this._createRightPanel();
			
			o.ui.min_width = o.ui.min_width>this.preview_body.width() ? o.ui.min_width : this.preview_body.width();
			var body_h = (o.ui.topPanel.show? this.top_panel.outerHeight():0) + this.left_panel.outerHeight();
			this.preview_body.css('height',body_h);
				
		}
		,_createTopPanel: function(){
			var o = this.options;
			if(!o.ui.topPanel.show){
				var tags = o.ui.leftPanel.specialTags;
				for(var key in tags){
					tags[key].enabled=false;
				}
				return;
			}
			this.top_panel = $("<div class=\"dp_top_panel\"></div>").appendTo(this.preview_body);
			
			this._buildSearchPanel();
			this._buildTopPanelAlphabet();
		}
		,_buildSearchPanel:function(){
			var o = this.options;
			if(!o.ui.topPanel.search.enabled){
				o.ui.leftPanel.specialTags.search.enabled=false;
				return;
			}
			this.top_panel_search = $("<div class=\"dp_top_panel_search\"></div>").appendTo(this.top_panel);
			this.search_field = $("<input class=\"search_field\" value=\"\"/>").appendTo(this.top_panel_search);
			this.search_field.hintedInput({
				hintText:"Search"
				,hintCss:{
					color:"#555"
				}
			});
			if(o.ui.topPanel.search.runAsYouType){
				this._registerSearchFieldChanges();
			}
			/*//no go button for now
			var go = $("<input class=\"go_btn\" type=\"button\" value=\""+o.ui.topPanel.search.goLabel+"\"/>").appendTo(this.top_panel_search);
			go.bind('click.datapicker',{self:this},function(e){
				//e.data.self._runSearch();
				e.data.self.search_field.trigger('change.datapicker');
			});
			*/
		}
		,_registerSearchFieldChanges:function(){
			this.search_field.bind('change.datapicker',{self:this}, function(e){
				var val = $(this).hintedInput("val");
				if(val=="") return;

				var self = e.data.self;
				if((!self.runningXhr && (!self.shownSearch || self.shownSearch!=val))//shown search results are for a different search term
					||(self.runningXhr && self.runningXhr.searchTerm != encodeURIComponent(val))//current ajax call search is different
					||self.selectedTag.attr('tagname')!=self.options.ui.leftPanel.specialTags.search.tagname//we are on a different tag
				){
					if(self.runningXhr)
						self.runningXhr.abort();
					e.data.self._runSearch();
				}
				
			}).bind('keyup.datapicker',{self:this}, function(e){
				var val = $(this).val();
				var delay = 100;
				//its slow for 1-letter searches, so lets delay it more, ie we assume user will type more letters
				if(val.length<2)
					delay=500;
				
				setTimeout(function(){
					e.data.self.search_field.trigger('change.datapicker');
				},delay);//to reduce number of calls

			});
		}
		,_runSearch:function(){
			var searchTagname = this.options.ui.leftPanel.specialTags.search.tagname;
			this._selectTag_string(searchTagname);
		}
		,_buildTopPanelAlphabet: function(){
			var alphabet = this.options.tags.alphabetical;
			if(alphabet.showInTopPanel && this.options.ui.topPanel.showAlphabet){
				var container = $("<div class=\"dp_top_panel_alphabet\"></div>").appendTo(this.top_panel);
				var letters = alphabet.values;
				if(letters && letters.length){
					var ul = $("<ul class=\"dp_top_panel_alphabet_ul\"></ul>").appendTo(container);
					var self = this;
					$.each(letters, function(i,c){
						if(!c.title){
							c.title = c.name;
						}
						var li = $("<li tagname=\""+c.name+"\" title=\""+c.title+"\">"+c.title+"</li>").appendTo(ul);
						self._addTag(li);
					});
				
				}
			}
		}
		,_createLeftPanel: function(){
			var self = this;
			var o = this.options;
			this.left_panel = $("<div class=\"dp_left_panel\"></div>").appendTo(this.preview_body);
			/*this.left_panel.css({
				width:o.css.dimension.leftPanel.width
				,height:o.css.dimension.leftPanel.height
			});
			*/
			this._addTags();
		}
		,_addTags: function(){
			var self = this;
			var o = this.options;
			var tags = o.tags;
			
			this._addSpecialTags();
			
			$.each(tags, function(k,tag){
				if(tag.showInLeftPanel){
					var t = tag.type;
					
					if(t=="list"){
						self._buildTagList(tag);
					}
					else if(t=="table"){
						self._buildTagTable(tag);
					}
				}
			});
		
		}
		,_addSpecialTags:function(){
			var o = this.options;
			
			var haveTags = false;
			var tags = o.ui.leftPanel.specialTags;
			for(var key in tags){
				var t = tags[key];
				if(t.enabled){
					haveTags = true;
					break;
				}
			}
			if(!haveTags)
				return;
			
			
			var div = $("<div class=\"dp_tag_div\"></div>").appendTo(this.left_panel);
			var ul = $("<ul class=\"dp_tag_list\"></ul>").appendTo(div);
			for(var key in tags){
				var t = tags[key];
				if(t.enabled){
					t.items = $();
					var tag = $("<li tagname=\""+t.tagname+"\" title=\""+t.ui+"\">"+t.ui+"</li>").appendTo(ul);
					this._addTag(tag);
				}	
			}
		}
		,_buildTagList:function(tag){
			var self = this;
			var o = this.options;
			if(tag.values && tag.values.length){
				var div = $("<div class=\"dp_tag_div\"></div>").appendTo(this.left_panel);
				var ul = $("<ul class=\"dp_tag_list\"></ul>").appendTo(div);
				$.each(tag.values, function(i,c){
					if(!c.title)
						c.title = c.name;
					var li = $("<li tagname=\""+c.name+"\" title=\""+c.title+"\">"+c.title+"</li>").appendTo(ul);
					self._addTag(li);
				});
			}
		}
		,_buildTagTable:function(tag){
			var self = this;
			var o = this.options;
			if(typeof tag.values != 'undefined' && tag.values.length){
				var div = $("<div class=\"dp_tag_div\"></div>").appendTo(this.left_panel);
				var table = $("<table class=\"dp_tag_table\"></table>").appendTo(div);
				var tbody = $("<tbody></tbody>").appendTo(table);
				var columns = tag.columns;
				var rows = Math.ceil(tag.values.length / columns);
				
				for(var ir = 0; ir<rows;ir++){
					var tr = $("<tr></tr>").appendTo(tbody);
					for(var ic = 0; ic<columns;ic++){
						var index = ir*columns+ic;
						if(index < tag.values.length){
							var c = tag.values[index];
							if(typeof(c.title) == 'undefined'){
								c.title = c.name;
							}
							//console.log("index:"+index+";len:"+tag.values.length+";val:"+c.name);
							var td = $("<td tagname=\""+c.name+"\" title=\""+c.title+"\">"+c.title+"</td>").appendTo(tr);
							self._addTag(td);
						}
						else break;
					}
				}
			}
		}
		,_addTag:function(tag){
			var self = this;
			var o = this.options;
			tag.click(function(e){
				self._selectTag($(this));
			});
			this.tags = this.tags.add(tag);
		}
		,_selectTag_string: function(tag){
			if(typeof(tag)=='string' && tag.length){
				var $tag = this.tags.filter('[tagname="'+tag+'"]');
				this._selectTag($tag);
			}
		}
		,_isSpecialTag:function(tagname){
			var tags = this.options.ui.leftPanel.specialTags;
			for(var t in tags){
				if(tagname == tags[t].tagname)
					return true;
			}
			return false;
		}
		,_selectTag:function(tag){
			var self = this;
			var o = this.options;
			var key = this._getKey(tag);
			
			if(typeof(this.selectedTag)=='undefined' || !this.selectedTag.is(tag)
				|| (this.items[key] && this.items[key].currentPage != this.items[key].pageWithSelection)
				||(tag.attr('tagname')==o.ui.leftPanel.specialTags.search.tagname && this.shownSearch != this.search_field.hintedInput("val"))){
				//do NOT update previous tag if we are already on search tag
				if(!this.selectedTag || (tag.attr('tagname')!=o.ui.leftPanel.specialTags.search.tagname && !this.selectedTag.is(tag)))
					this.previousTag = this.selectedTag;
				//TODO: save all specialTag results
				/*
				if(typeof(this.previousTag)!='undefined' && this._isSpecialTag(this.previousTag.attr('tagname'))){
					//clone this because right_panel is about to be emptied, but we need to remember these items(with events)
					//this.previousItems = this.previousItems.clone(true,true);
					var specialTag = o.ui.leftPanel.specialTags[this._getSpecialTagKeyByTagname(this.previousTag.attr('tagname'))];
					specialTag.items = specialTag.items.clone(true,true);
				}*/
				this.selectedTag = tag;
				
				this.right_panel.empty();
				this._setLoading(true,tag);
				
				if(this.selectedTag.attr('tagname')==o.ui.leftPanel.specialTags.search.tagname)
					this.shownSearch = this.search_field.hintedInput("val")||this.shownSearch||"";

				var key = this._getKey(tag);
				var page = undefined;
				if(this.items[key]){
					this.items[key].currentPage = this.items[key].pageWithSelection;
					var currentPage = this.items[key].currentPage;
					page = this.items[key].pages[currentPage].cache;
				}
						
				if(o.cacheAjaxResults && typeof(this.selectedTag)!='undefined' && this.selectedTag.attr('tagname') != o.ui.leftPanel.specialTags.previous.tagname //dont cache "previous" tag
					&& typeof(page)!='undefined'){
					
					//if we have same item in 2+ tags, ensure we always have 1 selectedItem(in the current tag) and 'selectedItem' class is updated correctly
					//eg.Featured, select chrominium,then open Light, chrominium is there too so it is set as selectedItem(as part of first time fetch)
					//now when we go back to Featured it uses cache. At this point we need to ensure selectedItem is reset to the cached item in Featured tag,
					//otherwise it will not be selected in right panel on display.
					if(this.selectedItem){
						
						var newSelectedItem = page.find('[dp_value="'+self.selectedItem.attr('dp_value')+'"]');
						if(newSelectedItem.length){
							this.selectedItem.removeClass('selectedItem');
							this.selectedItem = newSelectedItem.addClass("selectedItem");
							this.currentTag = this.initialTag = this.selectedTag.attr('tagname');
						}
					}
					
					this._showItems(this.selectedTag);
				}
				else{
					this._getData(tag,(this.selectedItem && this.selectedItem.length)?this.selectedItem.attr('dp_value'):this.origValue);
				}
				
				
				this.tags.not(tag).removeClass('selectedTag');
				tag.addClass('selectedTag');
			}
		}
		,_saveItems:function(opts){
			var values = opts.values;//array
			var tag = opts.tag;
			
			var container = $("<div></div>");
			if(this.options.ui.rightPanel.containerClass)
				container.addClass(this.options.ui.rightPanel.containerClass);
			
			var key = this._getKey(tag,opts.searchTerm);
			var itemsPerPage = this.options.ui.rightPanel.pagination.itemsPerPage;
			var size = values.length;
			var pages = Math.ceil(size/itemsPerPage);
			
			var arr = [];
			for(var i=0;i<pages;i++){
				var minIndex = i*itemsPerPage;
				var maxIndex = Math.min(minIndex+itemsPerPage,size);
				arr[i] = {
					items: values.slice(minIndex,maxIndex)
					,cache:undefined
				}
			}
			
			this.items[key] = {
				pageWithSelection:0//if we have selected item in this tag, this is the page the item is in
				,pageWithSelectionUnconfirmed:0//currently selected item's page
				,currentPage:0//currently displayed page
				,container:container
				,pages:arr
			};
		}
		,_getKey:function(tag, searchTerm){
			var key = $.type(tag)=="string"?tag:tag.attr('tagname');
			if(key==this.options.ui.leftPanel.specialTags.search.tagname){
				var srch = searchTerm ? searchTerm:(this.search_field.hintedInput("val")||this.shownSearch||"");
				key+="&q="+srch;
			}
			//console.log("key:"+key);
			return key;
		}
		,_loadItems:function(key,currentPage){
			var page = this.items[key].pages[currentPage];
			var items = page.cache.children();
			var self = this;
			$.each(items,function(i,item){
				if(!$(item).hasClass('dp_item_ready'))
					self._loadItem($(item));
			});
			
			
		}
		,_loadItem:function(div){}//to de defined by extending classes
		,_showItems:function(tag){
			if(!tag)
				tag = this.selectedTag;
			if(!this.selectedTag.is(tag))
				return;
			var key = this._getKey(tag);
			if(!$.isPlainObject(this.items[key]) || !this.items[key].pages.length)
				throw new Error("Items are not saved,key:"+key);
			
			var currentPage = this.items[key].currentPage;
			var page = this.items[key].pages[currentPage];
			
			//page not cached
			if(typeof(page.cache) == 'undefined')
				this._cachePage(tag,key,currentPage);
			
			
			//other category might have been selected while this has not loaded
			if(this.selectedTag.is(tag)){
				this._displayItems(key,currentPage);
				
				if(this.options.ui.leftPanel.specialTags.search.tagname == tag.attr('tagname'))
					this.shownSearch = this.search_field.hintedInput("val")||this.shownSearch;
			}
			
		}
		,_displayItems:function(key,currentPage){
			var page = this.items[key].pages[currentPage];
			var items = page.cache;
			
			if(typeof(items)=='undefined')
				throw new Error("items cache for page "+currentPage+" is empty");
			
			
			var paginationPanel = this._buildPagination(this.items[key].pages.length, this.items[key].currentPage,key);
			
			//this may be delayed untill all(or first) items are actually loaded
			this._itemsLoaded(this.selectedTag, (items.length?false:true));
			
			var clone = items.clone(true,true).css({
				position:''
				,top:''
				,visibility:''
			});
			
			this.right_panel.empty()
				.append(this._buildInfoPanel(items))
				.append(paginationPanel)
				.append(clone)
				.append(paginationPanel.clone(true,true));
			
			this._loadItems(key,currentPage);
		}
		,_cachePage: function(tag,key,currentPage){
			var page = this.items[key].pages[currentPage];
			var container = this.items[key].container.clone();
			
			if(container && container.length){
				var self = this;
				container.css({
					position:'absolute'
					,top:'-10000px'
					,visibility:'hidden'
				}).appendTo(this.main);
				var items = page.items;
				
				//build dom and assign events
				$.each(items, function(i,item){
					var $item = self._buildItem(item, tag, container);//defined by extending class
					self._bindItemEvents($item,key,currentPage);
					
					var sel = (self.selectedItem && self.selectedItem.length)?self.selectedItem.attr('dp_value'):self.origValue;
					if(sel && item==sel){
						//if we have selectedItem in this tag too, reassing selectedItem
						if(self.selectedItem)
							self.selectedItem.removeClass('selectedItem');
						self.currentTag = self.initialTag =  tag.attr('tagname');
						self.selectedItem = $item.addClass("selectedItem");
					}
				});
				
				page.cache = container;
			}
			
		
		}
		,_buildItem:function(item, tag, container){}//how to display an item - defined by extending class
		,_buildInfoPanel:function(items){
			/*var n = items.children().length;
			var ret = $('<div class="dp_items_info"></div>');
			var pageMsg = $('<div class="dp_items_info_totalMsg">Total: '+n+' item'+(n>1?'s':'')+'</div>').appendTo(ret);
			*/
			
			if(this.options.ui.leftPanel.specialTags.search.tagname != this.selectedTag.attr('tagname'))
				return;
			
			var ret = $('<div class="dp_items_info"></div>');
			var pageMsg = $('<div class="dp_items_info_totalMsg">Search: "'+this.shownSearch+'"</div>').appendTo(ret);
			
			return ret;
		}
		,_buildPagination:function(len, currentPage, key){
			var ret = $();
			if(len<2)
				return ret;
			
			var pageToShow = currentPage+1;
			
			var pageLinks = this.options.ui.rightPanel.pagination.pageLinks;
			
			ret = $('<div class="dp_pagination"></div>');
			var pageMsg = $('<div class="dp_pagination_pageMsg">Page '+pageToShow+' of '+len+'</div>').appendTo(ret);
			
			var buttons = $('<div class="dp_pagination_buttons"></div>').appendTo(ret);
			//if(currentPage!=0)
				//var first = $('<button class="dp_pagination_button first_page" value="0">First</button>').appendTo(buttons);
			var prev = $('<button class="dp_pagination_button prev_page" value="'+(currentPage==0?len-1:currentPage-1)+'">&lt;</button>').appendTo(buttons);
			
			/*
			var pageLinksToTheLeft = Math.floor((pageLinks-1)/2);
			var pageLinksToTheRight = pageLinks - pageLinksToTheLeft -1;
			//max pages to the left and to the right of selected page
			if(currentPage-pageLinksToTheLeft<0){
				pageLinksToTheLeft = currentPage-1;
				pageLinksToTheRight = Math.min(pageLinks - pageLinksToTheLeft -1,len-currentPage);
			}
			else if(currentPage+pageLinksToTheRight>len){
				pageLinksToTheRight = len-currentPage;
				pageLinksToTheLeft = Math.min(pageLinks - pageLinksToTheRight -1,currentPage-1);
			}
			this._buildPageLinksLeft(pageLinksToTheLeft,currentPage,len,buttons);
			var selected_button = $('<button class="dp_pagination_button selected_page" value="'+currentPage+'">'+pageToShow+'</button>').appendTo(buttons);
			this._buildPageLinksRight(pageLinksToTheRight,currentPage,len,buttons);
			*/
			var next = $('<button class="dp_pagination_button next_page" value="'+(currentPage==len-1?0:currentPage+1)+'">&gt;</button>').appendTo(buttons);
			//if(currentPage!=len-1)
			//	var last = $('<button class="dp_pagination_button last_page" value="'+(len-1)+'">Last</button>').appendTo(buttons);
			
			buttons.children('button').bind('click.datapicker',{self:this, currentPage:currentPage, key:key},function(e){
				if(e.data.currentPage == parseInt($(this).val()))
					return;
				e.stopPropagation();
				
				var self = e.data.self;
				self._setLoading(true,self.selectedTag);
				self.items[e.data.key].currentPage = parseInt($(this).val());
				self._showItems(self.selectedTag);
			});
			
			
			return ret;
		}
		/*
		,_buildPageLinksLeft:function(n,pageToShow,pages,buttons){
			if(pageToShow-n>1)
				var dots = $('<span class="dp_pagination_dots">..</span>').appendTo(buttons);
			while(n>0){
				var button = $('<button class="dp_pagination_button" value="'+(pageToShow-n)+'">'+(pageToShow-n)+'</button>').appendTo(buttons);
				n--;
			}
		}
		,_buildPageLinksRight:function(n,pageToShow,pages,buttons){
			var i = 1;
			while(i<=n){
				var button = $('<button class="dp_pagination_button" value="'+(pageToShow+i)+'">'+(pageToShow+i)+'</button>').appendTo(buttons);
				i++;
			}
			if(pageToShow+n<pages)
				var dots = $('<span class="dp_pagination_dots">..</span>').appendTo(buttons);

		}*/
		,_bindItemEvents: function(item,key,currentPage){
			var self = this;
			item.bind('item_ready',{dp:self}, function(e){
				$(this).addClass('dp_item_ready');
				var dp = e.data.dp;
				//ensure right panel has updated(ready) item
				var val = $(this).attr('dp_value');
				var displayedItem = dp.right_panel.find('[dp_value="'+val+'"]');
				if(displayedItem.length){
					var clone = $(this).clone(true,true);
					var prev = displayedItem.prev();
					var parent = displayedItem.parent();
					displayedItem.remove();
					
					if(prev.length)
						clone.insertAfter(prev);
					else
						parent.prepend(clone);
				}
				
				if(dp.fn_queue[val]){
					while(dp.fn_queue[val].length){
						dp.fn_queue[val].shift()();//shift and run the fn from the queue
					}
				}
			});
			
			item.bind('click.datapicker',{dp:self, item:item, key:key,currentPage:currentPage},function(e){
				//NOTE: we use 'item' not $(this), because we want to select in items cache.
				//items cache will be cloned wiht data/events so this way the correct item is used within a handler
				
				e.data.dp.items[e.data.key].pageWithSelectionUnconfirmed = e.data.currentPage;
				e.data.dp._selectItem(e.data.item);
			
			});
		}
		,_setLoading:function(loading, tag){
			if(loading){
				var searching = this.options.ui.leftPanel.specialTags.search.tagname == tag.attr('tagname');
				var msgText="Loading: "+tag.attr('title');;
				if(searching)
					msgText = "Searching: <p>\""+ this.search_field.val()+"\"</p>";
				
				var loadingDiv = $("<div class=\"dp_loading_div\"></div>").appendTo(this.right_panel);
				var msg = $("<div class=\"dp_loading_message\">"+msgText+"</div>").appendTo(loadingDiv);
				var img = $("<img class=\"dp_loading_indicator\" src=\"/images/loading.gif\"/>").appendTo(loadingDiv);
				this.working=true;
			}
			else if(tag.attr('tagname') == this.selectedTag.attr('tagname')){
				this.right_panel.empty();
				this.working=false;
			}
		}
		,_getData: function(tag,selectItem){
			var self = this;
			var o = this.options;
			
			if(this._getSpecialTag(tag))
				return true;
			
			return false;
		}
		,_getSpecialTagKeyByTagname: function(tagname){
			var tags = this.options.ui.leftPanel.specialTags;
			for(var t in tags){
				if(tagname == tags[t].tagname)
					return t;
			}
			return undefined;
		}
		,_getSpecialTag: function(tag){
			var self = this;
			var o = this.options;
			if(this._isSpecialTag(tag.attr('tagname'))){
				var specialTag = o.ui.leftPanel.specialTags[this._getSpecialTagKeyByTagname(tag.attr('tagname'))];
				
				//this.previousItems = this.previousItems.clone(true,true);
				this._setLoading(false,tag);
				var div = $("<div class=\"dp_preview_list\"></div>").appendTo(this.right_panel);
				//this.previousItems.appendTo(div);
				specialTag.items.appendTo(div);
				return true;
			}
			return false;
		}
		,_getItems: function(tag, data){ //to be overriden
		}
		,_itemsLoaded: function(tag, empty){
			this._setLoading(false,tag);
			if(empty){
				this._tagListEmpty(tag);
			}
		}
		,_selectItem: function(item){//can be added-to(by overriding and calling $.ui.datapicker.prototype._selectItem.apply(this, arguments)) but common behaviour is here
			var self = this;
			var o = this.options;
			
			if(typeof(this.selectedItem) != 'undefined')
				 this.selectedItem.removeClass('selectedItem');
			
			this.selectedItem = item;
			this.selectedItem.addClass('selectedItem');
			this.currentTag = this.selectedTag.attr('tagname');
			
			//update on the right_panel too
			this.right_panel.find('[dp_value="'+item.attr('dp_value')+'"]').addClass('selectedItem').siblings().removeClass('selectedItem');
			
			if(this.autoclose)
				this._close();
				
			//user-specific behaviour(like updating other plugin-related objects, eg hidden field which stores the value of the selected font)
			if ($.isFunction(o.select)){
				//var ui = self._ui();//this gives ui object as it now, ie not guaranteed to be same when item is ready
				this._ready(item,function(){
					//ensure we still have this item selected
					//this may be false in case we selected other item while this one is still loading(ie not ready)
					if(self.selectedItem.is(item))
						self._trigger('select', null, self._ui());
				});
			}
		}
		,_ready:function(item,fn){
			if(this._isItemReady(item))
				fn();
			else{
				var val = item.attr('dp_value');
				if(!this.fn_queue[val])
					this.fn_queue[val] = [];
				this.fn_queue[val].push(fn);
			}
		}
		,_isItemReady:function(item){
			return item.hasClass('dp_item_ready');
		}
		,_addToPreviousItems:function(){
			if(typeof(this.selectedItem)=='undefined')
				return;
			this.prevItem = this.selectedItem;//.clone(true,true);
			//this.prevItem.removeClass('selectedItem');
			
			if(!this.options.ui.leftPanel.specialTags.previous.enabled)
				return;
			
			var dp_value = this.prevItem.attr('dp_value');
			var previousTag = this.options.ui.leftPanel.specialTags.previous;
			var items = previousTag.items;
			
			//if(this.previousItems.filter('[dp_value="'+escapedVal+'"]').length)
			//use the following instead of the line above because '[attr="val"]' selector does not handle special chars in variable, eg Pee's Celtic Italic
			if(items.filter(function(){return $(this).attr("dp_value")==dp_value;}).length)
				return;//do not add
			
			//add to the beginning
			//this.previousItems.unshift(this.prevItem);
			//this.previousItems = this.previousItems.clone(true,true);
			//this.previousItems = this.prevItem.add(this.previousItems);

			previousTag.items = this.prevItem.add(items.clone(true,true));
		}
		,_escapedValue: function(val){
			if(typeof(val)!="string")
				return "";
			var ret = "";
			for(var i=0;i<val.length;i++){
				if(val.charAt(i)==' ')
					ret+='+';
				else
					ret+=val.charAt(i);
			}
			return encodeURIComponent(ret);
		}
		,_createRightPanel: function(){
			var self = this;
			var o = this.options;
			this.right_panel = $("<div class=\"dp_right_panel\"></div>").appendTo(this.preview_body);
			var right_panel_width = this.preview_body.width()-this.left_panel.outerWidth();
			this.right_panel.css('width',right_panel_width+"px");
			
			/*this.right_panel.css({
				width:o.css.dimension.rightPanel.width
				,height:o.css.dimension.rightPanel.height
			});*/
		}
		,_createFooter: function(){
			var self = this;
			var o = this.options;
			
			this.preview_footer = $("<div class=\"dp_preview_footer\"></div>").appendTo(this.preview_container);
			/*this.preview_footer.css({
				width:o.css.dimension.bottomPanel.width
				,height:o.css.dimension.bottomPanel.height
			});
			*/
			this._createAutoclose();
			this._createFooterButtons();
			
			o.ui.min_width = o.ui.min_width>this.preview_footer.width() ? o.ui.min_width : this.preview_footer.width();
		}
		,_createAutoclose: function(){
			var self = this;
			var o = this.options;
			
			this.autoclose = (typeof(o.autoclose)=='boolean')? o.autoclose : true;
			
			var div = $("<div class=\"dp_autocloseDiv\"></div>").appendTo(this.preview_footer);
			
			var checkbox = $("<input type=\"checkbox\" class=\"dp_autocloseDiv\"/>").appendTo(div);
			checkbox.prop("checked", this.autoclose);
			checkbox.bind('change.datapicker',{dp:self}, function(e){
				var dp = e.data.dp;
				dp.autoclose = !!$(this).prop("checked");
			});
			
			var label = $("<span class=\"dp_autocloseLabel\">"+o.ui.footer.autocloseLabel+"</span>").appendTo(div);
			label.bind('click.datapicker',{cb:checkbox}, function(e){
				e.data.cb.trigger('click').trigger('change');//need to trigger change for ie6
			});

		}
		,_createFooterButtons:function(){
			var self = this;
			var o = this.options;
			
			var div = $("<div class=\"dp_footerButtons\"></div>").appendTo(this.preview_footer);
						
			var cancel = $("<a href=\"\" class=\"dp_preview_button_cancel\">"+o.ui.footer.cancelLabel+"</a>").appendTo(div);
			cancel.bind('click.datapicker',{dp:self},function(e){
				e.preventDefault();
				var dp = e.data.dp;
				dp._cancel();
			});
			
			var okay = $("<input type=\"button\" class=\"dp_preview_button_okay\" value=\""+o.ui.footer.okayLabel+"\"/>").appendTo(div);
			okay.bind('click.datapicker',{dp:self},function(e){
				var dp = e.data.dp;
				dp._close();
			});
		
		}
		,_setWidths: function(){
			var self = this;
			var o = this.options;
			//set this explicitly for cross-browser gradients display
			//this ensures hasLayout is set for gradients to work in IE
			var width =  o.ui.min_width;
			this.preview_header.css('width',width+"px");
			this.preview_body.css('width',width+"px");
			this.preview_footer.css('width',width+"px");
			this.preview.css('width',"auto");//.width(width);
		}
		,destroy: function(){
			var self = this;
			self._close();
			self.element
				.removeClass("dp_control_element")
				.unbind('.datapicker')
				.removeData('datapicker');
			return self;
		}
	});
	
	//ajaxpicker widget, extends datapicker
	$.widget( "ui.ajaxpicker", $.extend({},$.ui.datapicker.prototype, {
		options:{
			ajaxCategory: "fonts"
			,ajaxFailed:function(){} //function to run when ajax fails
			,ajaxHost:""
			,ajaxCgi:"/net-fu/ajax.cgi"
		}
		,_create: function(){
			var opts = this.options;
			//ensure we have default datapicker options(and override them)
			//note: we do recursive merge here
			this.options = $.extend(true,{},$.ui.datapicker.prototype.options, opts);
			//this.element.data('ui.datapicker', this.element.data('ui.ajaxpicker'));
			$.ui.datapicker.prototype._create.apply(this, arguments);
			}
		,_getData: function(tag){
			var self = this;
			var o = this.options;
			var tag_str = tag.attr('tagname');
			var searching = o.ui.leftPanel.specialTags.search.tagname == tag_str && this.search_field.hintedInput("val")!="";
			
			if(o.ui.leftPanel.specialTags.search.tagname == tag_str && this.search_field.hintedInput("val")==""){
				this._showSearchHint(tag);
				return;
			}
			
			//if we selected "Previous" tag dont query
			if(!searching && $.ui.datapicker.prototype._getData.apply(this, arguments))
				return;
			
			var queryTag = encodeURIComponent(tag_str);
			var querySearch = "";
			if(searching){
				if(o.ui.topPanel.search.searchAll)
					queryTag = encodeURIComponent("_all");// for now, but can be any tag
				else
					queryTag = encodeURIComponent(this.previousTag.attr('tagname'));//use previous because we just switched to "search" tag from it.
				querySearch = encodeURIComponent(this.search_field.hintedInput("val"));
			}
			
			var context = {self:self, tag:tag, searching:searching, searchTerm:(this.search_field ? this.search_field.hintedInput("val"):"")};
			var u=o.ajaxHost;
			//if (this.imagebot.length)
				//u = this.imagebot.getConfigManager().getConfig().ftHost;
			u+=o.ajaxCgi+"?c="+o.ajaxCategory+"&t="+queryTag;
			if(searching)
				u+="&q="+querySearch;
			
			this.runningXhr = $.ajax({url:u,async:true, context:context, cache:false, dataType:"json",
				success:function(result) {
					this.self.runningXhr = undefined;
					if (result.values) {
						this.self._saveItems({values:result.values,tag:this.tag,searchTerm:this.searchTerm});
						if(this.searching && encodeURIComponent(this.searchTerm)!=encodeURIComponent(this.self.search_field.val())){
							this.self.search_field.trigger('change');
							return;
						}
						else
							this.self._showItems(this.tag);
					} else if (result.error && this.searching) {
						this.self._saveSearchEmpty(result.error, true, this.tag, this.searchTerm);
					} else if (result.error) {
						this.self._ajaxFailed(result.error, true, this.tag);
					} else {
						this.self._ajaxFailed("bad response from server", true, this.tag);
					}
				},
				error: function(req,textStatus) {
					//log("error:"+req.status+":"+textStatus);
					this.self._ajaxFailed("http error:"+textStatus, true, this.tag);
				}
			});
			this.runningXhr.searchTerm = querySearch;
		}
		,_ajaxFailed: function(str,empty, tag){
			var o = this.options;
			var self = this;
			this.runningXhr = undefined;
			if ($.isFunction(o.ajaxFailed)){
				self._trigger('ajaxFailed', null, str);
			}
			
			$.ui.datapicker.prototype._failed.apply(this, arguments);
		}
		,destroy: function(){
			var self = this;
			$.ui.datapicker.prototype.destroy.apply(this, arguments);
			self.element.unbind('.ajaxpicker').removeData('ajaxpicker');
			return self;
		}
	}));
	
	//fontpicker widget, extends ajaxpicker
	$.widget( "ui.fontpicker", $.extend({},$.ui.ajaxpicker.prototype, {
		options:{
			/*trying center of the screen(default of the datapicker)
			position:function(e,ui){
				var offsetElement = ui.controlElement.closest('div.formEntry');
				var offset = offsetElement.offset();
				var oWidth = offsetElement.outerWidth();
				var oHeight = offsetElement.outerHeight();
				
				var top = offset.top + oHeight + "px";
				var left = offset.left + "px";
				//bellow div.formEntry
				ui.main.css({
					top	:top
					,left	:left
				});
			}
			,*/ajaxCategory: "fonts" //used by ajaxpicker for ajax query parameter
			,fontFailed: function(str){} //nothing special do to, just pass the error to datapicker
			,origValue:"font"
			,autoclose:true
			,cacheAjaxResults:true
			,ui:{
				header:"Select Font"
				,topPanel:{
					show:true
				}
				,rightPanel:{
					containerClass:"fonts_div"
					,pagination:{
						itemsPerPage:10
						,pageLinks:5// so will show  something like: << < 7 8 9 10 11 > >>
					}
				}
			}
			,showPreviousTag:false
			,initialTag:"cool"
			//,loadingMessageTmpl:"<div class=\"dp_loading_message\">Loading {Tag} Fonts</div>"
			//,template:"<ul>{{each(i, font) fonts}}<li>${font}</li>{{/each}}</ul>" //do this way later
		}
		,_create: function(){
			var opts = this.options;
			//ensure we have default datapicker options(and override them)
			//note: we do recursive merge here
			this.options = $.extend(true,{},$.ui.ajaxpicker.prototype.options, opts);
			//this.element.data('ui.ajaxpicker', this.element.data('ui.fontpicker'));
			$.ui.ajaxpicker.prototype._create.apply(this, arguments);
		}
		,_buildItem:function(item, tag, container){
			var fontDiv= $("<div dp_value=\""+item+"\" title=\""+item+"\"></div>").appendTo(container);
			var escapedVal = this._escapedValue(item);
			var img = $("<img class=\"ft-font-image\" width=\"330\" height=\"75\" >").appendTo(fontDiv);
			img.error({self:this,div:fontDiv,value:item,escapedVal:escapedVal, tag:tag},function(e){
				e.data.div.remove();
				e.data.self._ajaxFailed("failed to load font:"+e.data.escapedVal+".png(original value:"+e.data.value+")",false, e.data.tag);
			});
			img.bind('load.datapicker', {div:fontDiv}, function(e){
				$(this).unbind('load.datapicker');
				e.data.div.trigger('item_ready');
			});
			return fontDiv;
		}
		,_loadItem:function(div){
			var val = div.attr('dp_value');
			var escapedVal = this._escapedValue(val);
			$('img',div).attr('src',"http://cdn1.ftimg.com/fonts/preview/330x75/"+escapedVal+".png");
		}
		,_ajaxFailed: function(str,empty,tag){
			var o = this.options;
			var self = this;
			if ($.isFunction(o.fontFailed)){
				self._trigger('fontFailed', null, str);
			}
			
			$.ui.datapicker.prototype._failed.apply(this, arguments);
		}		
		,destroy: function(){
			var self = this;
			$.ui.ajaxpicker.prototype.destroy.apply(this, arguments);
			self.element.unbind('.fontpicker').removeData('fontpicker');
			return self;
		}
	}));
	
	
	
	//patternpicker widget, extends ajaxpicker
	$.widget( "ui.patternpicker", $.extend({},$.ui.ajaxpicker.prototype, {
		options:{
			tags:{
				alphabetical:{enabled:false} //no alpha for patterns
			}
			/*trying center of the screen(default of the datapicker)
			,position:function(e,ui){
				var offsetElement = ui.controlElement.closest('div.formEntry');
				var offset = offsetElement.offset();
				var oWidth = offsetElement.outerWidth();
				var oHeight = offsetElement.outerHeight();
				
				var top = offset.top + oHeight + "px";
				var left = offset.left + "px";
				//bellow div.formEntry
				ui.main.css({
					top	:top
					,left	:left
				});
			}*/
			,ajaxCategory: "patterns" //used by ajaxpicker for ajax query parameter
			,patternFailed: function(str){} //nothing special do to, just pass the error to datapicker
			,origValue:"pattern"
			,autoclose:true
			,cacheAjaxResults:true
			,ui:{
				header:"Select Pattern"
				,rightPanel:{
					containerClass:"patterns_div"
					,pagination:{
						itemsPerPage:15
						,pageLinks:5// so will show  something like: << < 7 8 9 10 11 > >>
					}
				}
			}
			,showPreviousTag:false
			,initialTag:"standard"
		}
		,_create: function(){
			var opts = this.options;
			//ensure we have default datapicker options(and override them)
			//note: we do recursive merge here
			this.options = $.extend(true,{},$.ui.ajaxpicker.prototype.options, opts);
			//this.element.data('ui.ajaxpicker', this.element.data('ui.patternpicker'));
			$.ui.ajaxpicker.prototype._create.apply(this, arguments);
		}
		,_buildItem:function(item, tag, container){
			var patternDiv= $("<div dp_value=\""+item+"\" title=\""+item+"\"></div>").appendTo(container);
			var escapedVal = this._escapedValue(item);
			var img = $("<img class=\"ft-font-image\" width=\"100\" height=\"40\" >").appendTo(patternDiv);
			img.error({self:this,div:patternDiv,value:item,escapedVal:escapedVal, tag:tag},function(e){
				e.data.div.remove();
				e.data.self._ajaxFailed("failed to load pattern:"+e.data.escapedVal+".png(original value:"+e.data.value+")",false, e.data.tag);
			});
			img.bind('load.datapicker', {div:patternDiv}, function(e){
				$(this).unbind('load.datapicker');
				e.data.div.trigger('item_ready');
			});
			return patternDiv;
		}
		,_loadItem:function(div){
			var val = div.attr('dp_value');
			var escapedVal = this._escapedValue(val);
			$('img',div).attr('src',"http://cdn1.ftimg.com/images/patterns/100x40/"+escapedVal+".png");
		}
		,_escapedValue:function(val){
			if(typeof(val)!='string' || val.length==0)
				return "";
			var r='';
			for(i=0;i<val.length;i++){
				c=val.charAt(i);
				if(c==' ')r+='_';
				else if(c=='(')r+='_';
				else if(c==')')r+='_';
				else if(c=='$')r+='_';
				else if(c=='#')r+='_';
				else if(c=='?')r+='_';
				else if(c=='%%')r+='_';
				else if(c=='&')r+='_';
				else if(c=='\'')r+='_';
				else if(c=='+')r+='_';
				else r+=c;
			}
			return r;
		}
		,_ajaxFailed: function(str,empty, tag){
			var o = this.options;
			var self = this;
			if ($.isFunction(o.patternFailed)){
				self._trigger('patternFailed', null, str);
			}
			
			$.ui.datapicker.prototype._failed.apply(this, arguments);
		}
		,destroy: function(){
			var self = this;
			$.ui.ajaxpicker.prototype.destroy.apply(this, arguments);
			self.element.unbind('.patternpicker').removeData('patternpicker');
			return self;
		}
	}));
	
	
	//gradientnpicker widget, extends ajaxpicker
	$.widget( "ui.gradientpicker", $.extend({},$.ui.ajaxpicker.prototype, {
		options:{
			tags:{
				alphabetical:{enabled:false} //no alpha for patterns
			}
			/*trying center of the screen(default of the datapicker)
			,position:function(e,ui){
				var offsetElement = ui.controlElement.closest('div.formEntry');
				var offset = offsetElement.offset();
				var oWidth = offsetElement.outerWidth();
				var oHeight = offsetElement.outerHeight();
				
				var top = offset.top + oHeight + "px";
				var left = offset.left + "px";
				//bellow div.formEntry
				ui.main.css({
					top	:top
					,left	:left
				});
			}*/
			,ajaxCategory: "gradients" //used by ajaxpicker for ajax query parameter
			,gradientFailed: function(str){} //nothing special do to, just pass the error to datapicker
			,origValue:"gradient"
			,autoclose:true
			,cacheAjaxResults:true
			,ui:{
				header:"Select Gradient"
				,rightPanel:{
					containerClass:"gradients_div"
					,pagination:{
						itemsPerPage:24
						,pageLinks:5// so will show  something like: << < 7 8 9 10 11 > >>
					}
				}
			}
			,showPreviousTag:false
			,initialTag:"standard"
		}
		,_create: function(){
			var opts = this.options;
			//ensure we have default datapicker options(and override them)
			//note: we do recursive merge here
			this.options = $.extend(true,{},$.ui.ajaxpicker.prototype.options, opts);
			//this.element.data('ui.ajaxpicker', this.element.data('ui.gradientpicker'));
			$.ui.ajaxpicker.prototype._create.apply(this, arguments);
		}
		,_buildItem:function(item, tag, container){
			var patternDiv= $("<div dp_value=\""+item+"\" title=\""+item+"\"></div>").appendTo(container);
			var escapedVal = this._escapedValue(item);
			var img = $("<img class=\"ft-font-image\" width=\"100\" height=\"20\" >").appendTo(patternDiv);
			img.error({self:this,div:patternDiv,value:item,escapedVal:escapedVal, tag:tag},function(e){
				e.data.div.remove();
				e.data.self._ajaxFailed("failed to load gradient:"+e.data.escapedVal+".png(original value:"+e.data.value+")",false, e.data.tag);
			});
			img.bind('load.datapicker', {div:patternDiv}, function(e){
				$(this).unbind('load.datapicker');
				e.data.div.trigger('item_ready');
			});
			return patternDiv;
		}
		,_loadItem:function(div){
			var val = div.attr('dp_value');
			var escapedVal = this._escapedValue(val);
			$('img',div).attr('src',"http://cdn1.ftimg.com/images/gradients/100x20/"+escapedVal+".png");
		}
		,_escapedValue:function(val){
			if(typeof(val)!='string' || val.length==0)
				return "";
			var r='';
			for(i=0;i<val.length;i++){
				c=val.charAt(i);
				if(c==' ')r+='_';
				else r+=c;
			}
			return r;
		}
		,_ajaxFailed: function(str,empty,tag){
			var o = this.options;
			var self = this;
			if ($.isFunction(o.gradientFailed)){
				self._trigger('gradientFailed', null, str);
			}
			
			$.ui.datapicker.prototype._failed.apply(this, arguments);
		}
		,destroy: function(){
			var self = this;
			$.ui.ajaxpicker.prototype.destroy.apply(this, arguments);
			self.element.unbind('.gradientpicker').removeData('gradientpicker');
			return self;
		}
	}));
	
	//logopicker widget, extends ajaxpicker
	$.widget( "ui.logopicker", $.extend({},$.ui.ajaxpicker.prototype, {
		options:{
			tags:{
				alphabetical:{enabled:false} //no alpha for patterns
			}
			/*trying center of the screen(default of the datapicker)
			,position:function(e,ui){
				var offsetElement = ui.controlElement.closest('.box_inner');
				var offset = offsetElement.offset();
				var oWidth = offsetElement.outerWidth();
				var oHeight = offsetElement.outerHeight();
				
				var top = offset.top + oHeight + "px";
				var left = offset.left + "px";
				//bellow div.formEntry
				ui.main.css({
					top	:top
					,left	:left
				});
			}*/
			,ajaxCategory: "logos" //used by ajaxpicker for ajax query parameter
			,logoFailed: function(str){} //nothing special do to, just pass the error to datapicker
			,origValue:"logo"
			,autoclose:true
			,cacheAjaxResults:true
			,ui:{
				header:"Select Logo"
				,topPanel:{
					show:true
					,showAlphabet:false
				}
				,rightPanel:{
					containerClass:"logos_div"
					,pagination:{
						itemsPerPage:10
						,pageLinks:5// so will show  something like: << < 7 8 9 10 11 > >>
					}
				}
			}
			,showPreviousTag:false
			,initialTag:"Featured"
			,fontname:"agate"
			,text:"agate"
		}
		,_create: function(){
			var opts = this.options;
			//ensure we have default datapicker options(and override them)
			//note: we do recursive merge here
			this.options = $.extend(true,{},$.ui.ajaxpicker.prototype.options, opts);
			$.ui.ajaxpicker.prototype._create.apply(this, arguments);
		}
		,_buildItem:function(item, tag, container){
			var logo = logoEntries[item];
			var logoDiv = $("<div dp_value=\""+item+"\" title=\""+item+"\"></div>").appendTo(container);
			//logoDiv.addClass((i%2==0)?"logoPickerEvenPreview":"logoPickerOddPreview");
			if(logo)
				var logoDivText = $("<p class=\"logo_div_text\">"+(logo.title?logo.title:"&nbsp;")+"</p>").appendTo(logoDiv);
			var escapedVal = this._escapedValue(item);
			var loading_img = $("<img class=\"ft-loading-image\" src=\"http://cdn1.ftimg.com/images/loading.gif\">").appendTo(logoDiv);
			
			var img = $("<img class=\"ft-logo-image\"/>").css({width:'',height:''}).appendTo(logoDiv);
			img.bind('load.dp',{self:this,div:logoDiv,logo:logo,dp_value:item,tag:tag},function(e){
				$(this).attr('logo_loaded','true');
				
				var div = e.data.div;
				div.children().remove('.logo_div_text, .ft-loading-image');
				
				var logo = e.data.logo;
				if(logo && logo.bgClass)
					div.addClass(logo.bgClass);
					
				if(logo && logo.title)
					div.attr('title',logo.title);
				
				var h = $(this).outerHeight();
				var w = $(this).outerWidth();
				
				var divh = 75;//div.height();
				var divw = 340;//div.width();
				
				var scale = 1, scaleW = 1, scaleH = 1;
				if (w>divw)
					scaleW = divw/w;
				if (h>divh)
					scaleH = divh/h;
				scale = Math.min(1,scaleW,scaleH);
				
				if(scale<1){
					w= w*scale; h=h*scale;
					$(this).width(w);
					$(this).height(h);
				}
				
				var top = Math.round((divh - h)/2) + "px";
				var left = Math.round((divw - w)/2) + "px";
				$(this).css({
					top	:top
					,left	:left
				});
				//unbind as we need to do this once only.
				$(this).unbind('load.dp');
				
				div.trigger('item_ready');
				
			});
			img.error({self:this,div:logoDiv,value:item,escapedVal:escapedVal, tag:tag},function(e){
				e.data.div.remove();
				e.data.self._ajaxFailed("failed to load logo:"+e.data.escapedVal,false,e.data.tag);
			});
			return logoDiv;
		}
		,_loadItem:function(div){
			var val = div.attr('dp_value');
			if(!val)//empty tag - ie no results from search
				return;
			var escapedVal = this._escapedValue(val);
			var img = $('img',div);
			var logo = logoEntries[val];
			var o = this.options;
			
			var context = {self:this, img:img,div:div,logo:logo, tag:this.selectedTag};
			var u=o.ajaxHost+"/net-fu/image_output.cgi?script="+encodeURIComponent(escapedVal)+"&text="+encodeURIComponent(o.text)+"&fontname="+encodeURIComponent(o.fontname)+"&imageoutput=true";
			$.ajax({url:u,async:true, context:context, cache:false, dataType:"json",
				success:function(result) {
					if (result.src) {
						this.img.attr({'src':result.src});//,title:this.logo.title});
					} else if (result.error) {
						this.div.remove();
						this.self._ajaxFailed("failed to load image:"+result.error,false,this.tag);
					} else {
						this.div.remove();
						this.self._ajaxFailed("bad response from server",false,this.tag);
					}
				},
				error: function(req,textStatus) {
					this.div.remove();
					this.self._ajaxFailed("http error:"+textStatus,false, this.tag);
				}
			});
			
		}
		,_escapedValue:function(val){
			if(typeof(val)!='string' || val.length==0)
				return "";
			var r='';
			for(i=0;i<val.length;i++){
				c=val.charAt(i);
				if(c==' ')r+='_';
				else r+=c;
			}
			return r;
		}
		,_ajaxFailed: function(str,empty, tag){
			var o = this.options;
			var self = this;
			if ($.isFunction(o.logoFailed)){
				self._trigger('logoFailed', null, str);
			}
			
			$.ui.datapicker.prototype._failed.apply(this, arguments);
		}
		,destroy: function(){
			var self = this;
			$.ui.ajaxpicker.prototype.destroy.apply(this, arguments);
			self.element.unbind('.logopicker').removeData('logopicker');
			return self;
		}
	}));
	
	
	/*
	//helper
	$.extend({
		//use ft_ to reduce chances of conflicting with native jquery method with same name
		ft_renderTemplate:function(container, template, data ) {
			$(container).empty();
			$.tmpl(template, data).appendTo(container);
		}
	
	});*/
	
})(jQuery);

