/////
///   Utility Functions [util]
/////

function get_number_letter(number) {
	letters = "abcdefghijklmnopqrsuvwxyzABCDEFGHIJKLMNOPQRSUVWXYZ";
	return (letters.charAt(number));
}

function sprite_move(el, x, y) {
	$(el).setStyle('background-position', x + 'px ' + y + 'px');
}

function str_replace(search, replace, subject) {
    var f = search, r = replace, s = subject;
    var ra = is_array(r), sa = is_array(s), f = [].concat(f), r = [].concat(r), i = (s = [].concat(s)).length;
 
    while(j = 0, i--) {
        while(s[i] = s[i].split(f[j]).join(ra ? r[j] || "" : r[0]), ++j in f);
    }
     
    return sa ? s : s[0];
}

function is_array(mixed_var) {
    return (mixed_var instanceof Array);
}

function array_sum(array) {
    var key, sum=0;
 
    if(!array || (array.constructor !== Array && array.constructor !== Object) || !array.length) {
        return null;
    }
 
    for(var i=0; i<array.length; i++){
        sum += array[i];
    }    
    return sum;
}

function preload_images(images) 
{
	images = $splat(images);
	new Asset.images(images);
}

function print_r(array, return_val) {
    var output = "", pad_char = " ", pad_val = 4;
 
    var formatArray = function(obj, cur_depth, pad_val, pad_char) {
        if(cur_depth > 0)
            cur_depth++;
 
        var base_pad = repeat_char(pad_val*cur_depth, pad_char);
        var thick_pad = repeat_char(pad_val*(cur_depth+1), pad_char);
        var str = "";
 
        if(obj instanceof Array) {
            str += "Array\n" + base_pad + "(\n";
            for(var key in obj) {
                if(obj[key] instanceof Array) {
                    str += thick_pad + "["+key+"] => "+formatArray(obj[key], cur_depth+1, pad_val, pad_char);
                } else {
                    str += thick_pad + "["+key+"] => " + obj[key] + "\n";
                }
            }
            str += base_pad + ")\n";
        } else {
            str = obj.toString();
        };
 
        return str;
    };
 
    var repeat_char = function (len, pad_char) {
        var str = "";
        for(var i=0; i < len; i++) { str += pad_char; };
        return str;
    };
    output = formatArray(array, 0, pad_val, pad_char);
 
    if(return_val !== true) {
        document.write("<pre>" + output + "</pre>");
        return true;
    } else {
        return output;
    }
}

/////
///   CLASS: Calculator [calc]
/////

function Calculator(charClass, startLevel, maxLevel, ptsAvail) {
	this.charClass   = charClass;
	this.startLevel  = startLevel;
	this.maxLevel    = maxLevel;
	this.ptsAvail    = ptsAvail;

	this.ptsSpent    = 0;
	this.reqdLevel   = new Array();
	this.buildString = '';
	this.locked      = 0;
	this.ignoreReqs  = 0;
	
	this.saved       = 0;
	this.creator     = undefined;
	this.created     = undefined;
	this.modified    = 0;
	
	this.startTime   = new Date();
	
	var featsJson    = this.FetchFeats();
	this.feats       = new Feats(featsJson);
	
	this.MakeLevelArray(this.startLevel, this.maxLevel, 'double10s');
}

Calculator.prototype.GetLevel = function() {
	this.GetPointsSpent();
	
	return this.reqdLevel[this.ptsSpent];
}

Calculator.prototype.ProcessSavedBuild = function(json) {
	var build = eval('(' + json + ')');
	
	this.buildString = build.string;
	this.creator     = build.username;
	this.created     = build.created_at;
}

Calculator.prototype.GetSavedBuild = function(buildId) {
	new Request({url: 'http://f.goonheim.com/feats/load/' + buildId, 
	             async: false,
				 onSuccess: (function(json) {
				 	if(json) {
						this.ProcessSavedBuild(json);
				 	} else {
				 		this.Start();
				 	}
				 }).bind(this)}, this).send();
}

Calculator.prototype.Recalculate = function() {
	$each(this.feats.trees, function(tree) {
		tree.Recalculate();
		tree.UpdateTreePoints();
	});
}

Calculator.prototype.ParseBuildString = function(buildString) {
	this.feats.ignoreReqs = 1;
	
	var curTree = 0;
	
	$each(this.feats.trees, function(tree) {
		var idxIter = 0;
		
		var treeIdx = buildString.search('t' + curTree);
		
		if(typeof treeIdx != 'undefined') {
			var treeStr = buildString.substr(treeIdx + 2);
			var curFeat = 0;
			
			for(var z = 0; z < tree.featMap.length; z++) {
				var featId = tree.featMap[z];
				var feat = tree.feats[featId];
			
				if(treeStr.charAt(idxIter) != 't') {
					if(get_number_letter(curFeat) == treeStr.charAt(idxIter)) {
						var featIdx  = treeStr.indexOf(get_number_letter(curFeat));
						var featIdx  = featIdx + 1;
						var featRank = treeStr.substr(featIdx, 1);

						if(featRank > feat.maxRank) {
							featRank = feat.maxRank;
						}
						
						feat.rank = featRank;
						feat.Update();
						
						idxIter = idxIter + 2;
					}
				}
				
				curFeat++;
			};
		}
		
		curTree++;
	}, this);
	
	this.feats.ignoreReqs = 0;
	this.Recalculate();
	this.GetPointsSpent();
	this.UpdateInfoBox();
	this.UpdateBuildUrl();
}

