/*  Class Chooser
/*--------------------------------------------------------------------------*/
var Chooser = Class.create();
var dTexts={};
Chooser.options = {
	zIndex: 100,
	opened: null
};

/////////////////////////////////////////////
// Опции класса:
//  multiSelect - разрешать выбор нескольких элементов
Chooser.prototype = {
	initialize: function() {
		var options = Object.extend({
			container: null,
			url: '',
			queryParams: null,
			defaultValue: 0,
			defaultText: '',
			formFieldName: '',
			zIndex: Chooser.options.zIndex--,
			onChange: Prototype.emptyFunction,
			multiSelect: 0
		}, arguments[0] || {});

		options.defaultValue = (options.defaultValue ? options.defaultValue : 0);
		options.container = $(options.container);

		this.container = options.container;
		this.items = [];
		this.selectedItem = null;
		this.selectedItems = new Array();
		this.options = options;
	},

	load: function (onSuccess) {
		if (this.options.url != null) {
			new Ajax.Request(this.options.url, {
				method: 'get',
				parameters: this.options.queryParams,
				onSuccess: function (transport) {
					if (!transport.responseText.blank()) {
						try {
							var responseJSON = transport.responseText.evalJSON();
							this.parse(responseJSON);
							this.setup();
						} catch (e) {}
					}

					if (typeof onSuccess == "function") {
						onSuccess();
					}
				}.bind(this)
			});
		}
	},

	parse: function (response) {
		this.items.push(new ChooserItem({
			id: 0,
			parent: null,
			value: 0,
			text: dTexts.all,
			order: 0
		}));

		$H(response).each(function (pair) {
			var text=pair.value.name;
			if(pair.value.bold==1) text="<b>"+text+"</b>";

			this.items.push(new ChooserItem({
				id: pair.key,
				parent: this.getItemById(pair.value.parent_id),
				value: pair.value.value,
				text: text,
				order: pair.value.order,
				is_country: pair.value.is_country
			}));
		}.bind(this));
	},

	////////////////////////////////////////////////////////////////
	setup: function () {
		if (!this.container || !this.items.size()) {
			return;
		}

		this.container.update('').setStyle({
			zIndex: this.options.zIndex
		});

		this.container.appendChild($(Builder.node('input', {
			type: 'hidden',
			value: this.options.defaultValue,
			name: this.options.formFieldName
		})));

		this.container.appendChild($(Builder.node('div', {
			className: 'select_text select_disabled'
		})).update(this.options.defaultText));

		var ul = $(Builder.node('ul')).hide();

		this.items.each(function (item) {
			item.chooser = this;

			if (!item.parent) {
				item.container = ul;
			}else {
				item.parent.addChild(item);
			}
		}.bind(this));


		this.items.each(function (item) {
			if (item.hasChildren()) {
				var ul = $(Builder.node('ul')).hide();

				item.children.each(function (child) {
					child.container = ul;
				});

				Event.observe(ul, 'mouseover', function (e) {if (e) e.stop()});
			}
		}.bind(this));

		this.items = this.items.sortBy(function (item) {
			return parseInt(item.order);
		});

		this.items.invoke('setup');
		this.container.appendChild(ul);

		var selected_item = this.items.find(function (item) {
			return item.getValue() == this.options.defaultValue; // TODO getValue
		}.bind(this));


		if (!selected_item) {
			this.items[0].selected = true;
			selected_item = this.items[0];
		}

		if (selected_item) {
			selected_item.selected = true;
			this.setValue(selected_item);
			this.selectedItem = selected_item;
		}

		Event.observe(this.container, 'click', this.onClick.bindAsEventListener(this));

		Event.observe(document, 'click', function () {
			this.container.down('ul').hide();
			Chooser.options.opened = null;

			if (this.openedSubContainer) {
				this.openedSubContainer.hide();
				this.openedSubContainer = null;
			}
		}.bind(this));

		// Для multiSelect добавляем пункт "Закрыть"
		if(this.options.multiSelect) {
			var itm=new Element('li',{ 'class': 'pcenter' }).update("[ "+dTexts.close+" ]");
			Event.observe(itm, 'click', this.onClickClose.bindAsEventListener(this));
			ul.insert({ bottom: itm });

			// Проходим по всем defaultValue и отмечаем соответствующие элементы
			var vals=this.options.defaultValue.split(",");
			for(var i in vals) if(typeof(vals[i])=="string")
				// Отмечаем пункты с таким id
				for(var itm in this.items) if(this.items[itm].id==vals[i])
					this.items[itm].mark();

				this.setValue();
			}
	},


  ///////////////////////////////////////////////////////////////////////////////////////////
	// Проверка рилейшенов. Списку передаются два значения:
	// - объект с выбранными элементами
	// - массив с последующими списками
	// Список вызывает эту же функцию для последующих списков, а потом возвращает результат тому, кто его вызвал
	prepareFilter: function(choosers) {
		// Если есть еще элементы в choosers, вызываем функцию для первого
		var fields=new Array();
		if(choosers.length>0) {
			var newchoosers=new Array();
			var i;
			for(i=1;i<choosers.length;i++) newchoosers[i-1]=choosers[i];
			fields=choosers[0].prepareFilter(newchoosers);
			//alert(JSON.stringify(fields));
			}

		// Добавляем свои элементы в список
		var i;
		var selection=this.selectedItems;
		if(!this.options.multiSelect && this.selectedItem!=null)
			selection[this.selectedItem.id]=1;

		var newfields=new Array();

		var j; var i;
		for(j=0;j<this.items.length;j++) {
			var itemid=this.items[j].id;
			if(itemid==0) continue; // Неактивный
			if(!this.selectedItems[itemid]) continue; // Не выбран

			if(fields.length==0) {
				// Если список пока пуст
				var newentry={};
				//newentry[this.options.formFieldName]=this.items[j].text;
				newentry[this.options.formFieldName]=itemid;
				newfields.push(newentry);
				}

			for(i=0;i<fields.length;i++) {
				// Если не пуст
				var newentry=Object.clone(fields[i]);
				//newentry[this.options.formFieldName]=this.items[j].text;
				newentry[this.options.formFieldName]=itemid;

				newfields.push(newentry);
				}
			}

		// Если у нас ничего собственного не нашлось, то возвращаем результат предыдущий
		if(newfields.length==0) return fields;

    return newfields;
		},


  ///////////////////////////////////////////////////////////////////////////////////////////
  filter: function (paramslist) {
		// Нам передан массив со всеми возможными элементами. Проходим по нему.
		var i;
		var debug="";
		var debugPause=0;

		// Добавляем пустой элемент - чтобы проверить все пункты меню без условий (некоторые могут быть скрыты)
		if(paramslist.length==0) paramslist.push({});

		// Если передан пустой paramslist (такое случается в начале обработки), то ничего не скрываем
		//var initialVisible=paramslist.length?0:1;
		this.items.each(function (item) { if (item.getId()) item.isVisible=0; });

		for(i=0;i<paramslist.length;i++) {
			var params=paramslist[i];
			//alert("testing "+JSON.stringify(params));

			//debug+="processing "+JSON.stringify(params)+"<br>";

			// Проходим по всем своим элементам, сначала отмечаем их видимыми/невидимыми
			this.items.each(function (item) {
				if(!item.getId()) return;
				// -1 - всегда показываются
				// Выбранные всегда показываются
				var selected=0;
				if(this.selectedItem!=null && this.selectedItem.id==item.id) selected=1;
				if(this.selectedItems[item.id]) selected=1;

				// Каждого спрашиваем, а связан ли он с кем-либо из указанного списка
					if (item.isRelated(params) || item.getValue()==-1 || selected)
						item.isVisible=1;
				}.bind(this));
			}

		// Проходим по всем своим элементам и включаем-отключаем
		this.items.each(function (item) {
			if(!item.getId()) return;
			// Игнорируем -1 - они всегда показываются
			if (!item.isVisible) {
				// Если не связан, то скрываем
				item.element.hide();

				var itemselected=false; // Если он был выбран, то сбрасываем выбор (надо поменять!)

				if(this.options.multiSelect)
         	itemselected=(this.selectedItems[item.id]==1);
				else
					itemselected=item.selected;

				if (itemselected) this.reset();
				debug+=item.text+" - hide<br>";
				//debugPause=1;
			} else {
				// Связан - показываем
				item.element.show();
				debug+=item.text+" - show<br>";
				}
			}.bind(this));

		//var itms=$$(".phone");
		//itms[0].update("<p style='font-size: 10px'>"+debug);
		//window.dOutput=debug.length;
		//if(debugPause)
		//	alert("debug");
	},

  ///////////////////////////////////////////////////////////////////////////////////////////
	getItemById: function (id) {
		if (id != null) {
			return this.items.find(function (item) {
				return item.getId() == id;
			});
		}

		return false;
	},

	////////////////////////////////////////////////////////////////
	setValue: function (chooserItem) {
		var old_value = this.container.down('input').value;

    var val=0;
  	if(chooserItem) {
			if (chooserItem.getId()) {
				this.container.down('input').value = chooserItem.getValue(); // TODO getValue
				this.container.down('input').enable();
				this.container.down('div').update(chooserItem.getText()).removeClassName('select_disabled');
			}else {
				this.container.down('input').value = 0;
				this.container.down('input').disable();
				this.container.down('div').update(this.options.defaultText).addClassName('select_disabled');
				}

			val=chooserItem.getValue(); // TODO getValue
			}

		// Если multiSelect, то формируем список из id
		if(this.options.multiSelect) {
			var itms=new Array();
			var lastText="";

			for(var i in this.selectedItems)
				if(typeof(this.selectedItems[i])=="number") {
					itms.push(i);
					// Ищем название
					this.items.each( function(item) {
						if(item.id==i) lastText=item.getText();
						});
					}


      if(itms.length>0) {
				this.container.down('input').enable();
				this.container.down('div').removeClassName('select_disabled');

	      if(itms.length>1)
					this.container.down('div').update(dTexts.selected+": "+itms.length);
				else
					this.container.down('div').update(lastText);
			} else {
				this.container.down('input').disable();
				}

			val=itms.join(",");
			if(val=="") val=0;

			this.container.down('input').value = val;
			}

		if (old_value != val) {
			this.options.onChange(chooserItem);
		}
	},

	////////////////////////////////////////////////////////////////
	getValue: function () {
		if(this.options.multiSelect) {
			var itms=new Array();
			for(var i in this.selectedItems) if(typeof(this.selectedItems[i])=="number")
				itms.push(i);

			return itms.length?itms:null;
		} else {
			return this.selectedItem ? this.selectedItem.getValue() : false;
			}
	},

	////////////////////////////////////////////////////////////////
	reset: function () {
		if (this.selectedItem) {
			this.selectedItem.selected = false;
			this.selectedItem = null;
		}

		if (this.items.size() > 0) {
			this.items[0].selected = false;
			this.selectedItem = this.items[0];
		}

    //alert("Reset called!");
  	if(this.options.multiSelect) {
  		var chooser=this;
			this.items.each( function(item) {
				if(chooser.selectedItems[item.id]==1) {
					item.unMark();
					}
				});
			}

		this.container.down('input').value = 0;
		this.container.down('input').disable();
		this.container.down('div').update(this.options.defaultText).addClassName('select_disabled');
	},

	////////////////////////////////////////////////////////////////
  onClickClose: function (event) {
  	this.selectedItem=null;
  	onClick(event);
  },

	////////////////////////////////////////////////////////////////
	onClick: function (event) {
		var ul = this.container.down('ul');

		// Если не multiSelect, то при щелчке список открывается-закрывается. Иначе - только открывается
		// Кроме того, закрываем, если выбран пункт "Все" (с id=0)
		//alert(this.options.multiSelect+" || !"+this.selectedItem+" || "+this.selectedItem.id);
		if(!this.options.multiSelect || !this.selectedItem || this.selectedItem.id==0) {
			ul.toggle();
		} else {
			if(!ul.visible()) ul.toggle();
			}

		if (Chooser.options.opened && Chooser.options.opened!=this) {
			// Если открыт какой-то другой список на странице, то закрываем его
			Chooser.options.opened.container.down('ul').hide();
		}

		if (ul.visible()) {
			Chooser.options.opened = this;

			if (this.selectedItem) {
				if (this.selectedItem.parent) {
					this.selectedItem.showContainer();
				}

			}
		} else {
			Chooser.options.opened = null;

			if (this.openedSubContainer) {
				this.openedSubContainer.hide();
				this.openedSubContainer = null;
			}
		}

		if (event) event.stop();
	}
};

