/**
 * @author Andrey Lugovtsov
 * @author Vladimir Cvetic over @ ferdinand.rs
 */
Effect.DefaultOptions.queue = "end";
Effect.DefaultOptions.duration = 0.2;
var taggerBaseClass = Class.create({
	/**
	 * @param el Собственно элемент, внутри которого будут вызываться собыитя.
	 * @param t Элемент, клик по которому вызовет открытие tagger'a
	 */
	initialize: function(el, t, options) {
		this.element = $(el);
		this.trigger = $(t);
		
		this.options = Object.extend({
				sqsize: '25%',
				sqclass: 'square-class',
				tagInputClass: 'tag-input',
				tagsContainer: null,
				tag_square_class: 'tag_square_class',
				tag_class: 'tag_class',
				remove_link_class: 'remove_link_class',
				lang: {
					add: 'Add',
					remove: 'Close'
				}
			}, options || {}
		);
		
		this.itemId = 0;
		this.busy = 0;

		if (this.element) {		
			this.cos = this.element.cumulativeOffset();
			this.dim = this.element.getDimensions();
			
			Event.observe(document.onresize ? document : window, 'resize', function() {
				this.cos = this.element.cumulativeOffset();
			}.bind(this));
		}
		
		this.init();
	},
	
	init: function () {},
	
	createCropper: function(options) {
		this.cropper = new Cropper.Img(this.element, Object.extend({
				minWidth: 50,
				minHeight: 50,
				captureKeys: false,
				'onStartDrag': this.onCropStartDrag.bind(this),
				'onMove': this.onCropperMove.bind(this),
				'onEndCrop': this.onEndCrop.bind(this),
				'onResize': this.onCropperResize.bind(this)
		}, options));
	},
	
	onCropStartDrag: function(e) {
		this.element.fire('element:start-dragging');
		this.hideTagInputBox();
	},
	
	onCropperMove: function(point) {
		this.element.fire('element:cropper-move');
		this.hideTagInputBox();
	},
	
	onCropperResize: function(e) {
		this.element.fire('element:cropper-resize');
		this.hideTagInputBox();
	},
	
	onEndCrop: function(e) {
		this.showTagInputBoxNearSquare();
	},
	
	initObjectsAutoCompleter: function() {
		this.objectsCompleter = new customAutocompleterForTags({
			'targetInput': this.objectInputElement,
			'commentsInput': this.commentInputElement,
			'resultsHolder': this.tagInputBox.down('.autocompleter-results'),
			'resultsLimit': 5,
			'onResultClick': function(text, addInfo) {
				this.itemId = addInfo[1];
			}.bind(this),
			'minChars': 0,
			'requestUrl': '/user/followedJson/',
			'busyIndicator': 'flp_indicator',
			'singleRequest': false
		});
		
		// в моем автокомплитере query нужно выполнять самому
		with (this.objectInputElement) {
			observe('keyup', function() {
				if (typeof t != 'undefined') {
					clearTimeout(t);
				}
				t = this.objectsCompleter.query.bind(this.objectsCompleter).delay(0.4, this.objectInputElement.getValue());
			}.bind(this));
			
			this.queryOnFocus = 1;
			
			observe('focus', function() {
				this.objectsCompleter.query(this.objectInputElement.getValue(), this.queryOnFocus);
				//this.queryOnFocus = 0;
			}.bind(this));
		}
	},

	initTagInputBox: function () {
		this.tagInputBox = $(this.element.getAttribute('id') + '-box').remove().cloneNode(true);
		
		Element.insert(document.body, this.tagInputBox);
		
		with(this.tagInputBox) {
			setStyle({'position': 'absolute'});
			observe('mouseup', function(e) { e.stop(); });
			down('button.add').observe('click', this.performAddTagRequest.bindAsEventListener(this));
			down('button.close').observe('click', this.closeTagInputBox.bindAsEventListener(this));
		}
		
		// input для комментария к метке 
		this.commentInputElement = $(this.element.getAttribute('id') + '-comment');
		
		// input для выбора объекта метки
		this.objectInputElement = $(this.element.getAttribute('id') + '-object');
	},

	showTagInputBox: function (x, y) {
//		window.console.log('show')
		with (this.tagInputBox) {
			setStyle({
				'top': y + 'px',
				'left': x + 'px'
			});
			//show();
		}
		new Effect.Appear(this.tagInputBox, {
			duration: 0.5,
			afterFinish: function() {
				this.objectInputElement.focus();
			}.bind(this)
		});
	},
	
	closeTagInputBox: function() {
		this.element.fire('element:cropper-end');
		this.hideTagInputBox();
		this.resetTagInputBox();
	},
	
	showTagInputBoxNearSquare: function() {
		var c = this.cropper.areaCoords;
		var co = this.cos;
		this.showTagInputBox(c.x2 + 5 + co[0], c.y1 + co[1]);
	},
	
	hideTagInputBox: function() {
		with (this.tagInputBox) {
			hide();
			blur();
		}
		this.queryOnFocus = 1;
	},
	
	resetTagInputBox: function() {
		this.commentInputElement.setValue(null);
		with (this.objectInputElement) {
			setValue(null);
			removeAttribute('disabled');
			blur();
			show();
		}
		try {
			this.tagInputBox.down('.autocompleter-results').update(null);
		}
		catch (e) {};
	},
	
	performAddTagRequest: function() {
		if (this.busy) {
			return false;
		}
		
		var addParams = {};
		
		if (this.cropper) {
			var c = this.cropper.areaCoords;
			Object.extend(addParams, {
				'x1': c.x1, 
				'y1': c.y1,
				'x2': c.x2, 
				'y2': c.y2,
			})
		}

		// если выбран какой-то объект, иначе не включать это в запрос
		if (this.itemId > 0) {
			Object.extend(addParams, {
				'item_id': this.itemId,
				'item_type': this.options.itemType
			});
		}
		
		new Ajax.Request(this.options.url['save'], {
			method: 'post',
			parameters: Object.extend(addParams, {
				'comment': this.commentInputElement.getValue(),
				'media_id': this.options.mediaId,
				'media_type': this.options.mediaType,
				'item_note': this.objectInputElement.getValue()
			}),
			onCreate: function() {
				this.busy = 1;
			}.bind(this),
			onSuccess: function(r) {
				r = r.responseText;
				if (r.isJSON()) {
					r = r.evalJSON();
					if (r.error) {
						this.busy = 0;
						return alert(r.error);
					}
				}
				this.itemId = 0;
				this.element.fire('container:add-element', r);
				this.busy = 0;
			}.bind(this)
		});
	},
	
	performRemoveTagRequest: function(params, href) {
		new Ajax.Request(this.options.url['delete'], {
			method: 'get',
			parameters: params,
			onSuccess: function(r) {
				r = r.responseText;
				this.element.fire('container:remove-element', {'response': r, 'href': href});
			}.bind(this)
		});
	}
});

