function adminWidget() {
	if($('admin-actions-wrapper')) {
		var adminActions = new Fx.Slide($('admin-actions-wrapper'));
		adminActions.hide();
		$('admin-actions-title').addEvent('click', function(e){
			e = new Event(e); e.stop();
			adminActions.toggle();
			e.target.toggleClass('opened');
			
		});
	}
}

document.addEvent('domready', function() {

	// Admin widget
	adminWidget();	
	
	
	// reflink container 
	if($('reflink-field')) {
		$('reflink-field').addEvent('focus', function() {
			this.select();
		});
	}
	
	// invitation form
	if($('invite-friend-form')) {
		$('invite-friend-form').addEvent('submit', function(e) {
			e = new Event(e); e.stop();
			var reg = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;

			if(reg.test($('invite-email').value)) {
				$('invite-friend-form').addClass('no-display');
				$('successfull-invite').removeClass('no-display');
				$('invite-email-error').addClass('no-display');
				$('invite-friend-form').send();
				$('invite-friend-form').reset();
			} else {
				$('invite-email').focus();
				$('invite-email-error').removeClass('no-display');
			}
		});
		
		$('successfull-invite').addEvent('click', function(e) {
			e = new Event(e); e.stop();
			
			$('invite-friend-form').removeClass('no-display');
			$('successfull-invite').addClass('no-display');
			$('invite-email').focus();
		});
	}

	if($('rating')) {
		$('rating').addEvent('mouseover', function() {
			this.addClass('hovered');
		});
		$('rating').addEvent('mouseout', function() {
			this.removeClass('hovered');
		});
		$('rating').addEvent('click', function() {
			if($('rate-this')) $('rate-this').fireEvent('click');
			if($$('#rating > div.right > div > a.igp_white')[0]) $$('#rating > div.right > div > a.igp_white')[0].fireEvent('click');
		});
	}
									  
	if($('searchInput')) { 
		var defaultValue = $('searchInput').getProperty('default');
		$('searchInput').addEvent('focus', function() {
			if($('searchInput').value == defaultValue) $('searchInput').value = '';
			$('searchInput').removeClass('focused');		
		});
		
		$('searchInput').addEvent('blur', function() {
			if($('searchInput').value == '') $('searchInput').value = defaultValue;
			$('searchInput').addClass('focused');		
		});
	}
	
	
	$each($$('#side-help-on-igp .side-help-title, #side-help-on-igp-1 .side-help-title'), function(item) {
		item.addEvent('click', function(e) { e.stop(); });
	});
	
	if($('side-help-on-igp')) {
	
		var myAccordion = new Accordion($('side-help-on-igp'), '.side-help-title', '.block', {
			opacity: false,
			display: null,
			alwaysHide: true
		});
	}

	function initCommentBtns() {
		$each($$('#comments div.itself'), function(item) {
			item.addEvent('mouseover', function() {
				this.getParent().addClass('hovered');
			});
		
			item.addEvent('mouseout', function() {
				this.getParent().removeClass('hovered');
			});
		});
	}
	initCommentBtns();
	
	if($('report-a-bug-area')) {	
		
		$('report-a-bug-area').addEvent('mouseover', function() {
			this.addClass('hovered');
		});
		
		$('report-a-bug-area').addEvent('mouseout', function() {
			this.removeClass('hovered');
		});
		
		$('report-a-bug-area').addEvent('click', function() {
			$('report-a-bug-area').toggleClass('no-display');
			$('report-a-bug-area-opened').toggleClass('no-display');
			$('ticket_body').focus();
		});
	
		$each($$('.report-a-bug-link'), function(item) {
			item.addEvent('click', function(e) {
				$('report-a-bug-area').toggleClass('no-display');
				$('report-a-bug-area-opened').toggleClass('no-display');
				$('ticket_body').focus();										  
				e = new Event(e); e.stop();
				if(e.target.get('text') == 'Есть предложение?') $('ticket_type').value = 'Вношу предложение';
				if(e.target.get('text') == 'Нужна помощь?') $('ticket_type').value = 'Нужна помощь';
				if(e.target.get('text') == 'Видишь баг?') $('ticket_type').value = 'Сообщаю о баге';
				//$('ticket_type').options[$$('.report-a-bug-link').indexOf(item)].selected = 'selected';
				
			});
		});
		
		$('report-close-btn').addEvent('click', function(e) {
			$('report-a-bug-area').toggleClass('no-display');
			$('report-a-bug-area-opened').toggleClass('no-display');	
			e = new Event(e); e.stop();
		});
	}
	
	if($('posts')) {
		$each($$('#posts .item'), function(item, index) {
			item.addEvent('mouseover', function() {
				this.toggleClass('hovered');
			});
			
			item.addEvent('mouseout', function() {
				this.toggleClass('hovered');
			});
		});
	}
		
	
	if($('new-vb-video-listing')) {
		function setVideoListing(){
			$$('div.new-vb-single-toggler').addEvent('mouseover', function() {
				this.addClass('hovered');
			});
			
			$$('div.new-vb-single-toggler').addEvent('mouseout', function() {
				this.removeClass('hovered');
			});
			
			$$('div.new-vb-single-toggler .video-descr-toggler').addEvent('mouseover', function() {
				this.addClass('hovered');
			});
			
			$$('div.new-vb-single-toggler .video-descr-toggler').addEvent('mouseout', function() {
				this.removeClass('hovered');
			});
			
			var myAccordion = new Accordion($('new-vb-video-listing'), 'div.new-vb-single-toggler', 'div.new-vb-single-content', {
				opacity: false,
				alwaysHide: true,
				onActive: function(toggler, element){
					toggler.getParent().addClass('opened');
					toggler.getLast().addClass('opened');
					toggler.getLast().getChildren()[0].set('text', 'Скрыть видео');
				},
				onBackground: function(toggler, element){
					toggler.getParent().removeClass('opened');
					toggler.getLast().removeClass('opened');
					toggler.getLast().getChildren()[0].set('text', 'Показать видео');
				},
				display: null
			});
		}
		
		setVideoListing();
		var layer = $$('div.first div.new-vb-single-content');
                var layerText = $$('div.first div.video-descr-toggler span');
                var layerToggler = $$('div.first div.video-descr-toggler');
                layer.setStyle('height', '52px');
                layerText.set('text', 'Скрыть видео');
                layerToggler.addClass('opened');
	}
		
	
	
	if($('new-vb-wizard')) {
		var allLinksInFilter = $$('.three-steps-wizard a');
		var prevId = '';
		
		$('old-school-filter-content').toggleClass('no-display');
		
		$$('.vb-filter-toggler').addEvent('click', function(e) {			
			
			$('vb-toggler-1').toggleClass('no-display');
			$('vb-toggler-2').toggleClass('no-display');
			
			$('three-steps-wizard').toggleClass('no-display');
			$('old-school-filter-content').toggleClass('no-display');
														  
			e.stop();
		});
		
		function requestFilteredVideos(address) {
			var requestVideo = new Request({
				url: address,
				onRequest: function() {
					if($('video-loader-ind')) $('video-loader-ind').toggleClass('loading');
				},
				onSuccess: function(responseText) {
					$('new-vb-video-listing').set('html', responseText);
					if($('video-loader-ind')) $('video-loader-ind').toggleClass('loading');
					setVideoListing();
				},
				onFailure: function() {
					alert('Упс, что-то пошло не так. Попробуйте еще раз чуть позже.');
					if($('video-loader-ind')) $('video-loader-ind').toggleClass('loading');
					setVideoListing();
				}
			}).get();
		}
		
		if($('reset-video-filter')) {
			$('reset-video-filter').addEvent('click', function(e) {
				e = new Event(e);
				e.stop();
				requestFilteredVideos(e.target.href);
				allLinksInFilter.removeClass('selected');
				$$('#three-steps-wizard .second-level ul, #three-steps-wizard .third-level ul').addClass('no-display');				
			});
		}
		
		$each(allLinksInFilter, function(item) {
			item.addEvent('click', function(e) {
				e = new Event(e);
				e.stop();
				
				var thisParentLinks = e.target.getParent().getParent().getParent();
				var thisParentNext = e.target.getParent().getParent().getParent().getNext();
				var thisId = e.target.getParent().id;
				
				if(e.target.className == 'selected') { 
					e.target.toggleClass('selected');	
				} else {
					requestFilteredVideos(e.target.href);
				}
				
				$$('.' + thisParentLinks.className + ' ul li a').removeClass('selected');
				if( thisParentNext.getNext()) $$('.' + thisParentNext.className + ' ul li a').removeClass('selected');	
				
				$$('.' + thisParentNext.className + ' ul').addClass('no-display');					
				if( thisParentNext.getNext()) $$('.' + thisParentNext.getNext().className + ' ul').addClass('no-display');
				
				if($('level-for-' + thisId)) $('level-for-' + thisId).toggleClass('no-display');
				
				e.target.toggleClass('selected');
			});
		});
	}
	
	if($('searchSubmit')) {
		$('searchSubmit').setStyles({
			'opacity': '0.7',
			'filter': 'alpha(opacity = 75)'
		});
		
		$('searchSubmit').addEvent('click', function() {
			$('searchForm').submit();
		});
		
		$('searchSubmit').addEvent('mouseover', function() { 
			$('searchSubmit').setStyles({
				'opacity': '1',
				'filter': 'alpha(opacity = 100)'
			}); 
		});
		
		$('searchSubmit').addEvent('mouseout', function() { 
			$('searchSubmit').setStyles({
				'opacity': '.7',
				'filter': 'alpha(opacity = 75)'
			}); 
		});
	}
	
	function addPopup2Btn(popupId, btnId) {
		
		if($(btnId) && $(popupId)) {
			$(btnId).addEvent('click', function(e) {
				$(popupId).setStyles({
					visibility : 'visible',
					position: 'relative',
					top : '-22px',
					left : '0',
					opacity : '0'
				});
				if($('placeActionsCont')) $('placeActionsCont').removeClass('no-display'); 
				
				$(popupId).fade(Browser.Engine.trident ? 'show' : 'in');
						
				e = new Event(e).stop();
				
				window.addEvent('click', function(e) {
					e = new Event(e);
					if(!$(e.target).getParent('#'+popupId) && e.target.id != btnId && $(popupId).getStyle('opacity') != '0') {				
						$(popupId).fade(Browser.Engine.trident ? 'show' : 'out');
						if($('placeActionsCont')) $('placeActionsCont').addClass('no-display');
					}
				});
			});
		}
	}

		
	addPopup2Btn('placeActions', 'placeActionsBtn');
	
	
});