Calculator.prototype.Stasis = function(lock) {
	$each(this.feats.trees, function(tree) { 
		$each(tree.feats, function(feat) {
			if(feat.rank == 0) {
				feat.Deactivate();
			} else {
				feat.Activate();
			} 
		});
	});
	
	if(typeof lock != 'undefined') {
		switch(lock) {
			case true:
				this.Lock('lock');
				break;
			case false:
				this.Lock('unlock');
				break;
		}
	}
}

Calculator.prototype.Lock = function(action) {
	switch(action) {
		case 'toggle':
			if(this.locked == 0) {
				this.Stasis(true);
			} else {
				this.Stasis(false);
			}
	
			break;
		case 'lock':
			this.locked = 1;
			
			$('togLock-feats').setText('Unlock');
			$('togLock-feats').setStyle('background-position', 'left center');

			break;
		case 'unlock':
			this.locked = 0;
			if(this.ptsSpent != 79)
				this.feats.MakeActive();
			
			$('togLock-feats').setText('Lock');
			$('togLock-feats').setStyle('background-position', '-110px center');
			
			break;
	}
}

Calculator.prototype.Reset = function(treeName) {
	if(typeof treeName == 'undefined') {
		$each(this.feats.trees, function(tree) {
			tree.Reset();
		});
	} else {
		var tree = this.feats.trees.get(treeName);
		tree.Reset();
	}
	
	this.feats.MakeActive();
	this.GetPointsSpent();
	this.UpdateBuildUrl();
	this.UpdateInfoBox();
	
	if(this.locked == 1)
		this.Lock('unlock');
}

Calculator.prototype.GetPointsSpent = function() {
	var sum = 0;
	
	$each(this.feats.trees, function(tree) {
		sum += array_sum(tree.ptDist);
	});
	
	this.ptsSpent = sum;
}

Calculator.prototype.MakeBuildString = function() {
	var buildString = '';
	
	if(this.ptsSpent > 0) {
		var treeNum = 0;
		
		$each(this.feats.trees, function(tree) { 
			buildString = buildString + 't' + treeNum;
			
			$each(tree.feats, function(feat) {
				if(feat.rank > 0) {
					buildString = buildString + get_number_letter(feat.iterator) + feat.rank; 
				}
			});
			
			treeNum++;
		});
	}
	
	this.buildString = buildString;
}

Calculator.prototype.Interact = function(action, treeFeat, delayActivation) {
	if(this.locked == 1)
		return false;
	
	switch(action) {
		case 'train':
			if((this.ptsAvail - this.ptsSpent) <= 0)
				return false;
			if(this.feats.Interact(action, treeFeat, delayActivation)) {
				this.ptsSpent++;
				
				if(this.ptsSpent == this.ptsAvail)
					this.Stasis();
			}
			break;
		case 'untrain':
			if(this.ptsSpent <= 0)
				return false;
			if(this.feats.Interact(action, treeFeat, delayActivation)) {
				this.ptsSpent--;
			}
			break;
	}
	
	if(delayActivation != true) {
		this.UpdateBuildUrl();
	}
	
	this.UpdateInfoBox();
	this.modified = 1;
	this.saved    = 0;
	
	$each(this.feats.trees, function(tree) {
		for(var z = 0; z < tree.featMap.length; z++) {
			var featId = tree.featMap[z];
			var feat = tree.feats[featId];
			feat.UpdateTooltip(true, this.GetLevel());
		}
	}, this);
	
	return true;
}

Calculator.prototype.FetchFeats = function() {
	return eval(this.charClass);
}

Calculator.prototype.GetRequiredLevel = function() {
	var maxTier   = 0;
	var reqdLevel = 0;
	
	$each(this.feats.trees, function(tree) { 
		if(tree.maxTier > maxTier)
			maxTier = tree.maxTier;	
	});
	
	if(((maxTier - 1) * 10) > this.reqdLevel[this.ptsSpent]) {
		reqdLevel = (maxTier - 1) * 10;
	} else {
		reqdLevel = this.reqdLevel[this.ptsSpent];
	} 
	
	return reqdLevel;
}

Calculator.prototype.MakeLevelArray = function(start, end, method) {
	this.reqdLevel.push('-');
	
	switch(method) {
		case 'double10s':
			var i = start;
			while(i <= end) {
				this.reqdLevel.push(i);

				if(i % 10 == 0 && i != 10) {
					this.reqdLevel.push(i);
				}
				if(i == 80) {
					this.reqdLevel.push(i);
				}		
				i++;
			}
			break;
	}
}

Calculator.prototype.Start = function(delayActivation) {
	this.MakeTrees();
	this.MakeReqLines();
	this.MakeInfoBox();
	this.UpdateInfoBox();

	if(delayActivation != true) {
		this.feats.MakeActive();
	}	
}