/*--------------------------------------------------------------------------*/
/*  Class ChooserItem
/*--------------------------------------------------------------------------*/
var ChooserItem = Class.create();

ChooserItem.prototype = {
	initialize: function(options) {
		this.chooser = null;
		this.element = null;
		this.container = null;
		this.children = [];
		this.selected = false;
		this.parent = options.parent;
		this.id = options.id;
		this.value = options.value;
		this.text = options.text;
		this.order = options.order;
		this.is_country = options.is_country;
	},

	setup: function () {
		if (this.container) {
			var li = $(Builder.node('li')).update(this.text);
			this.container.appendChild(li);

			this.container = this.container;
			this.element = li;

			if (this.hasChildren()) {
				this.element.appendChild(this.children[0].container);
			}

			Event.observe(this.element, 'click', this.onClick.bindAsEventListener(this));
			Event.observe(this.element, 'mouseover', this.onMouseOver.bindAsEventListener(this));
			Event.observe(this.element, 'mouseout', this.onMouseOut.bindAsEventListener(this));
		}
	},

	getId: function () {
		return this.id;
	},

	getValue: function () {
		return this.value;
	},

	getText: function () {
		return this.text;
	},

	addChild: function (chooser_item) {
		this.children.push(chooser_item);
	},

	hasChildren: function () {
		return this.children.size() > 0;
	},

	mark: function () {
		this.setSelectedMark(1);
		this.chooser.selectedItems[this.id]=1;

		// Если при мультиселекте выбрали подпункт, то убираем отметку с родительского пункта, и просто подсвечиваем его
		if(this.parent) {
			this.parent.unMark();
			this.parent.setSelectedMark(1);
			}
	},

	unMark: function () {
		this.setSelectedMark(0);
		delete this.chooser.selectedItems[this.id];
	},

	setSelectedMark: function(mark) {
		if(mark)
			this.element.addClassName('selected');
		else
			this.element.removeClassName('selected');
		},

	showContainer: function () {
		if (this.parent) {
			this.container.setStyle({top:this.parent.element.offsetTop+'px'});
			this.chooser.openedSubContainer	= this.container;
		}

		this.container.show();
	},

	// Проверяет, связан ли этот элемент с теми, которые перечислены в params
	isRelated: function (params) {
		params = Object.clone(params);
		// Добавляем себя (чтобы понять, нарушится ли мировое равновесие, если мы будем в params)
		params[this.chooser.options.formFieldName] = this.getValue();

		//alert(this.id+" "+this.chooser.options.formFieldName+" "+JSON.stringify(params));

		var res=ChooserRelations.testSingle(params);

		return res;
	},

	//////////////////////////////////////////////////////////////////////////////////////////
	onClick: function (event) {
		// Если value==-1, то игнорируем
		if(this.value==-1) {
			this.chooser.ignoreNextClick=1;
			Event.stop(event);
			return;
			}

		// Если multiSelect, то не отменяем предыдущий выбор
		if(this.chooser.selectedItem && !this.chooser.options.multiSelect) {
			this.chooser.selectedItem.selected = false;
			this.chooser.selectedItem = null;
		}

		this.selected = true;
		this.chooser.selectedItem = this;

		this.chooser.onClick();

		// Если не multiSelect, то просто отмечаем элемент,
		// иначе ставим/снимаем отметку в зависимости от его состояния.
		// Игнорируем при наличии подменю
		if(!this.chooser.options.multiSelect) {
			this.mark();

			if (this.chooser.openedSubContainer) {
				this.chooser.openedSubContainer.hide();
				this.chooser.openedSubContainer = null;
				}
		} else {
			if(!this.chooser.selectedItems[this.id])
				this.mark();
			else
				this.unMark();


			// Если при мультиселекте выбрали родительский пункт, то убираем отметку со всех его потомков
			if (this.hasChildren())
				for(var i in this.children) if(this.children[i].unMark)
					this.children[i].unMark();

			// Если выбрали пункт "Все", то снимаем отметку со всех выбранных ранее пунктов
			var items=this.chooser.items;
			if(this.id==0)
				for(var i in items)
					if (items[i].unMark)
						items[i].unMark();
			}

		this.chooser.setValue(this);
		if (event) event.stop();
	},

	//////////////////////////////////////////////////////////////////////////////////////////
	onMouseOver: function (event) {
		if (this.chooser.selectedItem && !this.chooser.options.multiSelect) {
			this.chooser.selectedItem.unMark();
		}

		this.element.addClassName('over');

		if (this.chooser.openedSubContainer && this.chooser.openedSubContainer != this.container) {
			this.chooser.openedSubContainer.hide();
			this.chooser.openedSubContainer = null;
		}

		if (this.hasChildren()) {
			this.children[0].showContainer();
		}

		if (event) event.stop();
	},

	onMouseOut: function (event) {
		this.element.removeClassName('over');
		if (event) event.stop();
	}
};

