	if (!window.DG) {
	    window.DG = {};
	}


	DG.Drawing = new Class({
		Extends: Events,
		points : [],
		userPoints : [],
		countPoints : 15,
		minDistance : 50,
		pointSize : 5,
		bigCircleSize : 15,
		userResult : null,
		finished : false,
		difficulty: 'easy',
		useTimer : false,
		url: null,
		startTime : null,
		countExcercises : null,
		accumulatedPoints : 0,
		accumulatedSeconds : 0,
		currentExcerciseIndex : 0,
		initialConfig : null,
		jsg : null,
		jsgDrawing : null,
		freehand: false,

		html: {
			originalCanvas : null,
			drawingCanvas: null,
			transparent: null,
			highscore:null,
			clock : null
		},
		initialize : function(config) {



			this.initialConfig = config;

			var cookie = Cookie.read('drawingUsername');
			if(cookie) {
				try{
					$('userName').set('value', cookie);
				}catch(e){
				}
			}

			this._storeCanvas();
			if(config.countPoints) {
				this.countPoints = config.countPoints;
			}
			if(config.freehand) {
				this.freehand = config.freehand;
			}
			if(config.difficulty) {
				this.difficulty = config.difficulty;
			}
			if(config.userResult) {
				this.userResult = config.userResult;
			}
			if(config.countExcercises) {
				this.countExcercises = config.countExcercises;
			}
			if(config.minDistance) {
				this.minDistance = config.minDistance;
			}
			if (config.customExercise) {
				this.customExercise = config.customExercise;
				this._setupCustomExercise(config.customExercise);
			}
			if(config.useTimer) {
				this.useTimer = config.useTimer;
			}
			this.getPoints();

			this.url = config.url;

			var el = $('canvasForJsGraphics');
			if(el) {
				try {
					this.jsg = new jsGraphics('canvasForJsGraphics');
					this.jsg.setColor('#AAA');
				}catch(e){
					this.jsg = null;
				}
			}
			var el = $('canvasForJsGraphicsUser');
			if(el) {
				try {
					this.jsgUser = new jsGraphics('canvasForJsGraphicsUser');
					this.jsgUser.setColor('#AAA');
				}catch(e){
					this.jsgUser = null;
				}
			}

			this.drawPoints();
			this.drawStartingPoints();
			this.initEvents();
			this._initTime();
			if (this.useTimer) {
				this.displayStatus.periodical(1000, this);
			}

			this.displayStatus();

		},
		clearVariables : function() {
			this.currentExcerciseIndex = 0;
			this.accumulatedPoints = 0;
			this.accumulatedSeconds = 0;
			this.currentExcerciseIndex = 0;
		},
		_initTime : function() {
			var d = new Date();
			this.startTime = d.getTime();
		},
		_setupCustomExercise : function(exerciseConfig) {
			if(exerciseConfig.images) {
				this.html.originalCanvas.setStyle('background-image', 'url(' + exerciseConfig.images.original + ')');
				this.html.drawingCanvas.setStyle('background-image', 'url(' + exerciseConfig.images.user + ')');
			}else{
				this.html.originalCanvas.setStyle('background-image', 'url()');
				this.html.drawingCanvas.setStyle('background-image', 'url()');
			}


		},
		reset: function() {

			this.finished = false;
			if(this.jsg) {
				this.jsg.clear();
			}
			if(this.jsgUser) {
				this.jsgUser.clear();
			}

			var els = $$('.drawingPoint');
			for(var i=els.length;i--;i>=0) {
				els[i].destroy();
			}
			var bigCircleEls = $$('.bigCircle');
			for(i=bigCircleEls.length;i--;i>=0) {
				bigCircleEls[i].destroy();
			}
			var userResultEls = $$('.userResult');
			for(i=userResultEls.length;i--;i>=0) {
				userResultEls[i].destroy();
			}

			this.points = [];
			this.userPoints = [];
			this.getPoints();
			this.drawPoints();
			this.drawStartingPoints();
			this.displayStatus();
			if(this.userResult.el){
				$(this.userResult.el).set('html', '');
			}
			this._initTime();


		},
		initEvents : function() {
			this.html.drawingCanvas.addEvent('click', this._addPoint.bind(this));
			this.html.originalCanvas.addEvent('click', this._logCoordinate.bind(this));



		},

		_showClock : function(e){
			if(!this.html.clock){
				this.html.clock = new Element('div');
				this.html.clock.setStyles({
					'position'	:	'absolute',
					'background-image' : 'url(images/clock.png)',
					'width'	:	100,
					'height' : 	100,
					'display' : 'none',
					'z-index' : 200,
					'opacity' : 0.7,
					'filter' : 'alpha(opacity=70)'
				});
				this.html.clock.addEvent('click', this._showClock.bind(this));
				$(document.body).adopt(this.html.clock);
			}

			this.html.clock.setStyles({
				left : e.page.x - 50,
				top : e.page.y - 50,
				display : 'block'
			});


		},
		_hideClock : function() {
			if(this.html.clock){
				this.html.clock.setStyle('display','none');
			}

		},
		_logCoordinate : function(e) {
			try{
				console.info(e.event.layerX + 'x' + e.event.layerY);
			}catch(ex) {

			}

			if(e.control){
				this._showClock(e);
				return false;
			}else{
				this._hideClock();
			}

		},
		_getDistanceForEachUserPoint : function() {
			var ret = [];
			for (var i = 2; i < this.userPoints.length; i++) {
				ret.push(this._getDistanceToClosestPoint(this.userPoints[i], true));
			}
			return ret;

		},

		getUserResult : function() {
			var total = 0;
			if (this.countPoints == 2) {
				var userAngle  = (180/Math.PI) * Math.atan2(this.userPoints[1].x - this.userPoints[0].x, this.userPoints[1].y - this.userPoints[0].y);
				var angle = (180/Math.PI) * Math.atan2(this.points[1].x - this.points[0].x, this.points[1].y - this.points[0].y);
				ret = Math.abs(userAngle - angle);
				if(ret > 180) ret = 360 - ret;
				return ret.toFixed(2) / 1;
			}
			else {
				for (var i = 0; i < this.userPoints.length; i++) {
					var distance = this._getDistanceToClosestPoint(this.userPoints[i], true);
					total += distance;
					if (this.jsg && i>0) {
						var pointDiv = $('userPoint' + i);
						if (pointDiv) {
							var resultDiv = new Element('div');
							resultDiv.addClass('userResult');
							resultDiv.setStyles({
								left: (pointDiv.getStyle('left').replace('px', '') / 1) + 10,
								top: (pointDiv.getStyle('top').replace('px', '') / 1) - 2,
								position: 'absolute'
							});
							resultDiv.set('html', '+' + distance);
							this.html.originalCanvas.adopt(resultDiv);
						}
					}

				}
			}
			return total;
		},
		_getPointSize : function() {
			if(!this.pointSize) {
				var els = $$('.drawingPoint');
				this.pointSize = els[0].getStyle('width').replace('px','');
			}
			return this.pointSize;
		},
		_addPoint : function(e) {


			if(this.finished) {
				alert('This exercise is finished. Please start a new one');
				return;
			}


			var point = {
				x : (e.event.layerX ? e.event.layerX : e.event.offsetX),
				y : (e.event.layerY ? e.event.layerY : e.event.offsetY)
			};

			var distanceToClosestPoint = this._getDistanceToClosestUserPoint(point);

			if(e.target.hasClass('drawingPointUser') || distanceToClosestPoint < 20) {

				if(e.target.hasClass('drawingPointUser')) {
					point = {
						x : e.target.getStyle('left').replace('px','') / 1,
						y : e.target.getStyle('top').replace('px','') / 1
					};
				}
				var index;
				if(e.target.hasClass('drawingPointUser')) {
					index = e.target.id.replace(/[^0-9]/g,'');
					if(!this.customExercise && index < 2) {
						return;
					}
					this._destroyUserPoint(index);
					this._drawLinesOnUserCanvas();
				}else{
					index = this._getIndexOfClosestUserPoint(point);
				}
			}else if(!e.target.hasClass('drawingPointUser') && ( this.userPoints.length < this.points.length || this.freehand)) {
				this.userPoints.push(point);
				this._drawLinesOnUserCanvas();
				var el = this._getCircleElement(point);
				this._addUserPoint(el);
			}

			this.displayStatus();

			if(this.userPoints.length == this.points.length && this.countExcercises) {
				this._drawUserPointsOnOriginalCanvas();
				this.getUserResult();
				this.nextSheet();
			}
		},
		_drawLinesOnUserCanvas : function() {
			if(this.jsgUser) {
				this.jsgUser.clear();
				for (var i = 0; i < this.userPoints.length; i ++) {
					var index = this._getIndexOfClosestUserPoint(this.userPoints[i]);
					var index2 = this._getIndexOfSecondClosestUserPoint(this.userPoints[i])

					this.jsgUser.drawLine(this.userPoints[i].x, this.userPoints[i].y, this.userPoints[index].x, this.userPoints[index].y);
					if(index2 != null) {
						this.jsgUser.drawLine(this.userPoints[i].x, this.userPoints[i].y, this.userPoints[index2].x, this.userPoints[index2].y);
					}

					var el = this._getCircleElement(this.userPoints[i]);
					this._addUserPoint(el);
				}
				this.jsgUser.paint();
			}
		},
		nextSheet : function() {
			var timepenalty = this._getTimePenalty();
			var pointOffset = this.getUserResult();
			var userResult = pointOffset + timepenalty;
			this.accumulatedPoints += pointOffset;
			this.accumulatedSeconds += timepenalty;
			this.currentExcerciseIndex++;
			if(this.currentExcerciseIndex == this.countExcercises) {
				this._displayResult(userResult,pointOffset,timepenalty, 1);
				this.finish.delay(1000, this);
			}else{

				this.reset.delay(1500, this);
				this._displayResult(userResult,pointOffset,timepenalty);
			}
		},
		hideHighscore : function() {
			this.html.transparent.setStyle('display','none');
			this.html.highscore.setStyle('display','none');

		},

		showHighscore : function() {
			if(!this.html.highscore) {
				this.html.transparent = new Element('DIV');
				this.html.transparent.setStyles({
					width : '100%',
					height: '100%',
					'background-color' : '#FFF',
					filter: 'alpha(opacity=20',
					opacity: 0.2,
					position: 'absolute',
					left : 0,
					top:0,
					'z-index' : 1000
				});
				$(document.body).adopt(this.html.transparent);

				this.html.highscore = new Element('DIV');

				this.html.highscore.addClass('highscoreDiv');
				$(document.body).adopt(this.html.highscore);

				this.html.closeButton = new Element('DIV');
				this.html.closeButton.setStyles( {
					position : 'absolute',
					bottom: 0,
					left : 0,
					'background-color' : '#000',
					width:'100%',
					'text-align' : 'center'
				});
				var a = new Element('A');
				a.set('html', 'Close');
				a.setStyles({
					'color' : '#FFF',
					'text-decoration' : 'underline',
					cursor: 'pointer'
				});
				a.addEvent('click', this.hideHighscore.bind(this));
				this.html.closeButton.adopt(a);
				this.html.highscore.adopt(this.html.closeButton);

				this.html.highscoreInner = new Element('DIV');
				this.html.highscoreInner.id = 'highscoreDiv';
				this.html.highscore.adopt(this.html.highscoreInner);


			}

			this.html.transparent.setStyle('display','');
			this.html.highscore.setStyle('display','');

			var req = new Request({
				url: this.url,
				noCache : 1,
				data: {
					getHighscore:1,
					difficulty : this.difficulty
				},
				onComplete : function(responseText) {
					$('highscoreDiv').set('html', responseText);
				}
			});



			req.send();

		},
		getTimeSpend : function() {
			var d = new Date();
			var timeSpend = d.getTime() - this.startTime;
			return Math.round(timeSpend / 1000);
		},

		displayStatus : function() {
			if(this.finished) {
				return;
			}
			if(this.userResult && this.userResult.statusEl) {
				var text = this.userResult.statusText;
				if (!this.countExcercises) {
					text = text.replace('{0}', this.userPoints.length);
					text = text.replace('{1}', this.points.length);
				}else{
					text = text.replace('{2}', this.currentExcerciseIndex+1);
					text = text.replace('{3}', this.countExcercises);
				}
				if(this.useTimer) {
					var d = new Date();
					var seconds = this.getTimeSpend();
					text = text.replace('{3}', seconds);
				}
				$(this.userResult.statusEl).set('html', text);
			}
		},
		_destroyUserPoint : function(index) {
			try{
				var target = $('userPoint' + index);
				this.userPoints.splice(index,1);
				target.destroy();

				for(var i=index;i<this.countPoints;i++) {
					if($('userPoint' + i)){
						$('userPoint' + i).id = 'userPoint' + (i-1);
					}
				}
			}catch(e){

			}
		},
		_getTimePenalty: function() {
			if(this.countPoints == 2) {
				return (this.getTimeSpend() / 5).toFixed(2) / 1;
			}else if (this.countExcercises) {
				return Math.round(this.getTimeSpend() / 2);
			}
			else {
				return Math.ceil(this.getTimeSpend() / 3);
			}
		},
		_drawUserPointsOnOriginalCanvas : function() {
			var start = this.customExercise ? 0 : 2;
			if(this.countPoints == 2) start = 1;	// angle exercise only

			if(this.jsg) {
				if (this.countPoints == 2) {
					this.jsg.setColor('#FF0000');
					this.jsg.drawLine(this.userPoints[0].x, this.userPoints[0].y, this.userPoints[1].x, this.userPoints[1].y);
					this.jsg.setColor('#00FF00');
					this.jsg.drawLine(this.points[0].x, this.points[0].y, this.points[1].x, this.points[1].y);
				}
				else {
					for (var i = 0; i < this.userPoints.length; i++) {
						var index = this._getIndexOfClosestUserPoint(this.userPoints[i]);
						var index2 = this._getIndexOfSecondClosestUserPoint(this.userPoints[i])
						this.jsg.drawLine(this.userPoints[i].x, this.userPoints[i].y, this.userPoints[index].x, this.userPoints[index].y);
						if (index2 != null) {
							this.jsg.drawLine(this.userPoints[i].x, this.userPoints[i].y, this.userPoints[index2].x, this.userPoints[index2].y);
						}
					}
				}
				this.jsg.paint();
			}
			for(var i=start;i<this.userPoints.length;i++) {
				var el = this._getCircleElement(this.userPoints[i]);
				el.addClass('drawingPointUser');
				this.html.originalCanvas.adopt(el);
			}
		},

		finish : function() {
			if(this.finished) {
				return;
			}
			this.finished = true;


			this._drawUserPointsOnOriginalCanvas();
			if(this.userResult && this.userPoints.length == this.points.length) {
				var seconds = 0;
				if(this.useTimer) {
					seconds = this._getTimePenalty();
				}
				if (this.countExcercises) {
					var pointOffset = this.accumulatedPoints;
					var seconds = this.accumulatedSeconds;
				}
				else {
					var pointOffset = this.getUserResult();
				}

				var result =  Math.round(pointOffset + seconds);

				if (this.useTimer || this.countExcercises) {
					this._displayResult(result, pointOffset.toFixed(2)/1, seconds.toFixed(2)/1);
				}else{
					this._displayResult(result, pointOffset, 0);
				}

				if(this.url) {

					var username = $('userName').get('value');
					if(!username.length || username=='Anonymous') {
						username = window.prompt('Enter your username(For the highscore list)');
						$('userName').set('value', username);
					}
					if(username == 'null') {
						username = 'Anonymous';
					}
					Cookie.write('drawingUsername', username, {
						duration: 500
					});
					if(username) {
						if (this.difficulty == 'angle') {
							var comment = 'degrees: ' + pointOffset.toFixed(2)/1 + ', time: ' + seconds.toFixed(2)/1;
						}
						else {
							var comment = 'pixels: ' + pointOffset + ', time: ' + seconds;
						}
						if(this.difficulty == 'veryeasy' || this.difficulty == 'easy' || this.difficulty == 'difficult') {
							comment = 'Dist: ' +  this._getDistanceForEachUserPoint().join(', ');
						}

						var req = new Request(
							{
								url: this.url,
								method : 'post',
								data: {
									username: username,
									saveScore:1,
									countPoints : this.countPoints,
									difficulty : this.difficulty,
									comment : comment,
									score: result,
									seconds : this.getTimeSpend()
								}
							}

						);
						req.send();
					}
				}
			}


		},
		_displayResult : function(result, pointOffset, seconds, inProgress) {
			if(pointOffset % 1 != 0) {
				pointOffset = pointOffset.toFixed(2);
			}
			if(result % 1 != 0) {
				result = result.toFixed(2);
			}
			if(this.countExcercises && this.currentExcerciseIndex ==  this.countExcercises && !inProgress) {
				var text = this.userResult.texttotalscore.replace('{0}', result);
			}else{
				var text = this.userResult.text.replace('{0}', result);
			}


			if (this.useTimer || this.countExcercises) {
				text = text.replace('{1}', pointOffset);
				text = text.replace('{2}', seconds);
			}

			$(this.userResult.el).set('html', text);
		},
		_eventDestroyUserPoint : function(e) {
			e.stop();
			var index = e.target.id.replace(/[^0-9]/g,'');
			if(index){
				this._destroyUserPoint(index);
			}
		},
		_addUserPoint : function(el) {
			el.addClass('drawingPointUser');
			if(this.userPoints.length) {
				el.id = 'userPoint' + (this.userPoints.length-1);
			}
			this.html.drawingCanvas.adopt(el);
		},
		_storeCanvas : function() {
			var canvas = $$('.canvas');
			if(canvas.length == 2) {
				this.html.originalCanvas = canvas[0];
				this.html.drawingCanvas = canvas[1];
			}
		},
		drawPoints : function() {
			for(var i=0;i<this.points.length;i++) {
				this.html.originalCanvas.adopt(this._getCircleElement(this.points[i]));
			}
		},
		_getDistanceBetweenPoints : function(pointOne, pontTwo) {
			var distXAxis = Math.abs(pointOne.x - pontTwo.x);
			var distYAxis = Math.abs(pointOne.y - pontTwo.y);
			distXAxis *= distXAxis;
			distYAxis *= distYAxis;
			if(distXAxis + distYAxis === 0) {
				return 0;
			}
			return Math.round(Math.sqrt(distXAxis + distYAxis));
		},
		_getDistanceToClosestUserPoint : function(point, excludedIndex) {
			var minDiff = 10000;
			for (var i = 0; i < this.userPoints.length; i++) {
				var distance = this._getDistanceBetweenPoints(point, this.userPoints[i]);
				if(distance < minDiff) {
					minDiff = distance;
				}
			}
			return minDiff;
		},
		_sortPoints : function(obj,obj2) {
			return obj2.distance - obj.distance;
		},
		_getIndexOfClosestUserPoint: function(point, shift) {
			if(this.countPoints == 2) {
				return 0;
			}

			var minDiff = 10000;
			var minDiff2 = 10000;
			if(!shift) {
				shift = 0;
			}
			var ret = null;
			var ret2 = null;
			var distances = [];
			for (var i = 0; i < this.userPoints.length; i++) {
				var distance = this._getDistanceBetweenPoints(point, this.userPoints[i]);
				if(distance > 0) {
					distances.push({
						index: i,
						distance: distance
					});
				}
				/*
				if(distance < minDiff && distance>0) {
					ret2 = ret;
					ret = i;
					minDiff2 = minDiff;
					minDiff = distance;
				}else if(distance < minDiff2 && distance > 0) {
					ret2 = i;
					minDiff2 = distance;
				}*/
			}
			distances.sort(function(a,b){ return a.distance - b.distance });
			return distances[shift].index;

		},
		_getIndexOfSecondClosestUserPoint : function(point) {
			return this._getIndexOfClosestUserPoint(point, 1);
		},
		_getIndexOfThirdClosestUserPoint : function(point) {
			return this._getIndexOfClosestUserPoint(point, 2);
		},
		_getDistanceToClosestPoint : function(point, includeEqual) {
			var minDiff = 10000;
			for (var i = 0; i < this.points.length; i++) {
				var distance = this._getDistanceBetweenPoints(point, this.points[i]);
				if(distance>0 || includeEqual) {
					if(distance < minDiff) {
						minDiff = distance;
					}
				}
			}
			return minDiff;
		},
		_getClosestPoint : function(point) {
			var closestPoint;
			var minDiff = 10000;
			for (var i = 0; i < this.points.length; i++) {
				var distance = this._getDistanceBetweenPoints(point, this.points[i]);

				if(distance>0) {
					if(distance < minDiff) {
						minDiff = distance;
						closestPoint = this.points[i];
					}
				}
			}
			return closestPoint;
		},

		drawStartingPoints : function() {
			if(this.points.length < 2 || (this.customExercise && !this.freehand)) {
				return;
			}
			var el = this._getCircleElement(this.points[0]);
			this._addUserPoint(el);



			this.userPoints.push(this.points[0]);
			if (this.points.length > 2 || this.freehand) {
				var nextPoint = this._getClosestPoint(this.points[0]);
				el = this._getCircleElement(nextPoint);
				this._addUserPoint(el);
				this.userPoints.push(nextPoint);
			}
			this._drawBigCircles();

		},
		_drawBigCircles : function() {
			var posDiff = Math.floor(this.bigCircleSize /2);

			for(var i=0;i<this.userPoints.length;i++) {
				var el = new Element('div');
				el.addClass('bigCircle');
				el.setStyles( {
						left: this.userPoints[i].x - posDiff,
						top: this.userPoints[i].y - posDiff
					}
				);
				this.html.originalCanvas.adopt(el);

			}

		},

		_getCircleElement: function(coordinate) {
			var pointWidth = Math.ceil(this._getPointSize() / 2);
			if(navigator.userAgent.indexOf('MSIE')>=0){
				pointWidth--;
			}
			var el = new Element('DIV');
			el.setStyles({
				left: coordinate.x - pointWidth,
				top: coordinate.y - pointWidth
			});
			el.addClass('drawingPoint');
			return el;
		},

		_getPointsFromCustomExercise : function() {
			if(this.countPoints < this.customExercise.coordinates.length) {
				var ret = [];
				var keys = {};
				while(ret.length < this.countPoints) {
					var rnd = Math.floor(Math.random()*this.customExercise.coordinates.length);
					if(!keys[rnd]){
						keys[rnd] = true;
						ret.push(this.customExercise.coordinates[rnd]);
					}
				}
				return ret;

			}else{
				return this.customExercise.coordinates;
			}

		},
		getPoints : function() {

			if(this.customExercise) {
				this.points = this._getPointsFromCustomExercise();
				return;
			}

			var width = this.html.originalCanvas.getStyle('width').replace('px','')/1;
			var height = this.html.originalCanvas.getStyle('height').replace('px','')/1;
			width-=10;
			height-=10;
			for(var i=0;i<this.countPoints;i++) {
				var point = {
					x: Math.max(15, Math.round(Math.random() * width)),
					y: Math.max(15, Math.round(Math.random() * height))
				};
				while(this._getDistanceToClosestPoint(point) < this.minDistance) {
					point = {
						x: Math.max(15, Math.round(Math.random() * width)),
						y: Math.max(15, Math.round(Math.random() * height))
					};
				}
				this.points[i] = point;
			}

		}

	});