Calculator.prototype.MakeReqLines = function() {
	$each($$('.feat-button'), function(e) {
		var treeFeat = e.getProperty('id');
		var feat = this.feats.Find(treeFeat);

		if(feat.reqs) {
			var reqs = new Array(); 
			
			$each(feat.reqs, function(reqPts, reqId) {
				reqs.push(reqId);
			});
			
			for(var i = 0; i < reqs.length; i++) {
				var reqFeat = this.feats.Find(feat.tree + '-' + reqs[i]) 		

				if(feat.column > reqFeat.column) {
					var lineWidth = (feat.column - reqFeat.column) * 29;
					var line = new Element('div', { 'id': 'feat-req-' + feat.id, 'class': 'feat-req req-x-r',
													'styles': { 'width': lineWidth + 'px', 'left': '-20px' }
										  });
					line.inject(feat.tree + '-' + feat.id, 'after');
				}
				
				if(feat.column < reqFeat.column) {
					var lineWidth = (reqFeat.column - feat.column) * 32;
					var line = new Element('div', { 'id': 'feat-req-' + feat.id, 'class': 'feat-req req-x-l',
													'styles': { 'width': lineWidth + 'px', 'left': '30px' }
										  });
					line.inject(feat.tree + '-' + feat.id, 'after');
				}
				
				if(feat.tier > reqFeat.tier) {
					var lineHeight = (feat.tier - reqFeat.tier) * 66;
					var line = new Element('div', { 'id': 'feat-req-' + feat.id, 'class': 'feat-req req-y',
													'styles': { 'height': lineHeight + 'px' }
										  });
					line.inject(reqFeat.tree + '-' + reqFeat.id, 'after');
				}
				
			}
		}
	}, this);
}

Calculator.prototype.UpdateBuildUrl = function() {
	this.MakeBuildString();
	
	if(this.buildString.length > 0) {
		var url = window.location.href;
		
		if(url.indexOf("#") > -1) {
			var buildStringIdx = url.indexOf("#");
			url = url.slice(0, buildStringIdx);
		}
		
		var lastChar = url.charAt(url.length - 1);
		if(!isNaN(lastChar)) {
			var iter = (url.length - 1);
			for(var i = iter; i >= 0; i--) {
				if(!isNaN(url.charAt(i))) {
					continue;
				} else {
					break;
				}
			}
			
			url = url.substr(0, i);
		}
	
		$('feat-build-link').setProperty('value', url + '#' + this.buildString);
	} else {
		$('feat-build-link').erase('value');
	}
}

Calculator.prototype.UpdateInfoBox = function() {
	$('points_spent').setHTML(this.ptsSpent);
	$('level_required').setHTML(this.GetRequiredLevel());
}

Calculator.prototype.MakeInfoBox = function() {
	var clear = new Element('div', { 'class': 'clear' });
	
	var pointsInfo = new Element('div', { 'id': 'feats-points-info' });
	var spentWrapper = new Element('div', { 'id': 'points-spent-w', 'class': 'left' });
	var levelWrapper = new Element('div', { 'id': 'level-req-w', 'class': 'left' });
	
	var pointsSpentText = new Element('span', { 'id': 'stat-span', 'class': 'left' });
	var levelReqText = new Element('span', { 'id': 'stat-span', 'class': 'left' });
	
	pointsSpentText.setHTML('<b>Points Spent:</b>');
	levelReqText.setHTML('<b>Req. Level:</b>');
	
	var pointsSpent = new Element('span', { 'id': 'points_spent', 'class': 'right' });
	var levelReq = new Element('span', { 'id': 'level_required', 'class': 'right' });
	
	pointsSpent.setHTML('0');
	levelReq.setHTML('-');

	pointsInfo.inject('nav-wrapper', 'top');
	spentWrapper.inject(pointsInfo);
	levelWrapper.inject(pointsInfo);

	pointsSpent.inject(spentWrapper);
	levelReq.inject(levelWrapper);
	pointsSpentText.inject(spentWrapper);
	clear.inject(spentWrapper, 'after');
	levelReqText.inject(levelWrapper);
}