$E = function(what) { return $$(what)[0] }



IGC = new Class({
	Implements: [Events],
	
	initialize: function() {
		document.addEvent('domready', this.loaded.bind(this));
	},
	
	loaded: function() {
		this.fireEvent('load');
		this.fireEvent('reload', $(document.body));
	},
	
	reload: function(el) {
		return function() {
			this.fireEvent('reload', $(el))
		}.bind(this)
	},
	
	response: function() {
		for (var name in IGC.$events) {
			var header = name.match(/onRecieve(.*)/)
			if (!header) continue; 
			header = header[1].replace(/[a-z][A-Z]/g, function(match){ return match.charAt(0) + '_' + match.charAt(1).toUpperCase();});
			var value = this.getCustomHeader(header)
			if (!value) continue;
			IGC.fireEvent(name, value);
		}
	}
	
});
IGC = new IGC;

var Indicator = new Class({
	initialize: function(parent, where) {
		this.hook = parent;
		this.where = where || 'after';
		return this;
	},
	
	get: function() {
		if (!this.meter) this.meter = this.create();
		return this.meter;
	},
	
	create: function() {
		return new Element('div', {'class': 'indicator'}).inject(this.hook, this.where);
	},
	
	show: function() {
		this.get().fade('in');
	},
	
	hide: function() {
		this.get().fade('out');
	}
});


var Featured = new Class({
	initialize: function(el, thing) {
		this.el = $(el);
		this.controls = $(thing)
		if (!this.el || !this.controls) return;
		this.prev_button = $(thing).getFirst();
		this.prev_button.addEvent('click', this.next.bind(this))
		this.next_button = $(thing).getLast();
		this.next_button.addEvent('click', this.prev.bind(this))
		this.current = this.el.getFirst();
		this.current.fade('show');
		this.start();
		
		this.el.getParent().addEvents({
			'mouseenter': this.stop.bind(this), 
			'mouseleave': this.start.bind(this)
		})
	},
	
	next: function() {
		if (this.process) return;
		this.to($pick(this.current.getNext(), this.el.getFirst()))
	},
	
	prev: function() {
		if (this.process) return;
		this.to($pick(this.current.getPrevious(), this.el.getLast()))
	},
	
	to: function(el) {
		this.process = true;
		this.current.fade('out');
		(function() {
			this.current = el
			this.current.fade('in');
			(function() {
				this.process = false
			}).delay(500, this)
		}).delay(600, this)
	},
	
	stop: function() {
		this.interval = $clear(this.interval)
	},
	
	start: function() {
		this.interval = this.next.periodical(15000, this);
	}
})

var Selector = {
	init: function() {
		if (!$('game-selector')) return
		Selector.el = $('game-selector')
		Selector.el.setStyle('opacity', '.7');
		Selector.ul = Selector.el.getFirst();
		Selector.ul.fade('hide')
		Selector.el.addEvent('click', Selector.show);
		Selector.ul.addEvents({
			'mouseenter': Selector.clear,
			'mouseleave': Selector.hide
		});
		Selector.el.addEvents({
			'mouseenter': Selector.incOpac,
			'mouseleave': Selector.decOpac
		});
	},
	
	incOpac: function() {
		Selector.el.setStyle('opacity', '1');
	},
	
	decOpac: function() {
		if(Selector.ul.getStyle('visibility') != 'visible') Selector.el.setStyle('opacity', '.7');
	},
	
	clear: function() {
		$clear(Selector.timer);
	},
	
	show: function() {
		Selector.clear()
		Selector.el.fade(Browser.Engine.trident ? 'show' : 'in');
		Selector.ul.fade(Browser.Engine.trident ? 'show' : 'in');
		shownList = true;
	},
	
	hide: function() {
		Selector.timer = (function() {
			//Selector.el.fade(Browser.Engine.trident ? 'hide' : 'out')
			Selector.ul.fade(Browser.Engine.trident ? 'hide' : 'out')
			shownList = false;
		}).delay(700)
		setTimeout("Selector.el.setStyle('opacity', '.7');", 800);
	},
	
	get: function(e) {
		e = $(e.target)
		if (e.get('tag') == 'a') return e;
		return e.getFirst();
	},
	
	start: function(e) {
		Selector.get(e).fade('in')
	},
	
	stop: function(e) {
		Selector.get(e).fade('out')
	}
}


Slider = {
	init: function() {
		Slider.el = $('language-selector');
		if (Slider.el == null) return;
		var a = $$(Slider.el.getElementsByTagName('a'));
		Slider.ru = a[0];
		Slider.en = a[1];
		Slider.fx = new Fx.Tween(null, {link: 'cancel', property: 'width'});
		Slider.fx.set =  function(now){
			this.render(this.element, this.property, now);
			this.render(this.element == Slider.ru ? Slider.en : Slider.ru, this.property, (45 - this.serve(now, '')) + 'px')
			return this;
		}
		a.addEvent('mouseenter', Slider.start)
		Slider.el.addEvent('mouseleave', Slider.stop)
	},
	
	start: function(e) {
		$clear(Slider.timer)
		if (e.target) e = $(e.target);
		Slider.fx.element = e;
		Slider.fx.start('width', 44)
	},
	
	stop: function(e) {
		Selector.timer = (function() {
			Slider.start('width', Slider.ru.hasClass('current') ? Slider.ru : Slider.en)
		}).delay(1000)
	}	
}

Highlight = new Class({
	initialize: function(el, hover) {
		this.el = $(el);
		this.hover = $(hover)
		if (!this.el) return;
		this.el.setOpacity(0.75);
		$pick(hover, el).addEvents({
			'mouseenter': this.start.bind(this),
			'mouseleave': this.stop.bind(this)
		})
	},
	
	start: function() {
		this.el.fade(0.85);
	},
	
	stop: function() {
		this.el.fade(0.75);
	}
})


Authorization = {
  initialize: function(el) {
    this.el = $(el)
    if (!this.el) return;
    this.fx = new Fx.Scroll(this.el, {transition: Fx.Transitions.Circ.easeInOut})
    this.el.getElements('a.swap').addEvent('click', this.click.bind(this));
    this.el.scrollTo(0, 0)
  }, 
  
  click: function(e) {
    this.fx.start($(e.target).getParent('div.frame').hasClass('first') ? 530 : 0, 0)
    return false
  }
}



Appearance = new Class({
  
  options: {
    onShow: $empty,
    onHide: $empty
  },
  
	initialize: function(el, clickie, options) {
		if (!$(el)) return;
		this.el = $(el);
		this.el.fade('hide')
		$pick(clickie, el).addEvent('click', this.show.bind(this))
		this.setOptions(options)
		el.addEvents({
			'mouseenter': this.stop.bind(this),
			'mouseleave': this.start.bind(this)
		})
	},
	
	show: function(e) {
	  e.stop();
	  this.fireEvent('onShow');
		this.el.fade(Browser.Engine.trident ? 'show' : 'in');
	},

	hide: function() {
	  this.fireEvent('onHide');
		this.el.fade(Browser.Engine.trident ? 'hide' : 'out');
	},
	
	start: function() {
		this.delay = this.hide.delay(500, this)
	},
	
	stop: function() {
		$clear(this.delay);
		this.show;
	}
})

Appearance.implement(new Options)
Appearance.implement(new Events)


Helpers = {
	substractDimensions: function(o2, o1) {
		o2.x = o2.x - o1.x;
		o2.y = o2.y - o1.y;
		return o2;	
	}
}

Element.implement({
	getPositionRelativeTo: function(to) {
		return Helpers.substractDimensions(this.getPosition(), Element.getPosition(to))
	}
});