////////////////////////////////////////////////////////////////////////////////////////
/*  Object ChooserRelations
/*--------------------------------------------------------------------------*/
var ChooserRelations = {
	relations: null,
	loaded: false,

	// Загружает рилэйшены из УРЛа
	load: function (url, params) {
		new Ajax.Request(url, {
			method: 'get',
			parameters: params,
			onSuccess: function (transport) {
				if (!transport.responseText.blank()) {
					try {
						var responseJSON = transport.responseText.evalJSON();
						this.relations = responseJSON;

						// Оптимизируем размер
						for (i in this.relations) {
							this.relations[i]["category_id"]=this.relations[i]["c"];
							this.relations[i]["producer_id"]=this.relations[i]["p"];
							this.relations[i]["material_id"]=this.relations[i]["m"];
							this.relations[i]["filler_id"]=this.relations[i]["f"];
							this.relations[i]["size_id"]=this.relations[i]["s"];

							delete this.relations[i]["c"];
							delete this.relations[i]["p"];
							delete this.relations[i]["m"];
							delete this.relations[i]["f"];
							delete this.relations[i]["s"];
							}

					} catch (e) {}
				}

				this.loaded = true;
			}.bind(this)
		});
	},

	testSingle: function(params) {
		// Проходим по всем рилэйшенам. Их вид:
		// "352623": { category_id:"3", producer_id:"5", material_id:"2", filler_id:"6", size_id:"23" }
		// params:
		// {"producer_id":"43"}
		// Все элементы из params должны быть в одном элементе ролэйшена - в таком случае проверка проходит. Тупо сделано.
		//
		// 20110323 - Для оптимизации добавил возможность указывать несколько значений параметра как массив
		// Например страна/производитель указываются как ["4","c212"]
		for (i in this.relations) {
			var found = true;

			//if(params["producer_id"]=="c212") alert(i);

			var relLine=this.relations[i];

      //&& params["category_id"]==33
      var ps=false;
			//if(params["producer_id"]=="3" && params["category_id"]==38 && relLine==38) {
			//	ps=true;
			//	alert(JSON.stringify(params)+"\n\n"+JSON.stringify(this.relations[i]));
			//	}

			for(name in params) {
				var relValue=relLine[name];

				// Должно совпасть хотя бы с одним из элементов, если это массив
				if(ps) alert("checking relValue "+name+", type "+typeof(relValue)+", value "+relValue);

				if(typeof(relValue)=="object") {
					if(ps) alert("checking object");
					var subitemFound=false;
					var j;
					for(j=0;j<relValue.length;j++)
						if(params[name]==relValue[j]) subitemFound=true;

					found=subitemFound;
				// Либо быть равно, если это строка
				} else if (params[name] != relValue)
					found = false;

        // Если не нашли, то запись нам не подходит
				if(!found) break;
				}

			if(found) {
				if(ps) alert("returning true");
				// Если мы тут оказались, то все элементы из params нашлись в одном релейшене
				return true;
				}
		}

		return false;
	}
};