Calculator.prototype.MakeTrees = function() {
	var headersDiv  = new Element('div', { 'id': 'feats-tree-headers' });
	var treesDiv  = new Element('div', { 'id': 'feats-trees' });
	var featsList = new Element('div', { 'id': 'feats-list', 'class': 'feats-list' });
    
    headersDiv.inject('feats');
	treesDiv.inject('feats');
	featsList.inject('footer', 'before');
	
	$each(this.feats.trees, function(tree, treeName) {
		var date1 = new Date();
		this.charClass = this;
		this.treeName  = treeName;
		
		var treeHeaderWrapper = new Element('div', { 'id': treeName + '-header', 'class': 'feat-tree-header' });
		treeHeaderWrapper.inject(headersDiv);
		
		var treeHeaderName = new Element('span', { 'class': 'left' });
		var treeHeaderPoints = new Element('span', { 'id': treeName + '-points', 'class': 'right' });
		var treeHeaderPointsText = new Element('span', { 'class': 'right points-text' });
		var treeHeaderReset = new Element('span', { 'id': treeName, 'class': 'right reset-tree' });
		
		treeHeaderName.setHTML('<b>' + this.treeName.capitalize() + '</b>');
		treeHeaderPoints.setHTML('0');
		treeHeaderPointsText.setHTML('points');
		treeHeaderReset.setHTML('[ reset ]');
		
		treeHeaderName.inject(treeHeaderWrapper);
		treeHeaderReset.inject(treeHeaderWrapper);
		treeHeaderPointsText.inject(treeHeaderWrapper);
		treeHeaderPoints.inject(treeHeaderWrapper);
		
		var featListWrapper = new Element('div', { 'id': treeName + '-list', 'class': 'feats-list listbox' });
		featListWrapper.inject(featsList);
		
		var featListHeader = new Element('span');
		featListHeader.setHTML('<b>Trained Feats</b>');
		featListHeader.inject(featListWrapper);
		
		var treeDiv = new Element('div', { 'id': treeName + '-trees', 'class': 'feat-tree', 
											  'styles': {
										      	'background-image': 'url(http://static.goonheim.com/images/feats/' + 
										      						 this.charClass + '/bg-' + treeName + '.jpg)'
				      						  }
				      					 });
		treeDiv.inject(treesDiv);				      					 
		
		var treeTable = new Element('table', { 'id': 'tree-' + treeName, 'class': 'tree-table' });
		var tableBody = new Element('tbody');
		treeTable.inject(treeDiv);
		tableBody.inject(treeTable);
		
		for(var i = 0; i <= 8; i++) {
			var treeTier = new Element('tr', { 'id': 't' + i });
			treeTier.inject(tableBody);
			
			for(var j = 1; j <= 6; j++) {
				var treeFeat = new Element('td');
				
				if(i == 0) {
					var treeFeatContainer = new Element('div', { 'id': treeName + '-t' + i + 'c' + j, 'class': 'featContainer',
																 'styles': { 'left': '25px' } });
				} else {
					var treeFeatContainer = new Element('div', { 'id': treeName + '-t' + i + 'c' + j, 'class': 'featContainer' });
				}
				
				treeFeat.inject(treeTier);
				treeFeatContainer.inject(treeFeat);
			}
		}

		var featCount = 0;
		for(var z = 0; z < tree.featMap.length; z++) {
			var featId = tree.featMap[z];
			var feat = tree.feats[featId];

			var featButton = new Element('div', { 'id': feat.tree + '-' + feat.id, 'class': 'feat-button', 
											      'styles': {
											      	'background-image': 'url(http://static.goonheim.com/images/feats/' + 
											      						 this.charClass + '/' + this.treeName + '.png)',
											      	'background-position': (featCount * -38) + 'px 0px'
					      						  }
				      					 });
			featCount++;

			if(feat.column == 3.5) {
				feat.column = 3;
			}
			
			var featContainer = this.treeName + '-' + 't' + feat.tier + 'c' + feat.column;
			var featHighlight = new Element('div', { 'id': feat.id + '-highlight', 'class': 'feat-highlight' });
			var featRanks = new Element('div', { 'id': feat.id + '-ranks', 'class': 'feat-rank' });
			var featRank  = new Element('div', { 'id': feat.id + '-rank', 'class': 'feat-rank-numeral', 
					                             'styles': {
													'background-position': (((feat.maxRank-1) * 60) * -1) + 'px -130px'					                             	
					                             }
					                   });
			
			featButton.inject(featContainer);
			featRanks.inject(featContainer);
			featRank.inject(feat.id + '-ranks');
			featHighlight.inject(featContainer);

			feat.UpdateTooltip();
		}
	}, this.charClass);
	
}

/////
///   CLASS: Feats [fets]
/////

function Feats(featsJson) {
	this.trees = new Hash();
	
	this.Load(featsJson);
	
	this.ignoreReqs = 0;
}

Feats.prototype.Find = function(treeFeat) {
	treeFeat = treeFeat.split('-');

	var treeName = treeFeat[0];
	var featId   = treeFeat[1];
	
	var tree = this.trees.get(treeName);
	var feat = tree.feats[featId];
	
	return feat;
}

Feats.prototype.MakeActive = function() {
	$each($$('.feat-button'), function(e) {
		var treeFeat = e.getProperty('id');
		this.Interact('activate', treeFeat);
	}, this);
}

Feats.prototype.Load = function(featsJson) {
	var iterator = 0;
	var curTree  = '';
	
	$each(featsJson, function(feat) {
		if(curTree != feat.tree) {
			iterator = 0;
		}
		
		this.trees.include(feat.tree, new Tree(feat.tree))
		
		var tree = this.trees.get(feat.tree);
		tree.AddFeat(feat, iterator);

		curTree = feat.tree;		
		iterator++;
	}, this);
}

Feats.prototype.Interact = function(action, treeFeat, delayActivation) {
	if(typeof treeFeat != 'object') {
		treeFeat = treeFeat.split('-');
		
		var treeName = treeFeat[0];
		var featId   = treeFeat[1];
			
		var tree = this.trees.get(treeName);
		var feat = tree.feats[featId];
	} else {
		var feat = treeFeat;
		var tree = this.trees.get(feat.tree);
	}

	if(this.ignoreReqs != 1) {
		if(!this.InteractCheck(action, tree, feat)) {
			if(action == 'activate') {
				feat.Deactivate();
			}
			return false
		}	
	}
		
	switch(action) {
		case 'train':
			feat.Increment();
			tree.Increment(feat.tier);

			if(delayActivation != true) {
				this.MakeActive();
			}
			break;
		case 'untrain':
			feat.Decrement();
			tree.Decrement(feat.tier);;

			if(delayActivation != true) {
				this.MakeActive();
			}
			break;
		case 'activate':
			feat.Activate();
			break;
	}
	return true;
}