Toolbox = new Class({
	initialize: function(els, box) {
		if (els.length == 0 || !box) return;
		this.user_prop_regex = /user_(.*)/
		
		this.other = {"user_online": "0", "remote": "0"}
		
		this.els = els;
		this.box = box;
		this.els = $$(this.els.filter(function(el) { return !el.hasClass('no-tip')}));
		this.els.addEvent('click', this.click.bind(this));
		this.box.set('tween', {duration: 250});
		this.assign(this.box);
	},
	
	click: function(e) {
		e.stop();
		//this.box.fade('hide');
		var el = $(e.target);
		this.current = el;
		this.prepare(el);
		this.show(el);
		this.fetch();
		this.assign(el);
	},
	
	assign: function(el) {
		el.addEvents({
			'mouseenter': this.showing.bind(this),
			'mouseleave': this.hiding.bind(this)
		})
	},

	showing: function() {
		$clear(this.delay);
	},

	hiding: function() {
		$clear(this.delay)
		this.delay = this.hide.delay(500, this)
	},

	hide: function() {
		this.box.fade(Browser.Engine.trident ? 'hide' : 'out');
	},
	
	show: function(el) {
		this.box.fade(Browser.Engine.trident ? 'show' : 'in');
		var styles = el.computePosition(el.getPositionRelativeTo($('wrapper')))
		styles.top += el.scrollHeight
		styles.left -= 17 - this.current.getStyle('padding-left').toInt();
		this.box.setStyles(styles);
	},
	
	prepare: function() {
		var that = this;
		this.box.getElements('li').each(function(li) {
			var show = true;
			for (var prop in $merge(that.def, that.other)) {
				var required = li.getProperty(prop);
				if (required != 0 && !required) continue;
				if (that.getValue(prop) != required) show = false;
			}
			li.setStyle('display', show ? 'block' : 'none');
		});
		
		this.rules.each(this.replace, this);
	},
	
	replace: function(args) {
		var rule = args[0];
		var prop = args[1] || 'html';
		
		this.box.getElements(rule).each(function(el) {
			var retrieved = el.retrieve(prop); //restoring original template
			if (!retrieved) {
				retrieved = el.getProperty(prop);
				el.store(prop, retrieved)
			}
			var processed = this.process(retrieved)
			if (prop == "href") processed = processed.replace(/http.*http/, 'http') //nasty IE
			el.setProperty(prop, processed)
		}, this); 
	},
	
	process: function(str) {
		var that = this;
		return str.replace(/(?:\{|%7B)(.*?)(?:\}|%7D)/gi, function(m, prop) {
			return that.getValue(prop)
		})
	},
	
	getKey: function() {
		return this.current.getProperty(this.key) || this.def[this.key]
	},
	
	getValue: function(prop) {
		m = prop.match(this.user_prop_regex)
		if (m) {
			if ($user) {
				if (m[1] == "another") {
					return $user.login != this.getValue('login') ? "1" : "0"
				} else {
					return $user[m[1]]
				}
			} else {
				return "0"
			}
		} else {
			var k = this.getKey();
			return this.cache[k] ? this.cache[k][prop] : (this.current.getProperty(prop) || this.def[prop]);
		}
	},
	
	getAjax: function() {
		if (!this.ajax) this.ajax = new Request.JSON({onSuccess: this.setCache.bind(this)});
		this.ajax.cancel();
		return this.ajax;
	},
	
	fetch: function() {
		if (!this.cache[this.getKey()]) this.getAjax().get(this.process(this.url));
	},
	
	setCache: function(json) {
		if (json) {
			json.remote = 1
			this.cache[json[this.key]] = json
			if (json[this.key] == this.getKey()) {
				this.prepare()
			} else {
				this.fetch();
			}
		}
	}
	
});

Toolbox.cache = {};

UserToolbox = new Class ({ 
  Extends: Toolbox,
	initialize: function(els, box) { 
		Toolbox.cache.user = {};
		this.key = "login"
		this.cache = Toolbox.cache.user;
		this.url = "/users/{login}.json";
		this.def = {place: "?", igp: "?", remote: "0", friend: "0", friendship: "0"};
		this.rules = [
			['strong'],
			['span.exp'],
			['a', 'href']
		]
		this.parent(els, box);
	}
});


BlogToolbox = new Class ({ 
  Extends: Toolbox,
	initialize: function(els, box) {
		Toolbox.cache.blog = {};
		this.key = "slug"
		this.url = "/blogs/{slug}.json?top={top}";
		this.cache = Toolbox.cache.blog;
		this.def = {place: "?", subscribers: "?", remote: "0", igp: "?", subscribed: "0"};
		this.rules = [
			['strong'],
			['span.exp'],
			['a', 'href']
		]
		this.parent(els, box);
	}
});

Registration = {
	initialize: function(el, invintation) {
		this.el = $(el);
		if (!this.el) return;
		this.invintation = $(invintation);
		
		this.links = el.getElements('a.show-more');
		this.assignEvents();
	},
	
	assignEvents: function() {
		this.links.addEvent('click', this.click.bind(this));
	},
	
	click: function(e) {
		e.stop();
		var el = $(e.target)
		var block = this.block(el)
		
		block.setStyle('display', 'block');
		el.getParent().setStyle('display', 'none');
		
		$scroller.toElement(block);
		block.fade(0, 1);


		if (this.check()) this.invintation.setStyle('display', 'none')
	},
	
	extract: function(el) {
		return el.id.match(/-(.*?)$/)[1];
	},
	
	block: function(el) {
		return $('block-' + this.extract(el));
	},
	
	check: function() {
		return this.links.filter(function(el) { 
			return el.getParent().getStyle('display') == 'block'
		}).length == 0
	}
}

$scroller = new Fx.Scroll(window, {
	wait: false,
	duration: 500,
	offset: {'y': -150}
});



GameChooser = new Class({
	
	initialize: function(el) {
		this.el = $(el);
		if (!this.el) return;
		this.closeHook = this.el.getElement('.close-hook');
		this.openHook  = this.el.getElement('.open-hook');
		this.hidden = this.el.getElement('.hidden-input');
		this.assignEvents();
	},
	
	assignEvents: function() {
		if ($$('.open-hook') != '') {
			this.openHook.addEvent('click', this.open.bind(this));
			if (this.closeHook) this.closeHook.addEvent('click', this.close.bind(this))
		}
	},
	
	open: function(e) {
		e.stop();
		this.hidden.set('value', '');
		this.el.addClass('game-chooser-clicked');
		this.el.removeClass('game-chooser');
	},
	
	close: function(e) {
		e.stop();
		this.hidden.set('checked', 'checked')
		this.el.removeClass('game-chooser-clicked');
		this.el.addClass('game-chooser');
	}
	
})



Request.prototype.success = function(text, xml) {
	IGC.response.call(this, text, xml)
	this.onSuccess(text, xml);
}



Request.implement({
	getCustomHeader: function(name) {
		return this.xhr.getResponseHeader('X_' + name)
	},
	
 	isSuccess: function(){
		this.status = (this.getCustomHeader('Status') || this.status).toInt();
		return ((this.status >= 200) && (this.status < 300));
	}
});

Rating = new Class({
	
	initialize: function (el, url) {
		this.el = $(el);
		if (!this.el) return;
		this.indicator = this.getIndicator();
		this.assignEvents();
	},
	
	getIndicator: function() {
		return new Indicator(this.el.getParent(), 'after');
	},
	
	assignEvents: function() {
		this.el.addEvent('click', this.send.bind(this));
	},
	
	request: function() {
		this.indicator.show();
		this.notify();
		this.progress = true;
	},
	
	failure: function(html, code) {
		this.indicator.hide();
		this.notify(html && code != 404 ? html : 'Произошла ошибка :(')
		this.progress = false;
	},
	
	error: function() {
		if (!this.err) this.err = new Element('div', {'class': 'error'}).inject(this.el, 'before');
	},
	
	notify: function(msg) {
		this.error();
		if (msg) { 
			this.err.set('html', msg);
			this.err.setStyle('display', 'block');
		} else {
			this.err.setStyle('display', 'none');
		}
		return this.err;
	},
	
	success: function() {
		this.indicator.hide();
		this.el.set('html', 'Уже дал');
		this.el.addClass('not-link');
		//alert(this.ajax.xhr);
	},
	
	send: function(e) {
		if (e) e.stop();
		if (this.progress) return;
		if (!this.ajax) this.ajax = new Request({
			url: this.el.get('href'),
			onSuccess: this.success.bind(this),
			onFailure: function() {this.failure(this.ajax.xhr.responseText, this.ajax.status)}.bind(this),
			onRequest: this.request.bind(this)
		});
		this.ajax.PUT();
	}
	
});

CommentRating = new Class({
	Extends: Rating,
	request: function() {
		this.el.addClass('igp_grey');
		this.el.removeClass('igp_black');
		this.el.removeClass('error');
		this.el.set('html', 'Передаём');
		this.parent();
	},
	
	
	failure: function(html, code) {
		this.el.removeClass('igp_grey');
		this.el.addClass('igp_black');
		this.el.set('html', 'Дать');
		this.parent(html, code);
	},
	
	getBadge: function() {
		if (!this.badge) this.badge = this.el.getParent().getParent().getElement('.igp_badge');
		if (!this.counter) this.counter = this.badge.getLast();
	},
	
	success: function(value) {
		this.parent();
		this.getBadge();
		this.badge.removeClass('hidden');
		this.counter.set('html', value)
	}
});

