
// ------------ Effect function to jQuery Plugin .scrollTo() - (jquery.scrollTo.js) -------------

jQuery(function( $ ){
	/**
	 * Easing Effect
	 */
	$.easing.elasout = function(x, t, b, c, d) {
		var s=1.70158;var p=0;var a=c;
		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
		if (a < Math.abs(c)) { a=c; var s=p/4; }
		else var s = p/(2*Math.PI) * Math.asin (c/a);
		return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
	};
});


/* ============================================================================================
 * ----------------------------- RESIZE AND SCROLL MANAGER ------------------------------------
 * ============================================================================================*/


function Resizer (){
	if (typeof arguments.callee.instance=='undefined'){
		function resizerObj(){
//===================== declaration of singleton class =====================
			this.init = function () {
				// initialization of a new properties
				this.actionsGroup = 'default';
				this.windowSize = {'height':$(window).height(), 'width':$(window).width()};
				this.scrollPos = {'left': $(window).scrollLeft(), 'top': $(window).scrollTop()};
				this.docHeight = $(document).height();
				// site width, need to calculate a left site offset
				this.siteWidth = 1135; // very important!!!
				this.siteLeftOffset = 0; // auto-calculated value
				// preloader and other
				this.playPreloader = false;
				this.preloaderImg = 1;
				this.preloaderId = [];
				this.structure = [];
				this.debug = 0;
				if (window.console == undefined){
					this.debug = 0;
				}
				//
				this.callbacks = [];
				//
				this.siteLeftOffset = (this.windowSize.width - this.siteWidth) / 2;
				if (this.siteLeftOffset < 0) this.siteLeftOffset = 0;
			}

			// add block to auto-manage
			this.addBlock = function (block) {
				if (block.name != undefined){
					this.structure.push (block);
				}
			}

			// need to call after block's added, to update dom elements
			this.firstRun = function (){
				if (this.debug){
					window.console.log ('==== resizer: firstRun ====');
				}
				for (var k in this.structure){
					if (this.structure[k].name != undefined){
						if (this.structure[k].onLoadCSS != undefined){
							for (var k2 in this.structure[k].onLoadCSS){
								$(this.structure[k].name).css(k2, this.structure[k].onLoadCSS[k2]);
							}
						}
					}
				}
				this.onScroll(true);
				// callback
				this.runCallbacks('firstRun');
			}

			// on resize handler
			this.onResize = function (){
				// window size
				this.windowSize = {'height':$(window).height(), 'width':$(window).width()};
				if (this.debug){
					window.console.log ('==== resizer: onResize ====');
					window.console.log ('width:'+this.windowSize.width+', height:'+this.windowSize.height);
				}
				// left site offset
				this.siteLeftOffset = (this.windowSize.width - this.siteWidth) / 2;
				if (this.siteLeftOffset < 0) this.siteLeftOffset = 0;
				// need a re-draw, call a onScroll
				this.onScroll(true);
				// callback
				this.runCallbacks('onResize');
			}

			// on scroll handler
			this.onScroll = function (forceRecalc){
				forceRecalc = false || forceRecalc;
				var newPos = {'left': $(window).scrollLeft(), 'top': $(window).scrollTop()};
				if (newPos.left==this.scrollPos.left && newPos.top==this.scrollPos.top && !forceRecalc){
					// window scroll not changed (possibly scrolling div or jScrollPane) - no actions needed;
					return;
				}
				else{
					// scroll position changed!
					this.scrollPos = newPos;
				}
				if (this.debug){
					window.console.log ('==== resizer: onScroll ====');
					window.console.log ('left:'+this.scrollPos.left+', top:'+this.scrollPos.top);
				}
				// callback before compute a onScroll
				this.runCallbacks('onBeforeCompute');
				//
				for (var k in this.structure){
					var block = this.structure[k];
					if (block.onScroll != undefined){
						if (block.onScroll == 'setLeft'){
							$(block.name).css('left', '-'+this.scrollPos.left + 'px');
						}
						else if (block.onScroll == 'setLeftFromSiteArea'){
							var leftOffset = 0;
							if (block.leftOffset != undefined) leftOffset = block.leftOffset;
							var left = (this.siteLeftOffset + leftOffset)-this.scrollPos.left;
							if (this.debug==2){
								window.console.log ('setLeftFromSiteArea:'+block.name+', left:'+left+', this.siteLeftOffset: '+this.siteLeftOffset);
							}
							$(block.name).css('left',left+'px');
						}
						else if (block.onScroll == 'setLeftFromElement' && block.fromElement!=undefined){
							var left = $(block.fromElement).offset().left-this.scrollPos.left;
							if (this.debug==2){
								window.console.log ('setLeftFromElement:'+block.name+', left:'+left+', setLeftFromElement: '+block.fromElement);
							}
							$(block.name).css('left',(left)+'px');
						}
					}
				}
				// callback
				this.runCallbacks('onScroll');
			}
			// --------- Resizer Plugin System ----------
			this.addCallback = function (func, event, selector){
				selector = selector || null;
				if (typeof(func)=='function' && typeof(event)=='string'){
					this.callbacks.push({'func':func, 'event':event, 'selector':selector});
				}
			}

			this.runCallbacks = function (event){
				for (var k in this.callbacks){
					if (this.callbacks[k].event != event) continue;
					if (this.callbacks[k].selector != null){
						if ($(this.callbacks[k].selector).size()>0){
							this.callbacks[k].func.apply(this,arguments);
						}
					}
					else{
						this.callbacks[k].func.apply(this,arguments);
					}
				}
			}

			// -------- backward compatibility ----------
			this.changeActionsGroup = function (name){}
			this.getActionsGroup = function (name){}

			// ---------- preloader functions -----------

			this.startPreloader = function (obj){
				obj = obj || null;
				// center preloader
				var top = this.windowSize['height']/2;
				var left = this.windowSize['width']/2;
				if (obj!=null) {
					if ($(obj).size()>0) {
				        scrollTop = $(window).scrollTop();
				        top = ($(obj).offset().top - scrollTop + $(obj).height()/2)-30;
						left = ($(obj).offset().left + $(obj).width()/2)-30;
					}
				}
				$('#preloader').css('top', top+'px').css('left',left+'px');
				// run preloader
				this.playPreloader = true;
				$('#preloader').css('display','block');
				this.preloaderId.push(window.setInterval (this.runPreloader,150));
			}

			this.stopPreloader = function (){
				this.playPreloader = false;
				$('#preloader').css('display','none');
			}

			this.runPreloader = function (){
				var resizer = new Resizer;
				$('#preloader_img').attr('src',$('#preloader_img'+resizer.preloaderImg).attr('src'));
				resizer.preloaderImg++;
				if (resizer.preloaderImg > 8){
					resizer.preloaderImg = 1;
				}
				if (!resizer.playPreloader){
					// stopping the preloader(or many)
					if (resizer.preloaderId.length>1){
						// if many preloaders - do something
					}
					while (resizer.preloaderId.length>0){
						window.clearInterval (resizer.preloaderId.pop());
					}
				}
			}
//===================== end declaration of singleton class =====================
		}
		arguments.callee.instance = new resizerObj();
		arguments.callee.instance.init();
	}
	return arguments.callee.instance;
};