Feats.prototype.InteractCheck = function(action, tree, feat) {
	switch(action) {
		case 'train':
			if(feat.rank >= feat.maxRank)
				return false
			break;
		case 'untrain':
			if(feat.rank <= 0)
				return false
			break;
	}

	if(!tree.InteractCheck(action, feat.tier))
		return false
	
	switch(action) {
		case 'activate':
		case 'train':
			if(feat.reqs && !tree.CheckReqs(feat.reqs)) {
				return false
			}
			break;
		case 'untrain':
			if(feat.deps && !tree.CheckDeps(feat.deps))
				return false
			break;
	}
	return feat;
}

/////
///   CLASS: Tree [tree]
/////

function Tree(treeName) {
	this.name  = treeName.toLowerCase();

	this.maxTier = 0;
	this.ptDist  = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0); 
	this.feats   = new Hash();
	
	this.featMap = new Array();
}

Tree.prototype.Recalculate = function() {
	$each(this.feats, function(feat) {
		if(feat.rank > 0 && this.maxTier < feat.tier) {
			this.maxTier = feat.tier;
		}
		var featTier = feat.tier;
		this.ptDist[featTier] = this.ptDist[featTier] + Number(feat.rank);
	}, this);
}

Tree.prototype.Reset = function() {
	$each(this.feats, function(feat) {
		if(feat.rank > 0) {
			feat.Reset();
		}
	});
	
	this.ptDist = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0);
	this.maxTier = 0;
	this.UpdateTreePoints();
}

Tree.prototype.UpdateTreePoints = function() {
	$(this.name + '-points').setHTML(array_sum(this.ptDist));
}

Tree.prototype.Increment = function(tier) {
	this.ptDist[tier]++;
	this.UpdateTreePoints();
	
	if(tier > this.maxTier)
		this.maxTier = tier;
}

Tree.prototype.Decrement = function(tier) {
	this.ptDist[tier]--;
	this.UpdateTreePoints();
	
	if(this.ptDist[this.maxTier] == 0)
		this.maxTier--;	
}

Tree.prototype.AddFeat = function(featObj, iterator) {
	var feat = new Feat(featObj, iterator);
	
	var featId = feat.id;
	
	this.feats[featId] = feat;
	this.featMap.push(featId);
}

Tree.prototype.InteractCheck = function(action, featTier) {
	switch(action) {
		case 'activate':
		case 'train':
			if(array_sum(this.ptDist) < (featTier * 5)) {
				return false;
			}
			break;
		case 'untrain':
			if(featTier < this.maxTier) {
				var ptTotal = 0;
				for(var i = (featTier); i >= 0; i--) {
					ptTotal += this.ptDist[i];
				}
				
				if(((featTier + 1) * 5) >= ptTotal) {
					return false;
				} else {
					var ptTotal = 0;
					
					for(var i = (this.maxTier - 1); i >= 0; i--) {
						ptTotal += this.ptDist[i];
					}
	
					if((this.maxTier * 5) >= ptTotal) {
						return false;
					}
				}
			}
			break;
	}
	return true;
} 

Tree.prototype.CheckReqs = function(reqs) {
	var ret = true;
	
	$each(reqs, function(req, reqId) {
		var feat = this.feats[reqId];
		$each(req, function(reqPts) {
			if(this.rank < reqPts) 
				ret = false;			
		}, feat);
	}, this);

	return ret;
}

Tree.prototype.CheckDeps = function(deps) {
	var ret = true;
	
	$each(deps, function(depId) {
		var feat = this.feats[depId];
		if(feat.rank > 0)
			ret = false;
	}, this);
	
	return ret;
}

/////
///   CLASS: Feat [feat]
/////

function Feat(featObj, iterator) {
	if(featObj.column == '3.5') { 
		featObj.column == '3';
	}

	this.id       = featObj.id;
	this.reqLevel = featObj.reqlevel;
	this.name     = featObj.name;
	this.jsname   = featObj.jsname;
	this.tier     = featObj.tier;
	this.tree     = featObj.tree;
	this.column   = featObj.column;
	this.reqs     = featObj.req;
	this.deps     = featObj.dep;
	this.desc     = featObj.desc;
	this.maxRank  = featObj.maxRank;
	this.iterator = iterator;
	 
	this.rank     = 0;
	this.active   = 0;
	
	this.tooltipText = '';
	this.MakeTooltipText();
}