/**
 * Кастомный комплитер объектов
 */
var customAutocompleterForTags = Class.create(autoCompleter, {
	_populateResults: function(r) {
		var h = this.config.resultsHolder;
		var matches = r.findAll(function(a) {
			var v = a[0].toLowerCase();
			if (v.strip().startsWith(this.queryString)) {
				return true;
			}
		}, this);
		if (matches.size() < 1) {
			this.hideResults();
			return;
		}
		this.clearResultBox(h);
		var ul = this.config.resultsHolder.down('ul');
		matches.each(function(a, i) {
			if (i >= this.config.resultsLimit) {
				throw $break;
			}
			this.appendVariant(a, ul);
		}, this);
		this.showResults();
	},
	
	appendVariant: function(a, ul) {
		
		var cbox = new Element('input', {'type': 'checkbox'});
		cbox.observe('click', function(e) {
			with (Event.element(e)) {
				getValue() == 'on' ? setValue(false) : setValue('on');
			}
		});
		var text = (new Element('span')).update(a[0]);
		var img = new Element('img', {src: a[1][0]});
		var li = new Element('li');
		with (li) {
			addClassName(this.config.liClassName);
			appendChild(cbox);
			appendChild(img);
			appendChild(text);
		}
		ul.appendChild(li);
		
		function onClick(e) {
			// эта фигня будет ездить вверх/вниз
			var blindTarget = this.config.targetInput;
			with (cbox) {
				getValue() == 'on' ? setValue(false) : setValue('on');
			}
			if (cbox.getValue() == 'on') {
				li.removeClassName('selected');
				// оставив только элемент с выбранным значением
				// нужно очистить поле автокомплитера
				new Effect.BlindUp(blindTarget, {
					afterFinish: function() {
						this.config.resultsHolder.select('li').each(function(item) {
							if (item.down('input').getValue() != 'on') {
								item.remove();
							}
						});
						with (this.config.targetInput) {
							// заполним поле выбранным значением
							//setValue(a[0]);
							
							// и задизаблить поле
							//setAttribute('disabled', 'disabled');
						}
						new Effect.BlindDown(this.config.resultsHolder);
						this.config.commentsInput.focus();
					}.bind(this)
				});
			}
			else {
				new Effect.BlindDown(blindTarget, {
					afterFinish: function() {
						with (this.config) {
							targetInput.setValue(null).focus();
							targetInput.removeAttribute('disabled');
							// обнуляем itemId
							onResultClick(null, 0);
						}
						this.query(this.config.singleRequestQueryString, 1);
					}.bind(this)
				});
			}
			// здесь просто положим itemId в класс taggerBase
			this.config.onResultClick(a[0], a[1], cbox.getValue());
		}
		var onClick = onClick.bindAsEventListener(this);
		// клик по чекбоксу вызовет внутреннюю функцию, которую мы сможем переопределить во вне
		li.observe('click', onClick).observe('variant:click', onClick);
	}
});