/* ============================================================================================
 * ------------------------------------- AJAX MANAGER -----------------------------------------
 * ============================================================================================*/
/**
 * Available hooks:
 * scrollLoadStart
 * scrollLoadEnd
 *
 */
function AjaxManager (){
	if (typeof arguments.callee.instance=='undefined'){
		function ajaxManagerObj(){
//--------------------- declaration of singleton class ----------------------
			this.init = function () {
				// initialization of a new properties
				this.controllerName = 'ajax'; // controller to handle ajax queries
				this.shortAction = 'short'; // action to display a short URL's
				this.filterForm = 'search_form'; // form that containts a filters
				this.changeHashAndIgnore = '';
				// array of a filter names (id's of a <input type="hidden" /> )
				this.filters = {'master_make_id':0, 'master_model_id':0, 'cb_noimages':0, 'hash_id':0, 'feed_hash':0, 'showroom_request':0, 'preserve_f_info':0};
				// Original hash on before hash was changed
				this.originalHash = '';
				this.isIgnoreNewHash = false;
				this.scroll = false;
				this.needPreloader = true;
				this.infinent = null;
                this.eventListeners = {
                    'scrollLoadEnd': [],
                    'domChanged': []
                };
                this.centerEffectFlag = null;
			}

            /**
             * Register event handlers
             * @param eventName - Name of event to bing a callback
             * @param domSelector - Name of selector. If selector exist - function is actual, and must be a called.
             * 						If selector not exist - function must de deleted.
             * @param handler - Function to call.
             * @param needUniqueBySelector - if true (default) and callback registered to exist's selector, calling this method don't
             * add a new callback, just replace existing.
             */
            this.addEventListener = function(eventName, domSelector, handler, needUniqueBySelector) {
            	needUniqueBySelector = needUniqueBySelector || true;
            	if (this.eventListeners[eventName]!=undefined){
            		if ($(domSelector).size()>0){
            			if (needUniqueBySelector){
            				var key = -1;
            				for (var k in this.eventListeners[eventName]){
            					if (this.eventListeners[eventName][k]['selector']==domSelector){
            						key = k;
            					}
            				}
            				if (key != -1){
            					this.eventListeners[eventName][key]['handler'] = handler;
            				}
            				else{
            					this.eventListeners[eventName].push({'selector': domSelector, 'handler': handler});
            				}
            			}
            			else{
            				this.eventListeners[eventName].push({'selector': domSelector, 'handler': handler});
            			}
            		}
            		else{
                		if(window.console != undefined){
                			window.console.log ('ERROR! Trying to bind callback to a non-exist Selector: '+domSelector);
                		}
            		}
            	}
            	else{
            		if(window.console != undefined){
            			window.console.log ('ERROR! Trying to bind a non-exist callback: '+eventName);
            		}
            	}
            }

            /**
             * Delete event listener by eventName & domSelector
             */
            this.deleteEventListener = function (eventName, domSelector){
            	if (this.eventListeners[eventName]!=undefined){
            		for (var k in this.eventListeners[eventName]){
            			if (this.eventListeners[eventName][k]['selector'] == domSelector){
            				delete this.eventListeners[eventName][k];
            			}
            		}
            	}
            }

            /**
             * Call all listeners by eventName.
             * Listeners calling with some arguments.
             */
            this.runEventListeners = function (eventName){
            	if (this.eventListeners[eventName]!=undefined){
            		for (var k in this.eventListeners[eventName]){
            			// passing to function actual arguments:
            			if (typeof(this.eventListeners[eventName][k]['handler']) == 'function'){
            				this.eventListeners[eventName][k]['handler'].apply(this,arguments);
            			}
            		}
            	}
            }

            /**
             * Check all Listeners
             */
            this.checkListenersActual = function (){
            	for (var k in this.eventListeners){
            		for (var k2 in this.eventListeners[k]){
            			if ($(this.eventListeners[k][k2]['selector']).size()==0){
            				delete this.eventListeners[k][k2];
            			}
            		}
            	}
            }

			/**
			 * get a filter string
			 */
			this.getFilterString = function (){
				return $('#'+this.filterForm).serialize();
			}

			/**
			 * change a filter's values
			 */
			this.changeFilter = function (name, value){
				$('#'+name).val(value);
				if (this.filters[name]!=undefined){
					this.filters[name] = value;
				}
			}

			this.ignoreNewHash = function (){
				this.isIgnoreNewHash = true;
			}

			/**
			 * init а twitter paging
			 */
	        this.twitterPagingInit = function (type){

	        	type = type || 'showroom';

                if (type == 'showroom') {
                    var urlParam = '/car/showroomAjax?page={page}';
                    var completeMessage = '<strong>No more cars found</strong>';
                    var completeCriteria = 'This short list is currently empty';
                } else if (type == 'shortlist' || type == 'list') {
                    var urlParam = '/car/searchAjax?Car_page={page}&' + this.getFilterString();
                    var completeMessage = '<strong>No more cars found</strong>';
                    var completeCriteria = 'No more cars found';
                } else if (type == 'news') {
                	var urlParam = '/news/GetNewsListAjax?page={page}&' + sCurrentNewMonth;
                    var completeMessage = '<strong>No more news found</strong>';
                    var completeCriteria = 'No more news found';
                } else if (type == 'images') {
                    var urlParam = '/car/searchAjax?Car_page={page}&viewType=images&' + this.getFilterString();
                    var completeMessage = '<strong>No more cars found</strong>';
                    var completeCriteria = 'No more cars found';
                } else if (type.slice(0,10) == 'companies_') {
                    var urlParam = '/companies/'+type.slice(10)+'.html?page={page}&' + this.getFilterString();
                    var completeMessage = '<strong>No more items found</strong>';
                    var completeCriteria = 'No more items found';
                }

                if (this.infinent != null){
	                if (this.infinent.checkIsActual != undefined){
	                	if (typeof(this.infinent.checkIsActual)=='function'){
	                		if (!this.infinent.checkIsActual()){
	                			//alert('ne nado init');
	                			return;
	                		}
	                	}
	                }
                }

                //condition not to turn on twitter-like paging for the results less than 10
                var me = this;
	            if ($('div.box-result div.content-result').size() >= 10
	            	|| $('.location-box a').size() >= 10
	            	|| $('.csmagazine-companies div.content-result').size() >=10
	            	) {
		                if ( $(".box-result").length != 0 ) {
	                        $(window).unbind("scroll");
	                        this.infinent = addInfiniteScroller($(".box-result"));
	                    }
	                    else if ( $('.location-box').length != 0  ) {
	                        $(window).unbind("scroll");
	                        this.infinent = addInfiniteScroller($(".location-box"));
	                    }
	                    else if ($('.csmagazine-companies').length != 0  ){
	                        $(window).unbind("scroll");
	                        this.infinent = addInfiniteScroller($(".csmagazine-companies"));
	                    }
	            }

                function addInfiniteScroller(element) {
                    return element.infinentScroll({
	                    'url': urlParam ,
	                    'initialUpdate': true,
	                    'page': 2,
	                    'completeMessage': completeMessage,
	                    'completeCriteria': completeCriteria,
		                'callback' : function (){
	                		(new AjaxManager).runEventListeners('scrollLoadEnd');
	                	},
	                	'onComplete': function (){
	                		$('div.find-more').show(2500);
	                	}
	                });
                }
	        }

	        /**
	         * Change a dom structure. Used by parseAjaxResponce ().
	         */
	        this.changeDom = function (data){
	        	if (data.name != undefined && data.data != undefined){
	        		if (data.name=='title'){
	        			document.title = data.data; // fix for IE
	        		}
	        		else if (data.append != undefined){
	        			$(data.name).append(data.data);
	        		}
	        		else if (data.prepend != undefined){
	        			$(data.name).prepend(data.data);
	        		}
	        		else if (data.ifNotExistSelector != undefined){
	        			if ($(data.ifNotExistSelector).size()==0){
	        				$(data.name).html(data.data);
	        			}
	        		}
	        		else if (data.ifExistSelector != undefined){
	        			if ($(data.ifExistSelector).size()>0){
	        				$(data.name).html(data.data);
	        			}
	        		}
	        		else{
	        			$(data.name).html(data.data);
	        		}
	        	}
	        }

	        /**
	         * Function to manipulate a classes, attributes, styles of DOM-elements.
	         * Used by parseAjaxResponce ().
	         */
	        this.manipulateAttrs = function (data){
	        	if (data.operation != undefined){
	        		if (data.operation == 'css' && data.element != undefined && data.name != undefined && data.to != undefined){
	        			$(data.element).css(data.name, data.to);
	        		}
	        		else if (data.operation == 'changeAttr' && data.element != undefined && data.name != undefined && data.to != undefined){
	        			$(data.element).attr(data.name, data.to);
	        		}
	        		else if (data.operation == 'deleteAttr' && data.element != undefined && data.name != undefined){
	        			$(data.element).removeAttr(data.name);
	        		}
	        		else if (data.operation == 'addClass' && data.element != undefined && data.name != undefined){
	        			$(data.element).addClass(data.name);
	        		}
	        		else if (data.operation == 'delClass' && data.element != undefined && data.name != undefined){
	        			$(data.element).removeClass(data.name);
	        		}
	        		else if (data.operation == 'delElement' && data.element != undefined){
	        			$(data.element).remove();
	        		}
	        		else if (data.operation == 'emptyElementIfNotExistSelector' && data.element != undefined && data.selector != undefined){
	        			if ($(data.selector).size()==0){
	        				$(data.element).html('');
	        			}
	        		}
	        	}
	        }

			/**
			 * Parse a ajax responce
			 */
			this.parseAjaxResponce = function (data){
				// -- check the input data --
				if (data == null) return;
				if (data.result == undefined){
					// unknown data
					return;
				}
				if (data.result != true) {
					// some error occured
					return;
				}
				// if GET redirect needed
				if (data.redirect != undefined){
					location.href = data.redirect;
				}
				// pre-process dom before DOM elements update
				if (data.changeBeforeUpdate != undefined){
					for (var k in data.changeBeforeUpdate){
						this.manipulateAttrs(data.changeBeforeUpdate[k]);
					}
				}
				// -- process data --
				for (var k in data){
					if (data[k].name != undefined && data[k].data != undefined){
						if (data[k].ifNotExistSelector != undefined){
							if ($(data[k].ifNotExistSelector).size() > 0 ){
								continue;
							}
						}
						if (data[k].ifExistSelector != undefined){
							if ($(data[k].ifExistSelector).size() == 0 ){
								continue;
							}
						}
						// prepare the effect if need
						if (this.centerEffectFlag != null && data[k].centerEffectFlag != undefined){
							this.changeDom(data[k]);
						}
						else{ // if not need effect - replace content
							this.changeDom(data[k]);
						}
						// set the new flag
						if (data[k].centerEffectFlag != undefined){
							this.centerEffectFlag = data[k].centerEffectFlag;
						}
					}
				}
				// post-process dom after DOM elements update
				if (data.changeAfterUpdate != undefined){
					for (var k in data.changeAfterUpdate){
						this.manipulateAttrs(data.changeAfterUpdate[k]);
					}
				}
				// new effect
				if (this.centerEffectFlag != null){
					if ($(this.centerEffectFlag).size() == 0){
						this.centerEffectFlag = null;
					}
				}
				//
				// stop preloader
				(new Resizer).stopPreloader ();
				// change filters if needed
				if (data.filter != undefined){
					for (var k in data.filter){
						this.changeFilter(k, data.filter[k]);
					}
				}
				// init twitter paging if needed
				if (data.twitterPaging != undefined){
					this.twitterPagingInit(data.twitterPaging);
				}
				// if page need to change a hash of the page, and NOT send a request after it's changed
				if (data.changeHashAndIgnore != undefined || data.changeHash != undefined){
					if (data.changeHashAndIgnore != undefined){
						this.changeHashAndIgnore = data.changeHashAndIgnore;
						window.location.hash = data.changeHashAndIgnore;
					}
					else{
						window.location.hash = data.changeHash;
						if (data.importantReload != undefined){
							setTimeout(function(){
								(new AjaxManager).ajaxHandler(data.changeHash);
							},100);
						}
					}
				}
				// -- check the actions group --
				var resizer = new Resizer;
				if (data.actionsGroup != undefined){
					// return if responce not need to change actions group
					if (data.actionsGroup != 'notChange'){
						// changing actions group
						if (data.actionsGroup != resizer.getActionsGroup()){
							resizer.changeActionsGroup(data.actionsGroup);
						}
					}
				}
				else{
					// if not passed - 'default' group used
					var group = 'default';
					if (group != resizer.getActionsGroup()){
						resizer.changeActionsGroup(group);
					}
				}
				// if page need scroll to top or to specified selector
				if (data.scroll != undefined){
					if(data.scroll == 'top'){
						$(window).scrollTo({top:0, left:0});
					}
					else{
						if (data.scroll['container']!=undefined && data.scroll['target']!=undefined){
							var cont = data.scroll['container'];
							var targ = data.scroll['target'];
							setTimeout (function(){$(cont).scrollTo(targ);},300);
						}
						else{
							$(window).scrollTo(data.scroll);
						}
					}
				}

				// New design spec calling
	            makeCustomScroll ('#custom_scroll_container, #custom_scroll_wiki');// make a custom scroll
				if (data.notAnimation == undefined){
		            showAndHide (true);// show float panel
				}

	            // call a resizer after content renew
				setTimeout (function(){
					var res = new Resizer;
					res.onResize();
					res.onScroll();
				},200);

				// After loading responce -- look if we need to scroll to somewhere
				if (this.scroll) {
					this.scrollToAnchor(this.originalHash);
				}

				if (data.scriptExec != undefined){
					if (typeof(data.scriptExec)=='string'){
						$.globalEval(data.scriptExec);
					}
					else{
						for (var k in data.scriptExec){
							$.globalEval(data.scriptExec[k]);
						}
					}
				}

				// call a Click Tale
				if ((typeof ClickTaleExec=='function') && (typeof ClickTaleRebindEvents=='function')){
					ClickTaleExec(window.location);
					ClickTaleRebindEvents();
				}

				// check actual listeners
				this.checkListenersActual ();
				// make a callback
				this.runEventListeners('domChanged',data);
			}

			/**
			 * Get hash part of a ajax link
			 */
			this.getHash = function (url){
				// get the part after #!
				var pos = url.indexOf('#!');
				if (pos == -1) return null;
				return url.substr(pos);
			}

			/** Decode the string like "http://classicsearch.test/#!ajax/make/alfa%20romeo/id-7/"
			 *  IN: /ajax/make/?id=7
			 */
			this.decodeAjaxLink = function (url){
				var ajaxUrl = this.getHash(url);
				// if not correct link
				if (ajaxUrl == null) return null;
				// if we must change a hash and don't need a action
				if (ajaxUrl==this.changeHashAndIgnore){
					this.changeHashAndIgnore = '';
					return null;
				}
				this.changeHashAndIgnore = '';
				// Check if it is scrolling hash
				if (ajaxUrl.indexOf('#', 1) >0) {
					this.scroll = true;
				}
				ajaxUrl = ajaxUrl.substr(2);
				var urlArr = ajaxUrl.split('/');
				// if link a shortcut to a make/model/share/subscribe
				if (urlArr[0]!= undefined)
					if(urlArr[0]!=this.controllerName){
						if (urlArr[1]!=undefined){
							// if NOT a module and then controller specified
							if (urlArr[1]!=this.controllerName){
								// construct a link like: /ajax/short/?need=_what_hash_passed_
								ajaxUrl = '/' + this.controllerName + '/' + this.shortAction + '/?need=' + ajaxUrl;
								return ajaxUrl;
							}
						}
						else{
							// construct a link like: /ajax/short/?need=_what_hash_passed_
							ajaxUrl = '/' + this.controllerName + '/' + this.shortAction + '/?need=' + ajaxUrl;
							return ajaxUrl;
						}
					}
				if (urlArr.length > 1){
					// make the standart url
					ajaxUrl = '';
					// if controller in module
					if (urlArr[0]!=this.controllerName && urlArr[1]==this.controllerName && urlArr[2]!= undefined){
						ajaxUrl = '/'+urlArr[0]+'/'+this.controllerName+'/'+urlArr[2]+'/?';
					}
					else{
						ajaxUrl = '/'+this.controllerName+'/'+urlArr[1]+'/?';
					}
					var pos = -1;
					for (var k in urlArr){
						pos = urlArr[k].indexOf('-');
						if (pos >= 0){
							//var val = urlArr[k].split('-',2);
							var val = {0:urlArr[k].substr(0,pos), 1:urlArr[k].substr(pos+1)};
							if (val[0]=='noNeedPreloader'){
								this.needPreloader = false;
							}
							ajaxUrl = ajaxUrl + '&' +  val[0] + '=' + val[1];
						}
					}
					return ajaxUrl;
				}
				return null;
			}

			/** Get the link and call a JSON ajax juery
			 *
			 */
			this.ajaxHandler = function (url, data, type) {
				// formal parameters
				type = type || 'get';
				data = data || {};

				if (window.console != undefined){
					window.console.log(url);
				}

				this.needPreloader = true;

				// if need ignore new hash:
				if (this.isIgnoreNewHash){
					this.isIgnoreNewHash = false;
					return;
				}

				// compare old hash with new one.
				if (url.indexOf('/noCompareOldhash-')==-1){
					if (this.compareHashes(this.originalHash, url)) {
						if (this.originalHash != url) {
							// Base part of hashes are equal, but last parts are different.
							this.scrollToAnchor(url);
						}
						return null;
					}
				}
				// If hashes old -- store new hash and process it
				this.originalHash = url;

				// get a correct link
				var ajaxUrl = this.decodeAjaxLink(url);

				if (ajaxUrl == null) return;
				// get or post
				ajaxUrl += '&'+$('form#search_form').serialize();

				// run a preloader if needed
				if (this.needPreloader){
					(new Resizer).startPreloader();
				}

				// make a ajax call
				if (type=='get'){
					$.get(ajaxUrl,
							function(data){
								var manager = new AjaxManager();
								manager.parseAjaxResponce(data);
							},
							'json');
				}
				else if (type=='post'){
					$.post(ajaxUrl,
							function(data){
								var manager = new AjaxManager();
								manager.parseAjaxResponce(data);
							},
							'json');
				}
			}

			this.scrollToAnchor = function(hash) {
				this.scroll = false;
				// Remove hash sign from begin of hash and get anchor with such name
				var elements = $('a[name="'+ hash.substring(1) +'"]');
				// scroll only if there are element
				if (elements && elements[0]) {
					$.scrollTo(elements[0], {offset:{top:-125}});
				}
			}

			// Compares hashes without checking 2nd-#-part
			this.compareHashes = function(h1, h2) {
				// 1. Get hashes indexes
				var hash1 = '';
				var hash2 = '';
				var h1start = h1.indexOf('#');
				var h1end = h1.indexOf('#', 1);
				if (h1end > 0) {
					hash1 = h1.substring(h1start, h1end);
				} else {
					if (h1start==-1 && h1 != h2) return false;
					hash1 = h1.substring(h1start);
				}

				var h2start = h2.indexOf('#');
				var h2end = h2.indexOf('#', 1);
				if (h2end > 0) {
					hash2 = h2.substring(h2start, h2end);
				} else {
					hash2 = h2.substring(h2start);
				}
				if (hash1==''){
					if (hash1==hash2){
						return false;
					}
				}
				return (hash1 == hash2);
			}

			this.changeHashWithoutAjax = function (hash){
				this.changeHashAndIgnore = hash;
				window.location.hash = hash;
			}

			this.changeSeoLinkUrl = function (link, reverse){
		        if (reverse == true) {
		            link = link.replace(/\-/g," ");
		        }
		        else {
		            link = link.replace(/\s/g,"-");
		        }
		        return link;
		    }

			this.submitFormPost = function (par1, url, options){
				// default values
				options = options || {beforeUpdate: function(data){}, afterUpdate: function(data){}, sendFilters: false};
				url = url || null;
				// get the correct variables
				var formObj = null;
				var urlAddr = null;
				// --- determine a correct <FORM> object ---
				if (typeof(par1)=='string'){
					// selector of a par1 passed
					if ($(par1).size() > 0){
						formObj = $(par1);
					}
				}
				else if (typeof(par1)=='object'){
					if ($(par1).parents('form').size() > 0){
						formObj = $(par1).parents('form');
					}
				}
				// if form object not found - return. if console exist - print this error to console.
				if (formObj == null){
					// if console exists - print a debug error.
					if (window.console != undefined){
						if (typeof(par1)=='object'){
							window.console.log('------ ERROR! The tag <FORM> not finded in parent of object <'+par1.name+'> ------');
						}
						else{
							if (typeof(par1)=='string'){
								window.console.log('------ ERROR! The node by selector "'+par1+'" NOT FOUNDED! ------');
							}
						}
						window.console.log('------ Call of AjaxManager.submitFormPost(...) CANCELLED! ------');
					}
					return null;
				}
				// --- determine a correct url address if not specified ---
				if (url != null){
					urlAddr = url;
				}
				else{
					if (formObj.attr('action') != undefined){
						urlAddr = formObj.attr('action');
					}
					else{
						if (window.console != undefined){
							window.console.log('------ Error! URL not passed! Call of AjaxManager.submitFormPost(...) CANCELLED! ------');
							return null;
						}
					}
				}
				// add a filters if needed to $_GET
				if (options.sendFilters != undefined)
					if (options.sendFilters == true){
						if (urlAddr.indexOf('?')==-1){
							urlAddr += '?';
						}
						urlAddr += this.getFilterString();
					}
				// --- make a job ---
				this.options = options;
				var success = function(data){
					var manager = new AjaxManager ();
					manager.parseAjaxResponce(data);
				};
				(new Resizer).startPreloader();
				$.post(urlAddr, formObj.serialize(), success, 'json');
			}
			this.scrollContent = function (elemName){
				var api = element.data('jsp');
				if ($(elemName).size() > 0 ){
					api.scrollTo($(elemName).position().left, $(elemName).position().top);
				}
			}

//--------------------- end declaration of singleton class ------------------
		}
		arguments.callee.instance = new ajaxManagerObj();
		arguments.callee.instance.init();
	}
	return arguments.callee.instance;
};