Feat.prototype.MakeTooltipText = function(curLevel) {
	this.tooltipText = '';

	var rank = this.rank - 1;
	
	if(rank == -1) {
		if(this.desc[0]) {
			var rtext = str_replace(',', '<br/>', this.desc[rank+1]);
			var tt = '<div id="tt-gains">';
			tt = tt + '<div id="tt-gains-next">';
			tt = tt + '<span id="tt-rank-text" class="left nextrank-text"><b>Next Rank:</b></span>'
			tt = tt + '<span id="tt-rank" class="left rank">' + (this.rank + 1) + '/' + this.maxRank +'</span>';
			tt = tt + '<div style="clear: both;"></div>';
			
			tt = tt + '<span class="left gain-text" style="text-align: right;"><b>Feat Gain |</b></span>';
			tt = tt + '<span id="tt-rank" class="left gain">' + rtext + '</span>';
			tt = tt + '<div style="clear: both;"></div>';
			
			tt = tt + '</div></div>';
			
			this.tooltipText = this.tooltipText + tt + '<br/><br/>';
		}
	} else {
		if(this.desc[rank]) {
			var rtext = str_replace(',', '<br/>', this.desc[rank]);
			var tt = '<div id="tt-gains">';
			tt = tt + '<div id="tt-gains-cur">';
			tt = tt + '<span id="tt-rank-text" class="left rank-text"><b>Rank:</b></span>'
			tt = tt + '<span id="tt-rank" class="left rank">' + this.rank + '/' + this.maxRank +'</span>';
			tt = tt + '<div style="clear: both;"></div>';
			
			tt = tt + '<span class="left gain-text" style="text-align: right;"><b>Feat Gain |</b></span>';
			tt = tt + '<span id="tt-rank" class="left gain">' + rtext + '</span>';
			tt = tt + '<div style="clear: both;"></div>';
			tt = tt + '</div>';
			
			if(this.rank < this.maxRank && this.desc[rank+1]) {
				var rtext = str_replace(',', '<br/>', this.desc[rank+1]);
				tt = tt + '<div id="tt-gains-next">';
				tt = tt + '<span id="tt-rank-text" class="left nextrank-text"><b>Next Rank:</b></span>'
				tt = tt + '<span id="tt-rank" class="left rank">' + (this.rank + 1) + '/' + this.maxRank +'</span>';
				tt = tt + '<div style="clear: both;"></div>';
				
				tt = tt + '<span class="left gain-text" style="text-align: right;"><b>Feat Gain |</b></span>';
				tt = tt + '<span id="tt-rank" class="left gain">' + rtext + '</span>';
				tt = tt + '<div style="clear: both;"></div>';
			}		
			
			tt = tt + '</div></div>';
			
			this.tooltipText = this.tooltipText + tt + '<br/><br/>';
		}
	}

	this.tooltipText = this.tooltipText + this.desc.base;
	
	if(this.rank == 0) {
		this.tooltipText = this.tooltipText + '<br/><br/><font color=green><b>Click to train. Shift-click to max out this feat.</b></font>';
	}
	
	if(this.reqs && this.active == 0) {
		$each(this.reqs, function(req, reqId) {
			$each(req, function(reqPts, reqName) {
				reqName = str_replace('-', ' ', reqName);
				this.tooltipText = this.tooltipText + '<br/><br/><font color=red><b>REQUIRES:</b> ' 
												    + reqName.capitalize() + ' (' + reqPts + ')';
			}, this);
		}, this);
	}

	if(this.reqLevel > curLevel) {
		this.tooltipText = this.tooltipText + '<br/><br/><font color=red><b>Requires Level:</b> ' + this.reqLevel + '</font>';
	}
	
	if(this.rank > 0) {
		this.tooltipText = this.tooltipText + '<br/><br/><font color=red><b>Right-click or Control-click to untrain. <br/>Shift-right-click to untrain all points.</b></font>';
	}
}

Feat.prototype.UpdateTooltip = function(suppress, curLevel) {
	this.MakeTooltipText(curLevel);
	var featName = str_replace('-', ' ', this.name);
	
	$(this.tree + '-t' + this.tier + 'c' + this.column).store('tip:title', featName.capitalize());
	$(this.tree + '-t' + this.tier + 'c' + this.column).store('tip:text', this.tooltipText);
	
	if(typeof suppress == 'undefined') {
		if($$('div.tip-text')) {
			$$('div.tip-text').setHTML(this.tooltipText);
		}
	}
}

Feat.prototype.Reset = function() {
	this.rank = 0;
	this.UpdateTooltip();
	this.UpdateListrow();
	
	sprite_move(this.id + '-rank', (((this.maxRank-1) * 60) * -1), -130);
}

Feat.prototype.Update = function() {
	this.UpdateListrow();
	sprite_move(this.id + '-rank', (((this.maxRank-1) * 60) * -1), (-130 + (this.rank * 25)));
}

Feat.prototype.Increment = function() {
	if(this.rank != this.maxRank)  {
		this.rank++;
		this.UpdateTooltip();
		this.UpdateListrow();
		
		sprite_move(this.id + '-rank', (((this.maxRank-1) * 60) * -1), (-130 + (this.rank * 25)));
	}
}

Feat.prototype.Decrement = function() {
	if(this.rank != 0)  {
		this.rank--;
		
		this.UpdateTooltip();
		this.UpdateListrow();
		
		sprite_move(this.id + '-rank', (((this.maxRank-1) * 60) * -1), (-130 + (this.rank * 25)));
	}
}