Garmoshka = new Class({ //mini-accordion
	initialize: function(links) {
		this.links = links;
		this.assignEvents();
	},
	
	assignEvents: function() {
		this.links.addEvent('click', this.click.bind(this));
	},
	
	click: function(e) {
		e.stop();
		var block = $(e.target).getNext();
		block.get('tween').start('height', block.offsetHeight < 5 ? block.scrollHeight : 0)
	}
})

IGPHelp = new Class({
	initialize: function(el) {
		this.el = $(el)
		if (!this.el) return
		new Garmoshka(this.el.getElements('a.show-next'))
	}
});

ManagableSearch = {
	initialize: function(el) {
		this.el = $(el);
		if (!this.el) return;
		this.input = el.getElement('input[type=text]');
		this.names = el.getElements('span.ajaxed');
		this.assignEvents();
	},
	
	assignEvents: function() {
		this.names.addEvent('click', this.click.bind(this))
	},
	
	click: function(e) {
		e.stop();
		this.input.set('value', $(e.target).get('login'));
	}
}

Managable = new Class({
	initialize: function(el) {
		this.el = $(el)
		if (!this.el) return;
		this.items = this.el.getElements('li.item');
		
		
		this.links = this.el.getElements('a.pseudo-user');
		this.current = null;
		this.previous = null;
		this.assignEvents();
		
		if ($hash.query.length > 5) {
			var hilited = $($hash.query)
			if (hilited) {
				this.items.each(function(e) {
					if (e == hilited) this.open(e)
				}, this);
			}
		}
	},
	
	assignEvents: function() {
		this.items.addEvent('click', this.click.bind(this))
	},
	
	open: function(el, e) {
		if (!el.hasClass('item') || (e && el.get('tag') != 'a')) el = el.getParent('li.item');
		if (this.current == el ) return;
		if (this.current) this.current.removeClass('clicked');
		if (this.previous) this.previous.removeClass('before-clicked');
		this.current = el.addClass('clicked');
		if (e) e.stop()
		if (el.getPrevious()) this.previous = el.getPrevious().addClass('before-clicked');
	},
	
	click: function(e) {
		var el = $(e.target);
		this.open(el, e)
	}
});

PostRating = new Class({
	Extends: Rating,
	
	initialize: function(wrapper, el) {
		if (!wrapper) return;
		this.wrapper = wrapper;
		
		
		this.counter = this.wrapper.getElement('strong');
		
		this.parent(el);
		IGC.addEvent('onRecievePostKarma', this.set.bind(this));
	},
	
	set: function(value) {
		this.counter.set('html', value.length < 6 ? value : "?");
	},
	
	error: function() {
		if (!this.err) this.err = new Element('div', {'class': 'error'}).inject(this.wrapper, 'after');
	},
	
	getIndicator: function() {
		return new Indicator(this.el.getParent().getParent().getParent().getElement('div.right'), 'after');
	},
	
	success: function(value) {
		this.set(value);
		this.parent();
	}
})

Comments = new Class({
	initialize: function(el, handler, current, refresher, counter) {
		this.el = el;
		this.handler = handler;
		this.def = current;
//		this.refresher = refresher;
		this.counter = counter;
		if (!this.el || !this.handler) return;
		
		this.current = current;
		this.root = current;
		
		this.form = handler.getElement('form');
		this.form.set('value', '')
		this.default_action = this.form.get('action')
		
		this.label = this.handler.getElement('.label');
		this.parent = this.handler.getElement('input[type=hidden][name*=parent_id]');
		this.area = this.handler.getElement('textarea');
		this.setWidth()
		this.syntax = this.form.retrieve('syntax');
		this.form.store('comments', this);
		
		this.indicator = new Indicator(this.handler.getElement('span.submit'), 'after');
		this.indicator2 = new Indicator(refresher);
		
		this.saved = [null, this.parent.get('value')];
		
		var send = this.form.get('send');
		this.send = send;
		send.setOptions({
			onFailure: function() {this.failure(send.xhr.responseText, send.status)}.bind(this),
			onSuccess: this.success.bind(this),
			onRequest: this.notify.bind(this)
		});
		
		this.fetch = new Request({
//			url: this.refresher.getProperty('href'),
			onSuccess: function(html) { this.success(html, true); }.bind(this),
			onRequest: function() { this.notify(true) }.bind(this),
			onFailure: function() { this.clean(true) }.bind(this)
		});
		
		this.assignEvents(1);
	},
	
	setWidth: function(p) {
		var w = (this.handler.offsetWidth > 610 ? 610 : this.handler.offsetWidth)  - 2;
		if (Browser.Engine.trident) w -= 4;
		this.area.setStyle('width', w - 36)
	},
	
	assignEvents: function(first) {
//	  this.refresher.addEvent('click', this.refresh.bind(this));
	  this.form.addEvent('submit', this.submit.bind(this));
	  this.reassignEvents(true);
	},
	
	reassignEvents: function(first) {
		var els = this.el.getElements("a.respond");
		if (first) els.push(this.current);
		els.each(function(el) {
			el.addEvent('click', function(e) {
				e.stop();
				this.respond(e.target);
			}.bind(this));
			var comment = el.getParent().getParent();
			if (comment.get('tag') == 'li') {
				if (comment.hasClass('just-added')) $scroller.toElement(comment);
				new CommentRating('rate-' + comment.get('id'));
			}
		}, this);
		
		els = this.el.getElements("a.edit");
		els.each(function(el) {
			el.addEvent('click', function(e) {
				e.stop();
				this.edit(e.target);
			}.bind(this));
		}, this);
		
		$each($$('#comments div.itself'), function(item) {
			item.addEvent('mouseover', function() {
				this.getParent().addClass('hovered');
			});
		
			item.addEvent('mouseout', function() {
				this.getParent().removeClass('hovered');
			});
		});
	},
	
	refresh: function(e) {
		e.stop();
		this.fetch.GET()
	},
	
	fix: function() {
		this.handler.setStyle('height', this.handler.scrollHeight);
	},
	
	invalid: function(html) {
		if (!this.validations) this.validations = new Element('div', {'class': "validation-errors round-corners"}).injectTop(this.handler);
		this.validations.setStyle('display', 'block');
		this.validations.set('html', '<div><div><div>' + html + '</div></div></div>');
		this.fix();
	},
	
	valid: function(nofix) {
		if (!this.validations) return;
		this.validations.setStyle('display', 'none')
		if (!nofix) this.fix();
	},
	
	notify: function(refresh) {
		this[refresh ? "indicator2" : "indicator"].show();
		this.area.set('disabled', 'disabled')
	},
	
	clean: function(refresh) {
		this.area.set('disabled', '')
		this[refresh ? "indicator2" : "indicator"].hide();
	},
	
	failure: function(html, code) {
		this.clean();
		switch(code) {
			case 400: 
				this.invalid(html);
				break;
			case 403:
				this.invalid('Похоже, ваша сессия истекла :(, перелогиньтесь?');
				//Андрей, кроме :forbidden, выведи еще предложение залогиниться в хтмле.
				break;
			default:
				this.invalid('<strong>Ошибка ' + code + '</strong>. Комментарий не отправляется :(. <br /> Сохраните куда-нибудь текст комментария, если не хотите, чтобы он был утерян или попробуйте еще раз.');		
				//this.invalid(html);		
		}
	},
	
	success: function(html, refresh) {
		this.valid();
		this.indicator.hide();
		this.clean(refresh);
		this.area.set({html: '', value: ''});
		this.respond(this.root, true); //спасаем форму от уничтожительного влияния гарбаж коллектора
		this.el.set('html', html);
		var count = this.el.getElements('li.comment').length;
		if (count > 0) this.counter.set('html', count);
		IGC.fireEvent('reload', this.el);
		this.reassignEvents();
		this.area.set('html', '');
	},
	
	submit: function(e) {
		e.stop()
		this.send.send({url: this.form.get('action'), data: this.form.toQueryString()});
	},
	
	edit: function(el) {
	  if (this.current) this.current.setStyle('display', 'inline');
		this.respond(el.getParent().getParent().getElement('a.respond'), true)
		this.label.set('html', '<strong>Редактировать</strong> комментарий. Спешите, времени мало!');
		this.form.set('action', el.get('href'));
		this.send.options.method = "put"
		
		this.area.set('disabled', 'disabled');
		this.area.set('value', 'Загрузка комментария...');
		new Request.JSON({
			onSuccess: function(object) {
				this.area.set('disabled', '')
				this.clear = true
				this.area.set('value', object.body_source)
			}.bind(this)
		}).get(el.get('href') + '.json')
	},
	
	respond: function(el, instantly) {
		if (this.process || this.current == el) return;
		old = this.current;
		this.current = $(el);
		
		this.parent.set('value', (el.getParent().getParent().get('id').match(/comment-(\d*)/) || this.saved)[1]);
		
		if (instantly) return this.move(el);
		
		if (this.clear) {
			this.area.set('value', '')
			this.clear = false
		}
		this.area.set('disabled', '')
		this.process = true;
		this.send.options.method = "post"
		this.handler.setStyle('overflow','hidden');
		this.handler.get('tween').start('height', this.handler.scrollHeight, 18);
		(function() {
			if (old) old.setStyle('display', '');
			this.move(el);
			this.valid(true);
			this.handler.get('tween').start('height', 18, this.handler.scrollHeight);
			$scroller.toElement(this.handler);
			(function() {
				this.process = false
			}).delay(500, this);
			
			(function() {				
				this.handler.setStyle('height','auto');
				this.handler.setStyle('overflow','visible');
				this.area.focus();
			}).delay(600, this);
		}).delay(500, this);
		
		
		//this.handler.setStyle('height', 'auto');
	},
	
	move: function(el) {
		//this.current.setStyle('display', 'none');
		this.label.set('html', this.current == this.root ? "Написать комментарий" : "Ответить на комментарий");
		this.handler.inject(el, 'after');
		this.form.set('action', this.default_action);
		this.area.setStyle('display', 'none')
		this.setWidth()
		this.area.setStyle('display', 'block')
		this.syntax.close();
	}
});


