var Grapher = new Class({

	initialize: function() {
		this.graphContainer = $('graphContainer');
		this.positionX = $('positionX');
		this.positionY = $('positionY');
		this.currentLayer = 0;
		this.overlap = 10;
		this.sizex = 420;
		this.sizey = 420;
		this.graphIsDragged = false;
		this.options = new Hash({
			syntax:  1,
			centerx: 0,
			centery: 0,
			zoomx:   20,
			zoomy:   20,
/*
			sizex: 420,
			sizey: 420,
*/
			functions: new Array()
		});
		$each(['graph0', 'graph1'], function(layer) {
			$(layer).setStyle('height', this.sizey);
			$(layer).setStyle('width', this.sizex);
			new Drag(layer, {
					onStart: function(el) {
						$('graph' + (this.currentLayer + 1) % 2).setStyle('display', 'none');
						$('graph' + (this.currentLayer + 1) % 2).setStyle('background-image', 'none');
						this.graphIsDragged = true;
					}.bind(this),
					onComplete: function(el) {
						this.options.centery += (parseInt(el.getStyle('top')) + this.overlap) / this.options.zoomy;
						this.options.centerx -= (parseInt(el.getStyle('left')) + this.overlap) / this.options.zoomx;
						this.graphIsDragged = false;
						this.plot();
					}.bind(this),
					snap: 0,
				}
			);
		}, this);

		// assign button events
		$('btnReset').addEvent('click', function() {
			this.options.zoomx = 20;
			this.options.zoomy = 20;
			this.options.centerx = 0;
			this.options.centery = 0;
			this.plot();
		}.bind(this));
		$('btnZoomInBoth').addEvent('click', function() {
			this.options.zoomx *= 2;
			this.options.zoomy *= 2;
			this.plot();
		}.bind(this));
		$('btnZoomOutBoth').addEvent('click', function() {
			this.options.zoomx /= 2;
			this.options.zoomy /= 2;
			this.plot();
		}.bind(this));
		$('btnZoomInX').addEvent('click', function() {
			this.options.zoomx *= 2;
			this.plot();
		}.bind(this));
		$('btnZoomOutX').addEvent('click', function() {
			this.options.zoomx /= 2;
			this.plot();
		}.bind(this));
		$('btnZoomInY').addEvent('click', function() {
			this.options.zoomy *= 2;
			this.plot();
		}.bind(this));
		$('btnZoomOutY').addEvent('click', function() {
			this.options.zoomy /= 2;
			this.plot();
		}.bind(this));
		$('btnRefresh').addEvent('click', function(ev) {
			this.refreshFunctionList();
			this.plot();
		}.bind(this));
		$('functions').getElement('.functionNew .formula').addEvent('keyup', function(ev) {
			if (ev.key == 'enter') {
				ev.target.getParent('.functionNew').getElement('.store').click();
			}
		}.bind(this));
		$('functions').getElement('.functionNew .store').addEvent('click', function() {
			var fn = $('functions').getElement('.functionNew');
			this.storeFunction(fn.getElement('.formula').get('value'));
			fn.getElement('.formula').set('value', '');
			this.refreshFunctionList();
			// fn.getElement('.formula').focus(); // causes problems when keyup on store-button
			this.plot();
		}.bind(this));
		$('graphContainer').addEvent('mousemove', function(ev) {
			if ( ! this.graphIsDragged) {
				this.positionX.set('html', ((ev.client.x - this.graphContainer.offsetLeft - (this.sizex - this.overlap) / 2) / this.options.zoomx + this.options.centerx).toFixed(Math.round(Math.log(this.options.zoomx)) - 1));
				this.positionY.set('html', (-(ev.client.y - this.graphContainer.offsetTop - (this.sizey - this.overlap) / 2) / this.options.zoomy + this.options.centery).toFixed(Math.round(Math.log(this.options.zoomy)) - 1));
			}
			this.positionX.setStyle('left', ev.client.x);
			this.positionY.setStyle('top', ev.client.y);
		}.bind(this));

		if (window.location.href.contains('#')) {
			try {
				this.options.extend(JSON.decode(unescape(window.location.href.split('#')[1])));
			} catch (e) { } // for the case it's malformed suppress error messages and continue
		}
		if (this.options.functions.length) {
			this.options.functions.each(this.storeFunction, this);
			this.refreshFunctionList(); // actually just for renumering the sub's
		}
		$('functions').getElement('.functionNew .formula').set('value', '');

		(function() {
			$('functions').getElement('.functionNew .formula').focus(); // not working
		}).delay(100);

		this.plot();

	},

	storeFunction: function(formula) {
		var fn = $('functions').getElement('.functionNew');
		var f = fn.clone();
		f.set('class', 'functionEdit');
		f.getElement('.store').dispose();
		f.getElement('.formula').set('value', formula);
		var frm = new Element('input', {'type': 'image', 'class': 'remove', 'src': 'img/remove.png'});
		frm.addEvent('click', function(ev) {
			ev.target.getParent('.functionEdit').dispose();
			this.refreshFunctionList();
			this.plot();
		}.bind(this));
		frm.inject(f, 'bottom');
		f.getElement('.formula').addEvent('keyup', function(ev) {
			if (ev.key == 'enter') {
				$('btnRefresh').click();
			}
		}.bind(this));
		f.inject($('functionList'), 'bottom');
	},

	refreshFunctionList: function () {
		var i = 1;
		this.options.functions = new Array();
		$('functions').getElements('.functionEdit').each(function(fun) {
			fun.getElement('sub').set('html', i++);
			this.options.functions.push(fun.getElement('.formula').value);
		}, this);
		$('functions').getElement('.functionNew').getElement('sub').set('html', i);
		$('btnRefresh').setStyle('visibility', (i > 1) ? 'visible' : 'hidden');
	},

	plot: function() {
		window.location.href = '#' + JSON.encode(this.options);
		$('graph' + this.currentLayer).setStyle('z-index', 10);
		this.currentLayer = (this.currentLayer + 1) % 2;
		var url = 'img.php?' + this.options.toQueryString();
		if ( ! Browser.Engine.trident) {
			// toQueryString() is behaving different in firefox
			url = url.replace(/\(/g, '\\(').replace(/\)/g, '\\)');
		}
		$('graph' + this.currentLayer).setStyles({
			'z-index': 20,
			'top': (- this.overlap) + 'px',
			'left': (- this.overlap) + 'px',
			'display': 'block',
			'background-image': 'url(' + url + ')'
		});
	}

});