function integerDivision(x, y){
    var d=x/y;
    return (d - x%y/y);
}

/* ============================================================================================
 * ------------------------------------- ERROR MANAGER ----------------------------------------
 * ============================================================================================*/

(function ErrorManager (){
	if (typeof arguments.callee.instance=='undefined'){
		function ajaxManagerObj(){
//--------------------- declaration of singleton class ----------------------
			/**
			 * init properties when object creates
			 */
			this.init = function () {
				// properties init
				this.logUrl = '/ajax/errorLog';
				this.debug = 1;
				// connecting to events
				/*window.onerror = function(error, url, linenumber){
					return (new ErrorManager).onError(error, url, linenumber);
				};*/

				$(document).ajaxError(function(event, jqXHR, ajaxSettings, thrownError){
					return (new ErrorManager).onAjaxError(event, jqXHR, ajaxSettings, thrownError);
				});
			}
			/**
			 * Send's data to server
			 */
			this.sendDataToServer = function (data, errorType){
				var post = {'message': data, 'type': errorType};
				$.post(this.logUrl, post);
			}
			/**
			 * this method calls when JS error occured
			 */
			this.onError = function (error, url, linenumber){
				if (!this.debug) return false;
				alert('Error Handler! - '+error+'\nURL: '+url+'\nLine Number: '+linenumber);
				var message = error+"\n";
				message += "Page Hash: "+location.hash+"\n";
				message += "Browser: "+this.getBrowserInfo()+"\n";
				message += "URL: "+url+"\n";
				message += "Line Number: "+linenumber+"\n\n\n";
				this.sendDataToServer(message, 'jsError');
				if (this.debug==2){
					alert("JavaScript Error!\n\n"+message);
				}
				return true;
			}
			/**
			 * this method calls when Ajax error occured
			 */
			this.onAjaxError = function (event, jqXHR, ajaxSettings, thrownError){
				if (!this.debug) return false;
				var message = thrownError+"\n";
				message += "Page Hash: "+location.hash+"\n";
				message += "Browser: "+this.getBrowserInfo()+"\n";
				message += "Query Type: "+ajaxSettings.type+"\n";
				message += "Query Url: "+ajaxSettings.url+"\n";
				message += "Responce code: "+jqXHR.status+"\n";
				message += "Responce Text: \n\n"+jqXHR.responseText+"\n\n\n";
				//
				this.sendDataToServer(message, 'AjaxError');
				if (this.debug==2){
					alert("Ajax Error!\n\n"+message);
				}
				return true;
			}
			/**
			 * This method detects and returns a info about browser and version
			 */
			this.getBrowserInfo = function (){
				var ret = '';
				jQuery.each(jQuery.browser, function(i, val) {
						if (val == true){
							ret += i + " ";
						}
						else{
							ret += i + " " + val;
						}
				    });
				return ret;
			}
//--------------------- end declaration of singleton class ------------------
		}
		arguments.callee.instance = new ajaxManagerObj();
		arguments.callee.instance.init();
	}
	return arguments.callee.instance;
})();