Contributors = {
	initialize: function(el, toggler) {
		this.el = el;
		if (!this.el) return;
		this.open = this.el.hasClass('visible');
		this.toggler = toggler;
		this.toggler.set('or2', this.toggler.get('html'));
		this.adder = this.el.getElement('label .ajaxed');
		this.roles = this.el.getElements('div.role');
		this.removes = this.el.getElements('a.remove');
		this.assignEvents()
	},
	
	assignEvents: function() {
		this.adder.addEvent('click', this.add.bind(this));
		this.removes.addEvent('click', this.remove.bind(this));
		this.toggler.addEvent('click', this.toggle.bind(this));
	},
	
	add: function(e) {
		if (e) e.stop();
		var role = this.hidden();
		if (role.length == 0) return;
		if (role.length == 1) this.adder.setStyle('display', 'none')
		role = role[0];
		role.inject(this.el); //moving to bottom
		
		role.addClass('visible');
		//this.getInput(role).focus();
	},
	
	toggle: function(e) {
		if (e) e.stop();
		
		if (this.open) {
			this.open = false;
			this.el.removeClass('visible');
			for (var i = 0; i < 5; i++) this.remove(this.roles[i], true);
			this.toggler.set('html', this.toggler.get('or2'));
			this.toggler.removeClass('ajaxed_error');
		} else {
			this.el.addClass('visible');
			this.open = true;
			this.add();
			this.toggler.set('html', this.toggler.get('or'));
			this.toggler.addClass('ajaxed_error');
		}
	},
	
	remove: function(e, noremove) {
		if ($type(e) == "element") {
			var role = e;
		} else {
			e.stop();
			var role = $(e.target).getParent();
		}
		var input = this.getInput(role);
		input.set('value', '');
		input.retrieve('default').blur();
		if (this.hidden().length == 0) this.adder.setStyle('display', 'inline')
		role.removeClass('visible');
		if (this.hidden().length == 5 && !noremove) this.toggle();
	},
	
	getInput: function(role) {
		return role.getElement('input');
	},
	
	hidden: function() {
		return this.roles.filter(function(el) { return !el.hasClass('visible')});
	}
}


var Autocompleter = {};

Autocompleter.Base = new Class({

	options: {
		minLength: 1,
		markQuery: true,
		width: 'inherit',
		maxChoices: 10,
		injectChoice: null,
		customChoices: null,
		className: 'autocompleter-choices',
		zIndex: 42,
		delay: 400,
		observerOptions: {},
		fxOptions: {},
		onOver: $empty,
		onSelect: $empty,
		onSelection: $empty,
		onShow: $empty,
		onHide: $empty,
		onBlur: $empty,
		onFocus: $empty,

		autoSubmit: false,
		overflow: false,
		overflowMargin: 25,
		selectFirst: false,
		filter: null,
		filterCase: false,
		filterSubset: false,
		forceSelect: false,
		selectMode: true,
		choicesMatch: null,

		multiple: false,
		separator: ', ',
		separatorSplit: /\s*[,;]\s*/,
		autoTrim: true,
		allowDupes: false,

		cache: true,
		relative: false
	},

	initialize: function(element, options) {
		this.element = $(element);
		this.setOptions(options);
		this.build();
		this.observer = new Observer(this.element, this.prefetch.bind(this), $merge({
			'delay': this.options.delay
		}, this.options.observerOptions));
		this.queryValue = null;
		if (this.options.filter) this.filter = this.options.filter.bind(this);
		var mode = this.options.selectMode;
		this.typeAhead = (mode == 'type-ahead');
		this.selectMode = (mode === true) ? 'selection' : mode;
		this.cached = [];
	},

	/**
	 * build - Initialize DOM
	 *
	 * Builds the html structure for choices and appends the events to the element.
	 * Override this function to modify the html generation.
	 */
	build: function() {
		if ($(this.options.customChoices)) {
			this.choices = this.options.customChoices;
		} else {
			this.choices = new Element('ul', {
				'class': this.options.className,
				'styles': {
					'zIndex': this.options.zIndex
				}
			}).inject(document.body);
			this.relative = false;
			if (this.options.relative) {
				this.choices.inject(this.element, 'after');
				this.relative = this.element.getOffsetParent();
			}
			this.fix = new OverlayFix(this.choices);
		}
		if (!this.options.separator.test(this.options.separatorSplit)) {
			this.options.separatorSplit = this.options.separator;
		}
		this.fx = (!this.options.fxOptions) ? null : new Fx.Tween(this.choices, $merge({
			'link': 'cancel',
			'duration': 200
		}, this.options.fxOptions)).set('opacity', 0);
		this.element.setProperty('autocomplete', 'off')
			.addEvent((Browser.Engine.trident || Browser.Engine.webkit) ? 'keydown' : 'keypress', this.onCommand.bind(this))
			.addEvent('click', this.onCommand.bind(this, [false]))
			.addEvent('focus', this.toggleFocus.create({bind: this, arguments: true, delay: 100}))
			.addEvent('blur', this.toggleFocus.create({bind: this, arguments: false, delay: 100}));
	},

	destroy: function() {
		if (this.fix) this.fix.destroy();
		this.choices = this.selected = this.choices.destroy();
	},

	toggleFocus: function(state) {
		this.focussed = state;
		if (!state) this.hideChoices(true);
		this.fireEvent((state) ? 'onFocus' : 'onBlur', [this.element]);
	},

	onCommand: function(e) {
		if (!e && this.focussed) return this.prefetch();
		if (e && e.key && !e.shift) {
			switch (e.key) {
				case 'enter':
					if (this.element.value != this.opted) return true;
					if (this.selected && this.visible) {
						this.choiceSelect(this.selected);
						return !!(this.options.autoSubmit);
					}
					break;
				case 'up': case 'down':
					if (!this.prefetch() && this.queryValue !== null) {
						var up = (e.key == 'up');
						this.choiceOver((this.selected || this.choices)[
							(this.selected) ? ((up) ? 'getPrevious' : 'getNext') : ((up) ? 'getLast' : 'getFirst')
						](this.options.choicesMatch), true);
					}
					return false;
				case 'esc': case 'tab':
					this.hideChoices(true);
					break;
			}
		}
		return true;
	},

	setSelection: function(finish) {
		var input = this.selected.inputValue, value = input;
		var start = this.queryValue.length, end = input.length;
		if (input.substr(0, start).toLowerCase() != this.queryValue.toLowerCase()) start = 0;
		if (this.options.multiple) {
			var split = this.options.separatorSplit;
			value = this.element.value;
			start += this.queryIndex;
			end += this.queryIndex;
			var old = value.substr(this.queryIndex).split(split, 1)[0];
			value = value.substr(0, this.queryIndex) + input + value.substr(this.queryIndex + old.length);
			if (finish) {
				var space = /[^\s,]+/;
				var tokens = value.split(this.options.separatorSplit).filter(space.test, space);
				if (!this.options.allowDupes) tokens = [].merge(tokens);
				var sep = this.options.separator;
				value = tokens.join(sep) + sep;
				end = value.length;
			}
		}
		this.observer.setValue(value);
		this.opted = value;
		if (finish || this.selectMode == 'pick') start = end;
		this.element.selectRange(start, end);
		this.fireEvent('onSelection', [this.element, this.selected, value, input]);
	},

	showChoices: function() {
		var match = this.options.choicesMatch, first = this.choices.getFirst(match);
		this.selected = this.selectedValue = null;
		if (this.fix) {
			var pos = this.element.getCoordinates(this.relative), width = this.options.width || 'auto';
			this.choices.setStyles({
				'left': pos.left,
				'top': pos.bottom,
				'width': (width === true || width == 'inherit') ? pos.width : width
			});
		}
		if (!first) return;
		if (!this.visible) {
			this.visible = true;
			this.choices.setStyle('display', '');
			if (this.fx) this.fx.start('opacity', 1);
			this.fireEvent('onShow', [this.element, this.choices]);
		}
		if (this.options.selectFirst || this.typeAhead || first.inputValue == this.queryValue) this.choiceOver(first, this.typeAhead);
		var items = this.choices.getChildren(match), max = this.options.maxChoices;
		var styles = {'overflowY': 'hidden', 'height': ''};
		this.overflown = false;
		if (items.length > max) {
			var item = items[max - 1];
			styles.overflowY = 'scroll';
			styles.height = item.getCoordinates(this.choices).bottom;
			this.overflown = true;
		};
		this.choices.setStyles(styles);
		this.fix.show();
	},

	hideChoices: function(clear) {
		if (clear) {
			var value = this.element.value;
			if (this.options.forceSelect) value = this.opted;
			if (this.options.autoTrim) {
				value = value.split(this.options.separatorSplit).filter($arguments(0)).join(this.options.separator);
			}
			this.observer.setValue(value);
		}
		if (!this.visible) return;
		this.visible = false;
		this.observer.clear();
		var hide = function(){
			this.choices.setStyle('display', 'none');
			this.fix.hide();
		}.bind(this);
		if (this.fx) this.fx.start('opacity', 0).chain(hide);
		else hide();
		this.fireEvent('onHide', [this.element, this.choices]);
	},

	prefetch: function() {
		var value = this.element.value, query = value;
		if (this.options.multiple) {
			var split = this.options.separatorSplit;
			var values = value.split(split);
			var index = this.element.getCaretPosition();
			var toIndex = value.substr(0, index).split(split);
			var last = toIndex.length - 1;
			index -= toIndex[last].length;
			query = values[last];
		}
		if (query.length < this.options.minLength) {
			this.hideChoices();
		} else {
			if (query === this.queryValue || (this.visible && query == this.selectedValue)) {
				if (this.visible) return false;
				this.showChoices();
			} else {
				this.queryValue = query;
				this.queryIndex = index;
				if (!this.fetchCached()) this.query();
			}
		}
		return true;
	},

	fetchCached: function() {
		return false;
		if (!this.options.cache
			|| !this.cached
			|| !this.cached.length
			|| this.cached.length >= this.options.maxChoices
			|| this.queryValue) return false;
		this.update(this.filter(this.cached));
		return true;
	},

	update: function(tokens) {
		this.choices.empty();
		this.cached = tokens;
		if (!tokens || !tokens.length) {
			this.hideChoices();
		} else {
			if (this.options.maxChoices < tokens.length && !this.options.overflow) tokens.length = this.options.maxChoices;
			tokens.each(this.options.injectChoice || function(token){
				var choice = new Element('li', {'html': this.markQueryValue(token)});
				choice.inputValue = token;
				this.addChoiceEvents(choice).inject(this.choices);
			}, this);
			this.showChoices();
		}
	},

	choiceOver: function(choice, selection) {
		if (!choice || choice == this.selected) return;
		if (this.selected) this.selected.removeClass('autocompleter-selected');
		this.selected = choice.addClass('autocompleter-selected');
		this.fireEvent('onSelect', [this.element, this.selected, selection]);
		if (!selection) return;
		this.selectedValue = this.selected.inputValue;
		if (this.overflown) {
			var coords = this.selected.getCoordinates(this.choices), margin = this.options.overflowMargin,
				top = this.choices.scrollTop, height = this.choices.offsetHeight, bottom = top + height;
			if (coords.top - margin < top && top) this.choices.scrollTop = Math.max(coords.top - margin, 0);
			else if (coords.bottom + margin > bottom) this.choices.scrollTop = Math.min(coords.bottom - height + margin, bottom);
		}
		if (this.selectMode) this.setSelection();
	},

	choiceSelect: function(choice) {
		if (choice) this.choiceOver(choice);
		this.setSelection(true);
		this.queryValue = false;
		this.hideChoices();
	},

	filter: function(tokens) {
		var regex = new RegExp(((this.options.filterSubset) ? '' : '^') + this.queryValue.escapeRegExp(), (this.options.filterCase) ? '' : 'i');
		return (tokens || this.tokens).filter(regex.test, regex);
	},

	markQueryValue: function(str) {
		return (!this.options.markQuery || !this.queryValue) ? str
			: str.replace(new RegExp('(' + ((this.options.filterSubset) ? '' : '^') + this.queryValue.escapeRegExp() + ')', (this.options.filterCase) ? '' : 'i'), '<span class="autocompleter-queried">$1</span>');
	},
	addChoiceEvents: function(el) {
		return el.addEvents({
			'mouseover': this.choiceOver.bind(this, [el]),
			'click': this.choiceSelect.bind(this, [el])
		});
	}
});