Feat.prototype.UpdateListrow = function() {
	this.aT = 0;
	if(!$(this.tree + '-tier' + this.tier + '-list')) {
		if(!$(this.tree + '-tier' + (this.tier - 1) + '-list') && this.tier != 0) {
			for(var i = (this.tier-1); i >= 0; i--) {
				if($(this.tree + '-tier' + i + '-list')) {
				this.aT = i;
					break;			
				}
			}
		} else {
			if(this.tier != 0) {
				this.aT = (this.tier - 1);
			} else {
				this.aT = 0;
			}
		}
		var featListTierWrapper = new Element('div', { 'id': this.tree + '-tier' + this.tier + '-list', 'class': 'feats-list-tier tier' + this.tier });
		if(this.tier != 0) {
			featListTierWrapper.inject($(this.tree + '-tier' + this.aT + '-list'), 'after');
		} else {
			featListTierWrapper.inject($(this.tree + '-list'));
		}	
	}
	
	if($(this.id + '-listrow')) {
		if(this.rank == 0) {
			$(this.id + '-listrow').dispose();
			return;
		}
		
		$(this.id + '-listrow').empty();		
		
		var featName = new Element('span', { 'class': 'left' });
		var featRank = new Element('span', { 'class': 'right' });
		
		featName.setHTML(this.name);
		featRank.setHTML(this.rank + '/' + this.maxRank);
		
		featName.inject(this.id + '-listrow');
		featRank.inject(this.id + '-listrow');
	} else {
		var listrow = new Element('div', { 'id': this.id + '-listrow', 'class': 'feat-list-row' });
		var featName = new Element('span', { 'class': 'left' });
		var featRank = new Element('span', { 'class': 'right' });
		
		featName.setHTML(this.name);
		featRank.setHTML(this.rank + '/' + this.maxRank);
		
		listrow.inject(this.tree + '-tier' + this.tier + '-list');
		featName.inject(listrow);
		featRank.inject(listrow);
	}
}

Feat.prototype.ChangeArrow = function(action){
	if(!this.reqs)
		return false;
	
	if(action == 'activate') {
		var arrow = 'arrow';
	} else {
		var arrow = 'arrow_gray';
	}
	
	$each(this.reqs, function(req, reqId) {
		var reqFeat = calc.feats.Find(this.tree + '-' + reqId);
		
		if(this.column > reqFeat.column) {
			$('feat-req-' + this.id).setStyle('background-image', 'url(http://static.goonheim.com/images/feats/right_' + arrow + '.png)')
		}
		
		if(this.column < reqFeat.column) {
			$('feat-req-' + this.id).setStyle('background-image', 'url(http://static.goonheim.com/images/feats/left_' + arrow + '.png)')
		}
		
		if(this.tier > reqFeat.tier) {
			$('feat-req-' + this.id).setStyle('background-image', 'url(http://static.goonheim.com/images/feats/down_' + arrow + '.png)')
		}
	}, this);
}

Feat.prototype.Activate = function() {
	if(this.active == 1) {
		return true;
	}
		
	this.active = 1;

	this.UpdateTooltip(true);
	this.ChangeArrow('activate');
	sprite_move(this.tree + '-' + this.id, (this.iterator * -38), -38);
}

Feat.prototype.Deactivate = function() {
	if(this.active == 0) {
		return true;
	}
		
	this.active = 0;

	this.UpdateTooltip(true);
	this.ChangeArrow('deactivate');
	sprite_move(this.tree + '-' + this.id, (this.iterator * -38), 0);
}

/////
///   CLASS: Event Listeners [evnt]
/////

EventListeners = function() {
	this.shift = 0;
	this.logged_in = 0;
	
	this.Tooltips();
	this.FeatButton();
	this.Reset();
	this.ResetTree();
	this.ToggleLock();
	this.ClassDropdown();
	this.ShiftCheck();
	this.SaveLinkBuild();
	this.Login();
}

EventListeners.prototype.Login = function() {
	if($('login-action')) {
		$('login-action').addEvent('click', (function() {
			$('user-login-form').set('send', {url: 'http://f.goonheim.com/user/login', method: 'post',
											  onRequest: function() {
											  	$('login-update').empty();
											  	$('login-form').addClass('loading');
											  	$('user-login-form').setStyle('display', 'none');
											  },
											  onSuccess: function(resp) {
											  	if(resp == 'Login failed') {
											  		$('user-login-form').setStyle('display', 'block');
											  	} else {
											  		var logged_in = new Element('div', { 'id': 'logged_in', 'class': 'logged_in' });
											  		var text = new Element('span');
											  		text.setText('Logged in as: ' + resp);
											  		
													logged_in.inject('header', 'after');										  		
											  		text.inject(logged_in);
											  		$('register').empty();
											  	}
	
											  	$('login-update').empty();
											  	$('login-form').removeClass('loading');
											  }});
			$('user-login-form').send();
			this.logged_in = 1;
		}).bind(this));
	}
}

EventListeners.prototype.SaveLinkBuild = function() {
	$('save-build').addEvent('click', (function(e) {
		if($('logged_in') || this.logged_in == 1) {
			if(calc.saved == 0 && calc.ptsSpent > 0 && calc.modified == 1) {
				var req = new Request({url: 'http://f.goonheim.com/feats/save/' + calc.buildString + '/' + calc.charClass, 
									   onRequest: function() {
									   		$('feat-build-link').setStyle('display', 'none');
									   		$('feat-build-save').setStyle('display', 'inline');
											$('indicator').addClass('loading');
									   },
									   onSuccess: function(buildId) {
									   		$('indicator').removeClass('loading');
									   		if(window.location.href.indexOf("#") > -1 ) {
							   		 			var url = window.location.href.substr(0, window.location.href.indexOf("#"));
									   		} else {
									   			var url = window.location.href;
									   		}
		
											var lastChar = url.charAt(url.length - 1);
											if(!isNaN(lastChar)) {
												var iter = (url.length - 1);
												for(var i = iter; i >= 0; i--) {
													if(!isNaN(url.charAt(i))) {
														continue;
													} else {
														break;
													}
												}
												
												url = url.substr(0, i);
											}
		
									   		$('feat-build-save').setProperty('value', url + '/' + buildId);
									   }
									  }).send();
					calc.saved = 1;
			} else {
				$('feat-build-link').setStyle('display', 'none');
		   		$('feat-build-save').setStyle('display', 'inline');
		   		$('feat-build-save').setProperty('value', 'YOU MUST TRAIN ATLEAST ONE POINT IN A FEAT!');
			}
		} else {
			$('feat-build-link').setStyle('display', 'none');
	   		$('feat-build-save').setStyle('display', 'inline');
			$('feat-build-save').setProperty('value', 'YOU MUST LOG IN FIRST!');
		}
	}).bind(this));
	
	$('link-build').addEvent('click', function(e) {
	   		$('feat-build-save').setStyle('display', 'none');
	   		$('feat-build-link').setStyle('display', 'inline');
	});
}