/**
 * Задача данного класса - отображать рамки при наведении курсора на тэг
 * и давать возможность удалить тэг хозяину
 */
var tagListClass = Class.create(taggerBaseClass, {
	initialize: function($super, el, c, options) {
		// контейнер готовых тэгов
		$super(el, null, Object.extend(options, {'tagsContainer': c}));
	},
	
	init: function($super) {
		this.createSquare();
		
		// обноим список, хандлеры при добавлении вого тэга
		this.listenAddTagEvent(this.addTagEventHandler);
		
		// при удалении тэна удалим и его элемент в доме
		this.listenRemoveTagEvent(this.removeTagEventHandler);
		
		// на каждый из элементов тэга повесим необходимые события
		this.options.tagsContainer.select('.tag-info').each(function(div) {
			this.addTagElementsEventsObservers(div);
		}.bind(this));
	},
	
	addTagElementsEventsObservers: function(div) {
		// удаление тэгов
		var a = div.down('.remove-tag');
		if (a) {
			a.observe('click', function() {
				// получим tagId из спрятанного дива
				var tagId = div.down('.tag-data').innerHTML.split(',')[0];
				
				// совершаем запрос на удаление тэга
				this.performRemoveTagRequest({'tag_id': tagId}, a);
			}.bind(this));
		}
		
		// данные о координатах берем из скрытого span'а
		var frameInfo = div.down('.frame-data');
		if (frameInfo) {
			frameInfo = frameInfo.innerHTML.split(',');
			var a = div.down('.mouseover');
			
			// отобразим рамку по mouseover
			a.observe('mouseover', function() {
				this.showSquare(frameInfo[0], frameInfo[1], frameInfo[2], frameInfo[3]);
			}.bind(this));
			
			// спрячем рамку по mouseout
			a.observe('mouseout', function() {
				this.hideSquare();
			}.bind(this));
		}
		
		this.denyShowSquares = 0;
		this.element.observe('element:start-dragging', function() {
			this.denyShowSquares = 1;
		}.bind(this));
		this.element.observe('element:cropper-end', function() {
			this.denyShowSquares = 0;
		}.bind(this));
	},
	
	listenAddTagEvent: function(f) {
		this.element.observe('container:add-element', f.bindAsEventListener(this));
	},
	
	addTagEventHandler: function(e) {
		var l = $(this.options.tagsContainer);
		Element.insert(l, e.memo);
		this.addTagElementsEventsObservers(l.select('.tag-info').last());
		this.considerShowOrHideTagsContainer();
	},
	
	removeTagEventHandler: function(e) {
		var r = e.memo.response, a = e.memo.href;
		if (Object.isString(r) && r.isJSON()) {
			r = r.evalJSON();
			if (r.error) {
				return alert(r.error);
			}	
		}
		a.up('.tag-info').remove();
		this.considerShowOrHideTagsContainer();
	},
	
	listenRemoveTagEvent: function(f) {
		this.element.observe('container:remove-element', f.bindAsEventListener(this));
	},
	
	considerShowOrHideTagsContainer: function() {
		var c = $(this.options.tagsContainer);
		c.select('.tag-info').length < 1 ? c.hide() : c.show();
	},
	
	/**
	 * Создает рамку в this.square
	 */
	createSquare: function() {
		this.square = new Element('div');
		with (this.square) {
			hide();
			addClassName(this.options.sqclass);
			setStyle({
				'position': 'absolute',
				'zIndex': 1002
			});
		}
		
		Element.insert(document.body, this.square);
	},
	
	hideSquare: function() {
		this.square.hide();
	},

	showSquare: function(x1, y1, x2, y2) {
		if (this.denyShowSquares) {
			return false;
		}
//		window.console.log("пытаюсь отобразить рамку: ", [x1, y1, x2, y2], [this.cos], [this.element.cumulativeOffset()]);
		with (this.square) {
			setStyle({
				'left': parseInt(x1) + parseInt(this.cos[0]) + 'px',
				'top': parseInt(y1) + parseInt(this.cos[1]) + 'px',
				'width': x2 - x1 + 'px',
				'height': y2 - y1 + 'px'
			});
			show();
		}
	}
});