Autocompleter.Base.implement(new Events);
Autocompleter.Base.implement(new Options);

Autocompleter.Local = new Class({

	Extends: Autocompleter.Base,

	options: {
		minLength: 0,
		delay: 200
	},

	initialize: function(element, tokens, options) {
		this.parent(element, options);
		this.tokens = tokens;
	},

	query: function() {
		this.update(this.filter());
	}

});

Autocompleter.Ajax = {};

Autocompleter.Ajax.Base = new Class({

	Extends: Autocompleter.Base,

	options: {
		postVar: 'value',
		postData: {},
		ajaxOptions: {},
		onRequest: $empty,
		onComplete: $empty
	},

	initialize: function(element, options) {
		this.parent(element, options);
		var indicator = $(this.options.indicator);
		if (indicator) {
			this.addEvents({
				'onRequest': indicator.show.bind(indicator),
				'onComplete': indicator.hide.bind(indicator)
			}, true);
		}
	},

	query: function(){
		var data = $unlink(this.options.postData);
		data[this.options.postVar] = this.queryValue;
		this.fireEvent('onRequest', [this.element, this.request, data, this.queryValue]);
		this.request.send({'data': data});
	},

	/**
	 * queryResponse - abstract
	 *
	 * Inherated classes have to extend this function and use this.parent(resp)
	 *
	 * @param		{String} Response
	 */
	queryResponse: function() {
		this.fireEvent('onComplete', [this.element, this.request, this.response]);
	}

});

Autocompleter.Ajax.Json = new Class({

	Extends: Autocompleter.Ajax.Base,

	initialize: function(el, url, options) {
		this.parent(el, options);
		this.request = new Request.JSON($merge({
			'url': url,
			'link': 'cancel'
		}, this.options.ajaxOptions)).addEvent('onComplete', this.queryResponse.bind(this));
	},

	queryResponse: function(response) {
		this.parent();
		this.update(response);
	}

});

Autocompleter.Ajax.Xhtml = new Class({

	Extends: Autocompleter.Ajax.Base,

	initialize: function(el, url, options) {
		this.parent(el, options);
		this.request = new Request.HTML($merge({
			'url': url,
			'link': 'cancel',
			'update': this.choices
		}, this.options.ajaxOptions)).addEvent('onComplete', this.queryResponse.bind(this));
	},

	queryResponse: function(tree, elements) {
		this.parent();
		if (!elements || !elements.length) {
			this.hideChoices();
		} else {
			this.choices.getChildren(this.options.choicesMatch).each(this.options.injectChoice || function(choice) {
				var value = choice.innerHTML;
				choice.inputValue = value;
				this.addChoiceEvents(choice.set('html', this.markQueryValue(value)));
			}, this);
			this.showChoices();
		}

	}

});


var OverlayFix = new Class({

	initialize: function(el) {
		if (Browser.Engine.trident) {
			this.element = $(el);
			this.relative = this.element.getOffsetParent();
			this.fix = new Element('iframe', {
				'frameborder': '0',
				'scrolling': 'no',
				'src': 'javascript:false;',
				'styles': {
					'position': 'absolute',
					'border': 'none',
					'display': 'none',
					'filter': 'progid:DXImageTransform.Microsoft.Alpha(opacity=0)'
				}
			}).inject(this.element, 'after');
		}
	},

	show: function() {
		if (this.fix) {
			var coords = this.element.getCoordinates(this.relative);
			delete coords.right;
			delete coords.bottom;
			this.fix.setStyles($extend(coords, {
				'display': '',
				'zIndex': (this.element.getStyle('zIndex') || 1) - 1
			}));
		}
		return this;
	},

	hide: function() {
		if (this.fix) this.fix.setStyle('display', 'none');
		return this;
	},

	destroy: function() {
		this.fix = this.fix.destroy();
	}

});

/**
 * @todo Clean that up or check if they exist already
 */
Element.implement({

	getOffsetParent: function() {
		var body = this.getDocument().body;
		if (this == body) return null;
		if (!Browser.Engine.trident) return $(this.offsetParent);
		var el = this;
		while ((el = el.parentNode)){
			if (el == body || Element.getComputedStyle(el, 'position') != 'static') return $(el);
		}
		return null;
	},

	getCaretPosition: function() {
		if (!Browser.Engine.trident) return this.selectionStart;
		this.focus();
		var work = document.selection.createRange();
		var all = this.createTextRange();
		work.setEndPoint('StartToStart', all);
		return work.text.length;
	},

	selectRange: function(start, end) {
		if (Browser.Engine.trident) {
			var range = this.createTextRange();
			range.collapse(true);
			range.moveEnd('character', end);
			range.moveStart('character', start);
			range.select();
		} else {
			this.focus();
			this.setSelectionRange(start, end);
		}
		return this;
	}

});