//new ErrorManager();

/* ============================================================================================
 * ------------------------------------- BLINK PLUGIN -----------------------------------------
 * ============================================================================================*/



(function($){

	$.fn.workBlink = function(settings){

    var defaults = {
    		'duration':500,
    		'addclass':'blinking',
    		'count': 0
    };

    var options = $.extend(defaults, settings);

    return this.each(function(){

        var e = $(this);

        /*setInterval(function(){
            $e.addClass(options.addclass).animate({ opacity: 100 }, options.duration).queue(function(){
	            $e.removeClass(options['class']);
	            $e.dequeue();
            });
	    	},
	    	1500);
		});*/
        var countNow = 0;
		var intervalId = setInterval(function()
				{
					if($(e).css("visibility") == "visible")
					{
						$(e).css('visibility','hidden');
					}
					else
					{
						$(e).css('visibility','visible');
						// stop blinking routines
						countNow++;
						if (countNow == defaults.count){
							clearInterval (intervalId);
						}
					}
				}, options.duration);
			});

	};
})(jQuery);


/** MD5 Algoritm **/
/**
*
*  MD5 (Message-Digest Algorithm)
*  http://www.webtoolkit.info/
*
**/

var MD5 = function (string) {

	function RotateLeft(lValue, iShiftBits) {
		return (lValue<<iShiftBits) | (lValue>>>(32-iShiftBits));
	}

	function AddUnsigned(lX,lY) {
		var lX4,lY4,lX8,lY8,lResult;
		lX8 = (lX & 0x80000000);
		lY8 = (lY & 0x80000000);
		lX4 = (lX & 0x40000000);
		lY4 = (lY & 0x40000000);
		lResult = (lX & 0x3FFFFFFF)+(lY & 0x3FFFFFFF);
		if (lX4 & lY4) {
			return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
		}
		if (lX4 | lY4) {
			if (lResult & 0x40000000) {
				return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
			} else {
				return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
			}
		} else {
			return (lResult ^ lX8 ^ lY8);
		}
 	}

 	function F(x,y,z) { return (x & y) | ((~x) & z); }
 	function G(x,y,z) { return (x & z) | (y & (~z)); }
 	function H(x,y,z) { return (x ^ y ^ z); }
	function I(x,y,z) { return (y ^ (x | (~z))); }

	function FF(a,b,c,d,x,s,ac) {
		a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac));
		return AddUnsigned(RotateLeft(a, s), b);
	};

	function GG(a,b,c,d,x,s,ac) {
		a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac));
		return AddUnsigned(RotateLeft(a, s), b);
	};

	function HH(a,b,c,d,x,s,ac) {
		a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac));
		return AddUnsigned(RotateLeft(a, s), b);
	};

	function II(a,b,c,d,x,s,ac) {
		a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac));
		return AddUnsigned(RotateLeft(a, s), b);
	};

	function ConvertToWordArray(string) {
		var lWordCount;
		var lMessageLength = string.length;
		var lNumberOfWords_temp1=lMessageLength + 8;
		var lNumberOfWords_temp2=(lNumberOfWords_temp1-(lNumberOfWords_temp1 % 64))/64;
		var lNumberOfWords = (lNumberOfWords_temp2+1)*16;
		var lWordArray=Array(lNumberOfWords-1);
		var lBytePosition = 0;
		var lByteCount = 0;
		while ( lByteCount < lMessageLength ) {
			lWordCount = (lByteCount-(lByteCount % 4))/4;
			lBytePosition = (lByteCount % 4)*8;
			lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount)<<lBytePosition));
			lByteCount++;
		}
		lWordCount = (lByteCount-(lByteCount % 4))/4;
		lBytePosition = (lByteCount % 4)*8;
		lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80<<lBytePosition);
		lWordArray[lNumberOfWords-2] = lMessageLength<<3;
		lWordArray[lNumberOfWords-1] = lMessageLength>>>29;
		return lWordArray;
	};

	function WordToHex(lValue) {
		var WordToHexValue="",WordToHexValue_temp="",lByte,lCount;
		for (lCount = 0;lCount<=3;lCount++) {
			lByte = (lValue>>>(lCount*8)) & 255;
			WordToHexValue_temp = "0" + lByte.toString(16);
			WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length-2,2);
		}
		return WordToHexValue;
	};

	function Utf8Encode(string) {
		string = string.replace(/\r\n/g,"\n");
		var utftext = "";

		for (var n = 0; n < string.length; n++) {

			var c = string.charCodeAt(n);

			if (c < 128) {
				utftext += String.fromCharCode(c);
			}
			else if((c > 127) && (c < 2048)) {
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			else {
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}

		}

		return utftext;
	};

	var x=Array();
	var k,AA,BB,CC,DD,a,b,c,d;
	var S11=7, S12=12, S13=17, S14=22;
	var S21=5, S22=9 , S23=14, S24=20;
	var S31=4, S32=11, S33=16, S34=23;
	var S41=6, S42=10, S43=15, S44=21;

	string = Utf8Encode(string);

	x = ConvertToWordArray(string);

	a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;

	for (k=0;k<x.length;k+=16) {
		AA=a; BB=b; CC=c; DD=d;
		a=FF(a,b,c,d,x[k+0], S11,0xD76AA478);
		d=FF(d,a,b,c,x[k+1], S12,0xE8C7B756);
		c=FF(c,d,a,b,x[k+2], S13,0x242070DB);
		b=FF(b,c,d,a,x[k+3], S14,0xC1BDCEEE);
		a=FF(a,b,c,d,x[k+4], S11,0xF57C0FAF);
		d=FF(d,a,b,c,x[k+5], S12,0x4787C62A);
		c=FF(c,d,a,b,x[k+6], S13,0xA8304613);
		b=FF(b,c,d,a,x[k+7], S14,0xFD469501);
		a=FF(a,b,c,d,x[k+8], S11,0x698098D8);
		d=FF(d,a,b,c,x[k+9], S12,0x8B44F7AF);
		c=FF(c,d,a,b,x[k+10],S13,0xFFFF5BB1);
		b=FF(b,c,d,a,x[k+11],S14,0x895CD7BE);
		a=FF(a,b,c,d,x[k+12],S11,0x6B901122);
		d=FF(d,a,b,c,x[k+13],S12,0xFD987193);
		c=FF(c,d,a,b,x[k+14],S13,0xA679438E);
		b=FF(b,c,d,a,x[k+15],S14,0x49B40821);
		a=GG(a,b,c,d,x[k+1], S21,0xF61E2562);
		d=GG(d,a,b,c,x[k+6], S22,0xC040B340);
		c=GG(c,d,a,b,x[k+11],S23,0x265E5A51);
		b=GG(b,c,d,a,x[k+0], S24,0xE9B6C7AA);
		a=GG(a,b,c,d,x[k+5], S21,0xD62F105D);
		d=GG(d,a,b,c,x[k+10],S22,0x2441453);
		c=GG(c,d,a,b,x[k+15],S23,0xD8A1E681);
		b=GG(b,c,d,a,x[k+4], S24,0xE7D3FBC8);
		a=GG(a,b,c,d,x[k+9], S21,0x21E1CDE6);
		d=GG(d,a,b,c,x[k+14],S22,0xC33707D6);
		c=GG(c,d,a,b,x[k+3], S23,0xF4D50D87);
		b=GG(b,c,d,a,x[k+8], S24,0x455A14ED);
		a=GG(a,b,c,d,x[k+13],S21,0xA9E3E905);
		d=GG(d,a,b,c,x[k+2], S22,0xFCEFA3F8);
		c=GG(c,d,a,b,x[k+7], S23,0x676F02D9);
		b=GG(b,c,d,a,x[k+12],S24,0x8D2A4C8A);
		a=HH(a,b,c,d,x[k+5], S31,0xFFFA3942);
		d=HH(d,a,b,c,x[k+8], S32,0x8771F681);
		c=HH(c,d,a,b,x[k+11],S33,0x6D9D6122);
		b=HH(b,c,d,a,x[k+14],S34,0xFDE5380C);
		a=HH(a,b,c,d,x[k+1], S31,0xA4BEEA44);
		d=HH(d,a,b,c,x[k+4], S32,0x4BDECFA9);
		c=HH(c,d,a,b,x[k+7], S33,0xF6BB4B60);
		b=HH(b,c,d,a,x[k+10],S34,0xBEBFBC70);
		a=HH(a,b,c,d,x[k+13],S31,0x289B7EC6);
		d=HH(d,a,b,c,x[k+0], S32,0xEAA127FA);
		c=HH(c,d,a,b,x[k+3], S33,0xD4EF3085);
		b=HH(b,c,d,a,x[k+6], S34,0x4881D05);
		a=HH(a,b,c,d,x[k+9], S31,0xD9D4D039);
		d=HH(d,a,b,c,x[k+12],S32,0xE6DB99E5);
		c=HH(c,d,a,b,x[k+15],S33,0x1FA27CF8);
		b=HH(b,c,d,a,x[k+2], S34,0xC4AC5665);
		a=II(a,b,c,d,x[k+0], S41,0xF4292244);
		d=II(d,a,b,c,x[k+7], S42,0x432AFF97);
		c=II(c,d,a,b,x[k+14],S43,0xAB9423A7);
		b=II(b,c,d,a,x[k+5], S44,0xFC93A039);
		a=II(a,b,c,d,x[k+12],S41,0x655B59C3);
		d=II(d,a,b,c,x[k+3], S42,0x8F0CCC92);
		c=II(c,d,a,b,x[k+10],S43,0xFFEFF47D);
		b=II(b,c,d,a,x[k+1], S44,0x85845DD1);
		a=II(a,b,c,d,x[k+8], S41,0x6FA87E4F);
		d=II(d,a,b,c,x[k+15],S42,0xFE2CE6E0);
		c=II(c,d,a,b,x[k+6], S43,0xA3014314);
		b=II(b,c,d,a,x[k+13],S44,0x4E0811A1);
		a=II(a,b,c,d,x[k+4], S41,0xF7537E82);
		d=II(d,a,b,c,x[k+11],S42,0xBD3AF235);
		c=II(c,d,a,b,x[k+2], S43,0x2AD7D2BB);
		b=II(b,c,d,a,x[k+9], S44,0xEB86D391);
		a=AddUnsigned(a,AA);
		b=AddUnsigned(b,BB);
		c=AddUnsigned(c,CC);
		d=AddUnsigned(d,DD);
	}

	var temp = WordToHex(a)+WordToHex(b)+WordToHex(c)+WordToHex(d);

	return temp.toLowerCase();
}