EventListeners.prototype.ShiftCheck = function(reset) {
	window.addEvent('keydown', function(e) {
		if(e.shift == true) {
			this.shift = 1;
		}
	});
}

EventListeners.prototype.FeatButton = function() {
    $$('div.featContainer').addEvent('mousedown', function(e) {
    	this.shift = 0;
    	
		if(e.shift == true) {
			this.shift = 1;
			e.shift = false;
		}
		
    	e.preventDefault();
    	
		this.oncontextmenu = function() {
			return false;
		}
		
		if($(this).getChildren('.feat-button') != '') {		
			treeFeat = $(this).getFirst().getProperty("id").toLowerCase();
	
			switch(e.rightClick) {
				case false:
					if(e.control == true || this.shift == 1) {
						if(this.shift == 1) {
							for(var i = 0; i < 5; i++) {
								calc.Interact('train', treeFeat);
							}
						} else {
							calc.Interact('untrain', treeFeat);
						}
					} else {
						calc.Interact('train', treeFeat);
					}
					break;
				case true:
					if(this.shift == 1) {
						for(var i = 0; i < 5; i++) {
							calc.Interact('untrain', treeFeat);
						}
					} else {
						calc.Interact('untrain', treeFeat);
					}
					break;
			}
		}
    });
    
    
    $$('div.featContainer').addEvent('mouseover', function(e) {
    	if($(this).getChildren('.feat-button') != '') {
    		treeFeat = $(this).getFirst().getProperty("id");
    		treeFeat = treeFeat.split('-');
    		var featId = treeFeat[1]; 
    		
    		sprite_move(featId + '-highlight', 38, 0);
    	}
    });
    
    $$('div.featContainer').addEvent('mouseout', function(e) {
    	if($(this).getChildren('.feat-button') != '') {
    		treeFeat = $(this).getFirst().getProperty("id");
    		treeFeat = treeFeat.split('-');
    		var featId = treeFeat[1]; 
    		
    		sprite_move(featId + '-highlight', 0, 0);
    	}
    });
}

EventListeners.prototype.Tooltips = function() {
	new Tips('.featContainer', {className: 'tool-tip'});
}

EventListeners.prototype.ClassDropdown = function() {
	$('class-select').addEvent('change', function(e) {
		url = 'http://f.goonheim.com/';
		
		var char_class = $(this).value;
		window.location.href = url + char_class;
	});
}

EventListeners.prototype.Reset = function() {
	$('reset-feats').addEvent('click', function(e) {
		calc.Reset();
	});	
}

EventListeners.prototype.ResetTree = function() {
	$$('span.reset-tree').addEvent('click', function(e) {
		treeName = $(this).getProperty('id');
		calc.Reset(treeName);
	});	
}

EventListeners.prototype.ToggleLock = function() {
	$('togLock-feats').addEvent('click', function(e) {
		calc.Lock('toggle');
	});
}

/////
///   Application Start [apst]
/////

window.addEvent('domready', function() {
	images = new Array('http://static.goonheim.com/images/feats/right_arrow.png', 
					   'http://static.goonheim.com/images/feats/down_arrow.png',
					   'http://static.goonheim.com/images/feats/left_arrow.png');
	preload_images(images);
	var charClass = $('charClass').getText();
	
	calc = new Calculator(charClass, 10, 80, 79);
	
	if(window.location.href.indexOf("#") > -1 ) {
		calc.Start(true);
		
		if(window.location.href.indexOf("#") > -1 ) {
	 		var buildString = window.location.href.substr(window.location.href.indexOf("#"));
	 		buildString = buildString.substr(1);
		}
 		calc.ParseBuildString(buildString);
 		calc.Stasis(true);
	} else {
		var url = window.location.href;
	
		var lastChar = url.charAt(url.length - 1);
		if(!isNaN(lastChar)) {
			var iter = (url.length - 1);
			for(var i = iter; i >= 0; i--) {
				if(!isNaN(url.charAt(i))) {
					continue;
				} else {
					break;
				}
			}
			var buildId = url.substr(i+1, url.length);
			calc.Start(true);
			calc.GetSavedBuild(buildId);

	 		calc.ParseBuildString(calc.buildString);
	 		calc.Stasis(true);
		} else {
			calc.Start();
		}
	}
	
	var listeners = new EventListeners();

});