var Default = new Class({
	initialize: function(el) {
		this.el = $(el)
		if (!this.el) return;
		Default.remember(this)
		this.assignEvents();
		this.blur();
		return this;
	}, 
	
	assignEvents: function(el) {
		(el || this.el).addEvents({
			'blur':  this.blur.bind(this),
			'focus': this.focus.bind(this)
		})
	},
	
	focus: function() {
		if (this.el.hasClass('default')) {
			this.el.set('value', '');
			this.el.removeClass('default');
			return true
		}
	},
	
	blur: function() {
		if (this.el.get('value').match(/^\s*$/)) {
			this.el.set('value', this.el.get('default'));
			this.el.addClass('default')
			return true
		}
	}
});

Default.$index = [],
  
Default.remember = function(instance) {
  Default.$index.push(instance)
},
  
Default.empty = function() {
  Default.$index.each(function(instance) {
    if (instance.el.get('value') == instance.el.get('default')) instance.el.set('value', '')
  })
}


window.addListener('beforeunload', Default.empty);



Default.Password = new Class({
  Extends: Default,
  initialize: function(el) {
		if ($(!el)) return;
		this.input = new Element('input', {"class": el.className}).injectAfter(el).setStyle('display', 'none')
		this.parent(el);
		this.assignEvents(this.input)
		this.input.removeEvents('blur')
  },
  
  focus: function() {
    if (this.parent()) {
      this.el.set('value', this.el.get('value')).setStyle('display', 'block')
      this.el.focus()
      this.input.setStyle('display', 'none')
    }
  },
  
  blur: function() {
    if (this.parent()) {
      this.el.setStyle('display', 'none')
      this.input.set('value', this.el.get('value')).setStyle('display', 'block')
    }
  }
})


var Observer = new Class({

	Implements: [Options, Events],

	options: {
		periodical: false,
		delay: 1000
	},

	initialize: function(el, onFired, options){
		this.setOptions(options);
		this.addEvent('onFired', onFired);
		this.element = $(el) || $$(el);
		this.value = this.element.get('value');
		if (this.options.periodical) this.timer = this.changed.periodical(this.options.periodical, this);
		else this.element.addEvent('keyup', this.changed.bind(this));
	},

	changed: function() {
		var value = this.element.get('value');
		if ($equals(this.value, value)) return;
		this.clear();
		this.value = value;
		this.timeout = this.onFired.delay(this.options.delay, this);
	},

	setValue: function(value) {
		this.value = value;
		this.element.set('value', value);
		return this.clear();
	},

	onFired: function() {
		this.fireEvent('onFired', [this.value, this.element]);
	},

	clear: function() {
		$clear(this.timeout || null);
		return this;
	}

});

var Video = new Class({
	initialize: function(el) {
		this.el = $(el);
		if (!this.el) return;
	},
	
	inject: function(src) {
		new Swiff(src, $extend({container: this.el}, this.options));
	}
});

var YouTube = Video.extend({
	initialize: function(el) {
		this.parent(el);
		this.src = 'http://www.youtube.com/v/' + el.id.match(/youtube-(.*?)$/)[1]; + '&#38;hl=en'
		this.setOptions();
		this.inject(this.src);
	},
	
	setOptions: function(el) {
		this.options = {
			movie: this.src,
			width:  425, 
			height: 344
		}
	}
  
})

SyntaxHelp = {
	initialize: function(el) {
		this.el = el;
		if (!this.el) return;
		this.toggler = el.getElement('a.ajaxed');
		this.more = el.getElement('div.advanced');
		this.assignEvents();
		this.form = this.el.getParent().getParent().getParent();
		this.form.store('syntax', this)
	},
	
	assignEvents: function() {
		this.toggler.addEvent('click', this.open.bind(this))
	},
	
	get: function() {
		return this.form.retrieve('comments');
	},
	
	open: function(e) {
		if (e) e.stop();
		this.more.setStyle('display', 'block');
		this.toggler.getParent().setStyle('display', 'none');
		if (this.get()) this.get().fix();
	},
	
	close: function(e) {
		if (e) e.stop();
		this.more.setStyle('display', 'none');
		this.toggler.getParent().setStyle('display', 'block');
	}
}

var $equals = function(obj1, obj2) {
	return (obj1 == obj2 || JSON.encode(obj1) == JSON.encode(obj2));
};

var $hash = {query: '', entity: '', id: ''}

Fx.ProgressBar = new Class({

	Extends: Fx,

	options: {
		text: null,
		link: 'cancel'
	},

	initialize: function(element, options) {
		this.element = $(element);
		this.parent(options);
		this.text = $(this.options.text);
		this.set(0);
	},

	start: function(to, total) {
		return this.parent(this.now, (arguments.length == 1) ? to.limit(0, 100) : to / total * 100);
	},

	set: function(to) {
		this.now = to;
		this.element.setStyle('backgroundPosition', (100 - to) + '% 0px');
		if (this.text) this.text.set('text', Math.round(to) + '%');
		return this;
	}

});

var FileUpload = new Class({
	
	initialize: function(el) {
		this.el = $(el)
		if (!this.el) return;
		this.seed = this.generate();
		this.form = this.el.getParent('form');
		this.form.set('action', this.form.getProperty('action') + "?X-Progress-ID=" + this.seed)
		
		this.bar = this.el.getElement('.progress-bar')
		this.fx = new Fx.ProgressBar(this.bar);
		
		this.input = this.el.getElement('input')
		
		this.assignEvents();	
	},
	
	assignEvents: function() {
		this.form.addEvent('submit', this.start.bind(this))
	},
	
	start: function(e) {
		if (this.input.get('value') != "") {
			if (!Browser.Engine.webkit) {
				this.bar.setStyle('display', 'block');
				this.input.setStyle('display', 'none');
				this.track.periodical(1500, this);
			}
		} else {
			alert('Выберите видео для загрузки :-) awrite? OK! OKAY!')
		}
	},
	
	set: function(r) {
		eval('var upload = ' + r);
		if (!upload.size) return;
		this.fx.start(Math.round(upload.received / upload.size  * 100))
	},
	
	track: function() {
		this.getAjax().get('/progress')
	},
	
	generate: function() {
		uuid = "";
		for (i = 0; i < 32; i++) {
			uuid += Math.floor(Math.random() * 16).toString(16);
		}
		return uuid
	},
	
	getAjax: function() {
		if (!this.json) {
			this.json = [
				new Request({onSuccess: this.set.bind(this), 	headers: {'X-Progress-ID': this.seed}	}),
				new Request({onSuccess: this.set.bind(this), 	headers: {'X-Progress-ID': this.seed}	}),
				new Request({onSuccess: this.set.bind(this), 	headers: {'X-Progress-ID': this.seed}	})
			]
		}
		return this.json.getRandom();
	}
	
})

Calculator = new Class({
  initialize: function(el) {
    this.el = $(el)
    if (!this.el) return;
    this.input = this.el.getElement('input');
    this.rates = this.el.getElements('a[rate]');
    this.assignEvents();
  },

  assignEvents: function() {
    this.input.addEvent('keypress', this.keydown.bind(this))
  },

  keydown: function(e) {
    if ((e.key.length > 1) || (e.key.toInt() > -1) || (e.key.toInt() < 10)) this.set.delay(50, this); 
    else return e.stop()
    return true
  },

  set: function() {
    this.rates.each(function(el) {
      value = el.get('rate').toFloat() * this.getValue()
      el.set('href', el.get('href').replace(/[0-9.]+$/, value))
      el.set('html', el.get('html').replace(/^[0-9.]+/, value))
    }, this)
  },

  getValue: function() {
    this.value = this.input.get('value')
    if (this.value == '') {
      return this.value = 0;
    } else {
      this.value = this.value.toFloat()
    }
    if (this.value > 1000) this.cap(1000)
    if (this.value <= 0) this.cap(0)
    return this.value;
  },

  cap: function(at) {
    this.input.set('value', this.value = at)
  }

});


Tickets = new Class({
  initialize: function(el, form) {
    this.el = $(el);
    this.form = $(form)
    if (!this.el) return;
    this.assignEvents();
  },
  
  open: function() {
    form.setStyle('display', 'block')
  },
  
  close: function() {
    form.setStyle('display', 'none')
  },
  
  edit: function(e) {
    this.respond(e, "edit")
  },
  
  create: function(e, methid) {
    this.respond(e, "create")
  },
  
  respond: function(e, method) {
    e.stop()
    var el = $(e.target);
    method = method || "respond"
    var parent = this.current = el.getParent('li')
    var area = this.form.getElement('textarea').set('value', '').fireEvent('blur')
    this.form.injectAfter(!!el.get('just-child') || el.getParent().hasClass('links') ? el.getParent() : el);
    var form = this.form.get('tag') == "form" ? form : form.getElement('textarea');
    this.form.action = el.href
    this.form.getElement('input[type=submit]').set('value', method == "respond" ? "Ответить" : "Сохранить")
    this.form.getElements('label').setStyle('display', method == "respond" ? "none" : "block")
    var select = this.form.getElement('select');
    var input = this.form.getElement('input[type=text]');
    
    
    if (method == "edit") {
      area.set('value', 'Ща, сек...')
  		new Request.JSON({
  			onSuccess: function(object) {
  			  if (this.current != parent) return;
  				area.set('value', object.body_source)
  				select.set('value', object.category_id)
  				input.set('value', object.title)
  			}.bind(this)
  		}).get(parent.get('href') + '.json')
		}
  },
  
  assignEvents: function() {
    this.el.getElements('a.respond').addEvent('click', this.respond.bind(this))
    this.el.getElements('a.edit').addEvent('click', this.edit.bind(this))
    this.el.getElements('a.create').addEvent('click', this.create.bind(this))
    this.el.getElements('div.inactive .collapsed').addEvent('click', function(e) {
      e.stop()
      var el = $(e.target);
      while (el.get('tag') != "li") el = el.getParent();
      if (el.hasClass('collapsed')) {
        el.removeClass('collapsed');
      }
    }.bind(this))
  }
})