// ============================ Stack Tracing Functions ===========================


function output(arr) {
	  //Optput however you want
	  alert(arr.join('\n\n'));
}

function MarkErrorDisplay(str){
	var div1 = document.createElement("div");// parent div
	var div2 = document.createElement("div");// child container
	// style parent div
	div1.style.zIndex = 1999999;
	div1.style.position = 'absolute';
	div1.style.top = 100;
	div1.style.left = 100;
	div1.style.width = 1000;
	div1.style.height = 600;
	div1.style.backgroundColor = 'red';
	div1.className = 'mark-custom-error-display';
	div1.id = 'mark_custom_error_display';
	// style child div
	div2.style.marginLeft = '5px';
	div2.style.marginTop = '5px';
	div2.style.backgroundColor = 'white';
	div2.style.width = 990;
	div2.style.height = 590;
	div2.style.overflow = 'scroll';
	div2.style.color = 'black';
	div2.style.fontSize = '14px';
	// create a hierarchy
	div2.innerHTML = str;
	//alert(str);
	div1.appendChild (div2);
	document.body.appendChild(div1);
}


function printStackTrace() {
	  var callstack = [];
	  var isCallstackPopulated = false;
	  try {
	    i.dont.exist+=0; //doesn't exist- that's the point
	  } catch(e) {
	    if (e.stack) { //Firefox
	      var lines = e.stack.split('\n');
	      for (var i=0, len=lines.length; i<len; i++) {
	        if (lines[i].match(/^\s*[A-Za-z0-9\-_\$]+\(/)) {
	          callstack.push(lines[i]);
	        }
	      }
	      //Remove call to printStackTrace()
	      callstack.shift();
	      isCallstackPopulated = true;
	    }
	    else if (window.opera && e.message) { //Opera
	      var lines = e.message.split('\n');
	      for (var i=0, len=lines.length; i<len; i++) {
	        if (lines[i].match(/^\s*[A-Za-z0-9\-_\$]+\(/)) {
	          var entry = lines[i];
	          //Append next line also since it has the file info
	          if (lines[i+1]) {
	            entry += ' at ' + lines[i+1];
	            i++;
	          }
	          callstack.push(entry);
	        }
	      }
	      //Remove call to printStackTrace()
	      callstack.shift();
	      isCallstackPopulated = true;
	    }
	  }
	  if (!isCallstackPopulated) { //IE and Safari
		  //ieStacktrace();
		  var str = '';
		  var source = '';
		  var c = arguments.callee.caller;
		  while (c){
			  // get a source
			  source = c + '';
			  // get a arguments, that is passed
			  a = '';
			  for (i = 0; i < c.arguments.length - 1; i++)
			  {
				  a += "'" + c.arguments[i] + "', ";
			  }
			  // make a string
			  str += 'Arguments: ' + a + String.fromCharCode(13);
			  str += source + String.fromCharCode(13) + '---------' + String.fromCharCode(13);
			  // get parent caller
			  if (c.arguments.callee.caller != undefined){
				  c = c.arguments.callee.caller;
			  }
			  else{
				  c = false;
			  }
		  }
		  MarkErrorDisplay('<pre>'+str+'</pre>');
	  }
	  else{
		  MarkErrorDisplay('<pre>'+callstack.join('\n\n')+'</pre>');
	  }
}

function addScriptToHead (src, charset, innerHTML, async, onload, type){
	// default values
	src = src || null;
	charset = charset || "utf-8";
	innerHTML = innerHTML || null;
	type = type || "text/javascript";
	onload = onload || function (){};
	async = async || false;
	// creating
	if (src==null) return false;
	var newNode = document.createElement("script");// new <script> tag
	newNode.innerHTML = innerHTML;
	newNode.charset = charset;
	newNode.type = type;
	newNode.src = src;
	newNode.onload=onload;
	newNode.async=async;
	// appending to <head>
	var head = document.getElementsByTagName("head")[0];
	head.appendChild (newNode);
	//
	return true;
}

function animateShowroom (selector,url,directlyAjax){
	url = url || null;
	directlyAjax = directlyAjax || false;
	var object = $(selector);
	// positioning scrollable plugin if needed
	if (url!=null){
		var sc = $('#scrollable').data("scrollable");
		if (sc){// scrollable exist
			var index = 0;
			var cnt = 0;
			$('#scrollable > #sh_items > div > a').each(function(){
				if ($(this).attr('id')==object.attr('id')){
					index = cnt;
				}
				cnt++;
			});
			sc.seekTo(Math.floor(index/4),300);
		}
	}
	object.animate({opacity: 0.01},1000, function(){
		if (url != null){
			if (directlyAjax){
				(new AjaxManager).ajaxHandler(url);
			}
			else{
				window.location.hash = url;
			}
		}
		else{
			object.animate({opacity: 1}, 1000, function(){});
		}
	});
}

function closeAllPopUps (selector){
	selector = selector || '.selectBox';
	//
	$(selector).each(function(){
		var funcClose = $(this).data('selectBox-close');
		funcClose();
	});
}


