/**
 * @author Triaffer
 */

	var relatedColors = new Array();
	relatedColors[0] = '#7aa559';
	relatedColors[1] = '#d39500';
	relatedColors[2] = '#9b1600';
	relatedColors[3] = '#d26551';
	relatedColors[4] = '#996c00';
	relatedColors[5] = '#0079ea';
	relatedColors[6] = '#f00ee8';
	relatedColors[7] = '#2be300';
	relatedColors[8] = '#12e9e6';
	relatedColors[9] = '#5f5f5f';
	
	var colorsCount;

//Map prototype
var mapPrototype = function(containerId){

//Constructor
	this.keywordsArray		= new Array();
	this.relationsArray		= new Array();
	this.attemptsCount		= 100; //count of random attemps
	this.containerId		= containerId;
	this.containerWidth		= $('#'+this.containerId).attr('offsetWidth');
	this.containerHeight	= $('#'+this.containerId).attr('offsetHeight');
	
	this.minLinkWeight;
	this.maxLinkWeight;
	this.stylesStepsCount	= 5;
	this.iconPath			= 'images/icons/';
	this.showIcons			= true;
	this.searchObject;
	
	this.colorCenters		= new Array();
	
	this.minRelationWeight;
	this.maxRelationWeight;
	
//Abstract methods

	//Clear map
	this.clear = new Function();
	
	//Add word into query
	this.addWord = new Function();
	
	//Delete word from query
	this.deleteWord = new Function();
	
	//Prepare style for keyword in according to their weight
	this.prepareWordStyle = new Function();
	this.prepareLinkStyle = new Function();


//Public methods

	//Return keyword with specified id
	this.getKeyword = function (id, type) {
		for (var i=0; i<this.keywordsArray.length; i++) {
			
			if ((type=='realId')&&(id==this.keywordsArray[i].realId)) {
				return this.keywordsArray[i];
			};
			
			if (id==this.keywordsArray[i].id) {
				return this.keywordsArray[i];
			};
		};
		return false;
	};

	//Return first related keyword
	this.getFirstRelatedKeyword = function (id) {

		if (this.relationsArray.length==0) {
			return false;
		};
		
		var relations = this.getRelationsTo(id);
		
		if (relations.length==0) {
			return false;
		};
		
		var firstRelatedKeyword;
		
		for (var i=0; i<relations.length; i++) {
			var keywordTo = this.getKeyword(relations[i].id1, 'realId');
			if ((keywordTo.type == 'normal')&&(relations[i].weight>0.55)) {
				return keywordTo;
			};
		};

		return false;
	};

	//Import object from xml
	this.importFromXml = function (xml) {
		
		//Re-inicialize object
		var map = this;
		this.keywordsArray = new Array();
		this.relationsArray = new Array();
		
		//Import existing words
		$('existingWord', $(xml)).each(function() {
			var newKeyword = new wordPrototype('query');
			newKeyword.importFromXml(this);
			map.keywordsArray[ map.keywordsArray.length ] = newKeyword;
		});

		//Import related words
		$('relatedWord', $(xml)).each(function() {
			var newKeyword = new wordPrototype('normal');
			newKeyword.importFromXml(this);
			map.keywordsArray[ map.keywordsArray.length ] = newKeyword;
		});
				
		//Import relations
		var mapDescriptor = this;
		$('relation', $(xml)).each(function() {
			var newRelation = new relationPrototype();
			newRelation.importFromXml(this);
			map.relationsArray[ map.relationsArray.length ] = newRelation;

			if ((mapDescriptor.minRelationWeight==undefined)||(newRelation.weight<mapDescriptor.minRelationWeight)) {
				mapDescriptor.minRelationWeight = newRelation.weight;
			};
			
			if ((mapDescriptor.maxRelationWeight==undefined)||(newRelation.weight>mapDescriptor.maxRelationWeight)) {
				mapDescriptor.maxRelationWeight = newRelation.weight;
			};
		});
		
		//Sorting keywords array
		/*this.keywordsArray.sort(function (x,y) {
			if (x.linkWeight>y.linkWeight) return -1;
			else if (x.linkWeight<y.linkWeight) return 1;
			return 0;
		});*/
		
		//Prepare minimal and maximal values
		if (this.keywordsArray.length > 0) {
			this.minLinkWeight = this.keywordsArray[this.keywordsArray.length - 1].linkWeight;
		} else {
			this.minLinkWeight = 0;
		};
		
		if (this.keywordsArray[0] != undefined) {
			this.maxLinkWeight = this.keywordsArray[0].linkWeight;
		} else {
			this.maxLinkWeight = 0;
		};
		
		
		//Colorize keywords
		var color=0;
		for (var i=0; i<this.keywordsArray.length; i++) {
			
			var prettyKeyword = this.keywordsArray[i];
			if (prettyKeyword.color==undefined) {
				var firstRelatedKeyword = this.getFirstRelatedKeyword(prettyKeyword.realId);
				if ((firstRelatedKeyword.color==undefined)) {
					prettyKeyword.color = color;
					color++;
				}
				else {
					prettyKeyword.color = firstRelatedKeyword.color;
				};
			};
		};
		colorsCount = color;
	};
	
	//Prepare div rects
	this.prepareRects = function(){
		
		//Prepare div sizes and keywords sizes
		var k = (this.maxLinkWeight-this.minLinkWeight)/(this.stylesStepsCount-1);
		for (var i=0; i<this.keywordsArray.length; i++) {
			var keyword = this.keywordsArray[i];
			keyword.size = Math.floor(keyword.linkWeight/k)+1;
			if (keyword.size>this.stylesStepsCount) {
				keyword.size = this.stylesStepsCount;
			};

			//Prepare icon for word
			var keywordIcon = new String();
			if ((keyword.icon.length>0)&&(this.showIcons)) {
				keywordIcon = '<img src="'+this.iconPath+keyword.icon+'" alt="" class="iconStyle" style="width: 16px; height: 16px;" />';
			};
			
			//Put div with keywords in container
			$('#'+this.containerId).append(
			'<div id="keyword'+keyword.id+'" class="'+keyword.type+'KeywordDiv">'
			+ keywordIcon
			+ '<a href="javascript:'
			+ keyword.onClick
			+ '" onMouseOver="'
			+ keyword.onMouseOver
			+ '" onMouseOut="'
			+ keyword.onMouseOut
			+ '" class="'+keyword.type
			+ 'Keyword '+keyword.type+'KeywordLink keywordSize'+keyword.size+'"'
			+ ' title="'+keyword.word+'">'
			+ keyword.word
			+ '</a></div>');
			
			//Prepare keyword size
			this.keywordsArray[i].width = $('#keyword'+keyword.id).attr('offsetWidth');
			this.keywordsArray[i].height = $('#keyword'+keyword.id).attr('offsetHeight');
		};
		
	};
	
	//Draw map
	this.drawMap = function(xml){
	
		//Save start time
		var timeBefore = new Date();
		this.colorCenters = new Array();
		
		//Clear map container
		$('#' + this.containerId).attr('innerHTML', '');
		var containerWidth = $('#' + this.containerId).attr('offsetWidth');
		var containerHeight = $('#' + this.containerId).attr('offsetHeight');
		
		//Prepare keywords 
		this.prepareRects();
		
for (var z=0; z<colorsCount; z++){		
		//Calculate keywords positions
		for (var i = 0; i < this.keywordsArray.length; i++) 
		
		if (this.keywordsArray[i].color==z){
		
			var newX = 0;
			var newY = 0;
			var minDistance = undefined;
			
			for (var j = 0; j < this.attemptsCount; j++) {
				//generate random position
				var randomX = Math.round(Math.random() * (containerWidth - this.keywordsArray[i].width));
				var randomY = Math.round(Math.random() * (containerHeight - this.keywordsArray[i].height));
				
				//Check intersection with other keywords
				var intersection = false;
				for (var k = 0; k < this.keywordsArray.length; k++) {
					//if not same
					if (this.keywordsArray[k].id != this.keywordsArray[i].id) {
						this.keywordsArray[i].x = randomX;
						this.keywordsArray[i].y = randomY;
						
						if (getMin(this.keywordsArray[k].x, this.keywordsArray[k].x + this.keywordsArray[k].width, this.keywordsArray[i].x, this.keywordsArray[i].x + this.keywordsArray[i].width) &&
						getMin(this.keywordsArray[k].y, this.keywordsArray[k].y + this.keywordsArray[k].height, this.keywordsArray[i].y, this.keywordsArray[i].y + this.keywordsArray[i].height)) {
							intersection = true;
							break;
						};
						
											};
									};
				
				if (intersection == false) {
					//calculate distance to container center
					if (this.colorCenters[this.keywordsArray[i].color] == undefined) {
						var localCenterX = randomX + this.keywordsArray[i].width / 2 - containerWidth / 2;
						var localCenterY = randomY + this.keywordsArray[i].height / 2 - containerHeight / 2;
					}
					else {
						var colorCenter = this.colorCenters[this.keywordsArray[i].color];
						var localCenterX = randomX + this.keywordsArray[i].width / 2 - colorCenter.x;
						var localCenterY = randomY + this.keywordsArray[i].height / 2 - colorCenter.y;
					};
					
					var distanceToCenter = Math.sqrt(Math.pow(localCenterX, 2) + Math.pow(localCenterY, 2));
					
					if ((distanceToCenter < minDistance) || (minDistance == undefined)) {
						minDistance = distanceToCenter;
						newX = randomX;
						newY = randomY;
					};
									};
							};
			this.keywordsArray[i].x = newX;
			this.keywordsArray[i].y = newY;
			
			if (this.colorCenters[this.keywordsArray[i].color] == undefined) {
				var colorCenter = new Object();
				colorCenter.x = this.keywordsArray[i].x;
				colorCenter.y = this.keywordsArray[i].y;
				this.colorCenters[this.keywordsArray[i].color] = colorCenter;
			};
			
			
			$('#keyword' + this.keywordsArray[i].id).css('display', 'none');
			$('#keyword' + this.keywordsArray[i].id + '>a').css('color', relatedColors[this.keywordsArray[i].color]);
			
		};
	};	
		//Show map
		for (var i = 0; i < this.keywordsArray.length; i++) {
			if (this.keywordsArray[i].x > 0) {
			$('#keyword'+this.keywordsArray[i].id).css('left',this.keywordsArray[i].x+'px');
			$('#keyword'+this.keywordsArray[i].id).css('top',this.keywordsArray[i].y+'px');
				$('#keyword'+this.keywordsArray[i].id).slideDown();
			};
		};
		
		//Add script execution time
		var timeAfter = new Date();
		var workTime = timeAfter.getTime() - timeBefore.getTime();
		$('#'+this.containerId).append('<input type="hidden" id="workTime" value="'+workTime+' msec" />');

	};

	//Get all keywords relations
	this.getRelationsTo = function(id) {

		var resultRelations = new Array();
		for (var i=0; i<this.relationsArray.length; i++) {
			
			var a1 = this.relationsArray[i].id1*1;
			var a2 = this.relationsArray[i].id2*1;
			var a3 = id*1;

			if ((a1*1==a3*1)||(a2*1==a3*1)) {
				resultRelations[resultRelations.length] = this.relationsArray[i];
			};
		};
		return resultRelations;
	};
	
//Private methods
	var getMin = function (min1, max1, min2, max2) {
		if (((min1>=min2)&&(min1<=max2))||((min2>=min1)&&(min2<=max1))) {
			return true;
		};
		return false;
	};
};