Support = {
  initialize: function(el) {
    this.el = el;
    if (!this.el) return;
    $$(this.el.getElements('.list')).each(function(list) {
      new Support.List(list)
    })
  },
  
  add: function(e) {
    e.stop();
    this.add.getNext().setStyle('display', 'block')
  },
  
  cancel: function(e) {
    e.stop();
    this.add.getNext().setStyle('display', 'none')
  }
};

Support.List = new Class({
  initialize: function(el) {
    this.el = $(el);
    if (!this.el) return;
    this.forms = el.getElements('form');
    this.assignEvents();
  },
  
  assignEvents: function() {
    this.el.getElements('a.delete').addEvent('click', this.close.bind(this))
    this.el.getElements('a.plus, a.add').addEvent('click', this.add.bind(this))
    this.el.getElements('a.pencil').addEvent('click', this.edit.bind(this))
  },
  
  close: function(e) {
    e.stop();
    var f = $(e.target).getParent('form');
    f.setStyle('display', 'none')
  },
  
  add: function(e) {
    e.stop();
    this.forms[0].setStyle('display', 'block')
    if (this.forms[1]) this.forms[1].setStyle('display', 'none')
  },
  
  edit: function(e) {
    e.stop();
    this.forms[1].setStyle('display', 'block')
    if (this.forms[1]) this.forms[0].setStyle('display', 'none')
  }
})


IGC.addEvent('load', function() {
  Support.initialize($('support-widget'))
  new Tickets($('tickets'))
});



IGC.addEvent('load', function() {
  new Calculator($('exchange-calculator'))
})

IGC.addEvent('load', function() {
	if (location.hash && location.hash.length > 1) {
		$hash.query = location.hash.substr(1, 200);
		var splitten = $hash.query.split("-");
		$hash.entity = splitten.shift();
		$hash.id = splitten.join("-");
	}
});

//Top bar interface thingies
IGC.addEvent('load', function() {
/*
	Slider.init();*/
	Selector.init(); 
	new Appearance($('actions'), $('add-or'));
	Authorization.initialize('authorization')
	
	new Appearance($('content-filter-toolbox'), $('content-filter-picker'), {
	  onShow: function() {
      var styles = $('content-filter-picker').computePosition($('content-filter-picker').getPositionRelativeTo($('wrapper')));

      var previous = $E('#content-filter-toolbox li.active').getAllPrevious('li')
      previous = previous ? previous.length : 0;
      styles.top -= previous * 14;
      $('content-filter-toolbox').setStyles(styles)
	  }	  
	})
});

//Tooltips
IGC.addEvent('reload', function(el) {
	new UserToolbox(el.getElements('.user'), $('user-toolbox'));
	new BlogToolbox(el.getElements('.game-icon'), $('blog-toolbox'));
});
	
//Registration & Option editing
IGC.addEvent('load', function() {
	Registration.initialize($('registration'), $('registration-invintation'))
});

//Featured stuff 
IGC.addEvent('load', function() {
	new Featured($E('#slider ul'), $('slider-controls'));
});


//Managable lists
IGC.addEvent('load', function() {
	new Managable($('users') || $('blogs'));
})

//Syntax Help
IGC.addEvent('load', function() {
	SyntaxHelp.initialize($('syntax-help'));
});

//Comments 
IGC.addEvent('load', function() {
	new Comments($('comments'), $('new-comment'), $('new-comment-respond'), $('refresh-comments'), $('comment-count'));
	/*
	$each($$('#comments .give-igp'), function(item, index) {
		item.addEvent('click', function(e) {
			e = new Event(e);
			e.stop;
			alert(e.target.href);
		});
	});*/

});

//Game chooser 
IGC.addEvent('load', function() {
	$$('.game-chooser').each(function(el) {new GameChooser(el);});
});

//Contributors
IGC.addEvent('load', function() {
	if ($('show-contributors')) {
		Contributors.initialize($('contributors-form'), $('show-contributors'))
	}
});

IGC.addEvent('load', function() {
	ManagableSearch.initialize($('managable-search'))
});

//Default inputs
IGC.addEvent('reload', function() {
	$$('input[default], textarea[default]').each(function(el) {
		el.store('default', new (el.get('type') == "password" ? Default.Password: Default)(el));
	})
});

//Post rating
IGC.addEvent('load', function() {
	new PostRating($('rating'), $('rate-this'));	
  $$('#pay-help, div.inline-help, ul.side-help li').each(function(e) {
    new IGPHelp(e)
  })
});

IGC.addEvent('load', function() {
//	$$('p.flash-video').each(function(el) {
//		if (el.hasClass('youtube')) new YouTube(el)
//	})
});

IGC.addEvent('load', function() {
	/*
	if ($hash.query.length > 5) {
		var el = $($hash.query);
		if (el) {
			el.addClass('currently-selected');
			$scroller.toElement(el)
		}
	}*/
})

//Tags
IGC.addEvent('reload', function() {
	$$('input.suggester').each(function(el) {
	   new Autocompleter.Ajax.Json(el, el.getProperty('url'), {
			'minLength': 2, 
			'selectMode': el.get("force") == "true" ? 'type-ahead' : true,
			'multiple': el.get("comma-separated") == "true",
			'postVar': 'q',
			ajaxOptions: {
				'method': 'get'
			}
    });		
	})
});

IGC.addEvent('load', function() {
	new FileUpload($('upload-video')) 
})

IGC.addEvent('load', function() {
  new Tickets('tickets', 'ticket-form')
})

IGC.addEvent('load', function() {

  if (!window.ReMooz) return
  ReMooz.options.modal = true
	ReMooz.assign('a[rel=boxed]', {
		'shadow': 'onOpenEnd', // fx is faster because shadow appears after resize animation
		'resizeFactor': 0.8, // resize to maximum 80% of screen size
		'opacityResize': 0.4, // opaque resize
		'dragging': false, // disable dragging
		'type': 'url',
		'cutOut': false,
		'shadow': false,
		'centered': true,
		'onClose': function() {
		  $$('a.remooz-btn-close').fade('hide')
		  $$('div.remooz-box').setStyle('overflow', 'hidden')
		},
		'onOpenEnd': function() {
		  $$('div.remooz-box').setStyle('overflow', 'visible');
		  var this_id = this.link.replace('/items/', '').replace('/lightbox', '').toInt();
		  if($('product-version-container-' + this_id)) {
			  function enough2buy(key) {
					if(key == 1) {
						if($('few-karma-' + this_id)) $('few-karma-' + this_id).addClass('no-display');
						if($('few-bablo-' + this_id)) $('few-bablo-' + this_id).addClass('no-display');
						if($('but-this-item-btn-' + this_id)) $('but-this-item-btn-' + this_id).setStyle('display', 'inline-block');
					}
					if(key == 2) {
						if($('few-karma-' + this_id)) $('few-karma-' + this_id).addClass('no-display');
						if($('few-bablo-' + this_id)) $('few-bablo-' + this_id).removeClass('no-display');
						if($('but-this-item-btn-' + this_id)) $('but-this-item-btn-' + this_id).setStyle('display', 'none');
					}
					if(key == 3) {
						if($('few-karma-' + this_id)) $('few-karma-' + this_id).removeClass('no-display');
						if($('few-bablo-' + this_id)) $('few-bablo-' + this_id).addClass('no-display');
						if($('but-this-item-btn-' + this_id)) $('but-this-item-btn-' + this_id).setStyle('display', 'none');
					}
					return false;
				}
				
			  $each($$('#product-version-container-' + this_id + ' input'), function(item) {
			  	item.addEvent('click', function() {
					if($('this-product-price-' + this_id)) $('this-product-price-' + this_id).set('html', this.getProperty('price').toFloat());
					if($('this-product-min-karma-' + this_id)) $('this-product-min-karma-' + this_id).set('html', this.getProperty('max_lower_karma').toFloat());					
					enough2buy(this.getProperty('buy').toInt());
				});
			  });
			  
			  enough2buy($('last-version-of-item-' + this_id).getProperty('buy').toInt());
			  $('last-version-of-item-' + this_id).fireEvent('click');
		  }
		} // resize to center of the screen, not relative to the source element
	});

});