/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Вызывается после загрузки страницы (см. shop_catalog_filter.xsl)
function initChoosers(categoryId,categoryFilterOn,fillerFilterOn,defaultTexts) {
	dTexts=defaultTexts;
	var Choosers = {
		list: [],
		loaded: false,

		add: function (obj) {
			Choosers.list.push(obj);
			},

		// Проверка рилейшенов
		// Работает следующим образом:
		// 1. собираем все списки в массив
		// 2. вызываем функцию filter первого списка в массиве, и передаем ей массив с оставшимися списками
		// 3. Chooser.filter то же самое делает для второго элемента массива...
		// Когда мы собрали все возможные комбинации, то
		filter: function () {
			var params = {};

			var choosers=new Array();
			var i;
			for(i=1;i<Choosers.list.length;i++)
				choosers.push(Choosers.list[i]);

			var res=Choosers.list[0].prepareFilter(choosers);

			//alert("item test: "+JSON.stringify(res));

			// Теперь для каждого списка вызываем фильтр и передаем ему текущий выбранный список
			Choosers.list.each( function (chooser) {
				chooser.filter(res);
				});
			},

		load: function (onComplete) {
			var activeRequests = 0;

			Choosers.list.each(function (chooser) {
				activeRequests++;

				chooser.load(function () {
					activeRequests--;
					});
				});

			new PeriodicalExecuter(function(timer) {
				if (activeRequests == 0) {
					if (typeof onComplete == "function") {
						onComplete();
						}

					Choosers.loaded = true;
					timer.stop();
					}
				}, 0.01);
			}
		};

		//////////////////
		// Настройка полей

		var QueryString = location.search.toQueryParams();
		var curCategory=QueryString.category_id ? QueryString.category_id : categoryId;

    if(categoryFilterOn)
			Choosers.add(new Chooser({
				container: 'filter_field_category',
				url: '/filter/categories/',
				queryParams: { category_id: categoryId },
				defaultValue: curCategory,
				defaultText: defaultTexts.category,
				formFieldName: 'category_id',
				// multiSelect: 1,  // Нельзя выбрать несколько категорий
				onChange: function () { Choosers.filter(); }
				}));

		Choosers.add(new Chooser({
			container: 'filter_field_size',
			url: '/filter/sizes/',
			queryParams: { category_id: categoryId },
			defaultValue: (QueryString.size_id),
			defaultText: defaultTexts.size,
			formFieldName: 'size_id',
			//multiSelect: 1,
			onChange: function () { Choosers.filter(); }
			}));

		Choosers.add(new Chooser({
			container: 'filter_field_material',
			url: '/filter/materials/',
			queryParams: { category_id: categoryId },
			defaultValue: QueryString.material_id,
			defaultText: defaultTexts.material,
			formFieldName: 'material_id',
			//multiSelect: 1,
			onChange: function () { Choosers.filter(); }
			}));

		if(fillerFilterOn)
			Choosers.add(new Chooser({
				container: 'filter_field_filler',
				url: '/filter/fillers/',
				queryParams: { category_id: categoryId },
				defaultValue: QueryString.filler_id,
				defaultText: defaultTexts.filler,
				formFieldName: 'filler_id',
				//multiSelect: 1,
				onChange: function () { Choosers.filter(); }
				}));

		Choosers.add(new Chooser({
			container: 'filter_field_producer',
			url: '/filter/producers/',
			queryParams: { category_id: categoryId },
			defaultValue: QueryString.producer_id,
			defaultText: defaultTexts.producer,
			formFieldName: 'producer_id',
			//multiSelect: 1,
			onChange: function () { Choosers.filter(); }
			}));

		Choosers.load();
		ChooserRelations.load('/filter/links/', { category_id: categoryId });

		new PeriodicalExecuter(function(timer) {
			if (Choosers.loaded && ChooserRelations.loaded) {
				Choosers.filter();
				timer.stop();
				}
			},
			0.01);

}

