// skills.js

/*
  3EProfiler character sheet source file.
  Copyright (C) 2007 Myth-Weavers Games
  **
*/

// void SkillCalcRanks(void)
// Tallies the total number of skill points spent, weighting the ranks in
// each skill with whether or not it's a cross class skill.
//function SkillCalcRanks()
//{
//	var total = 0;
//	// Calculate the total ranks.
//	var slots = document.getElementById("skills").rows.length - 2;
//
//	for (var i = 1; i <= slots; i++)
//	{
//		var num = FormatNumber(i);
//		total += GetNum(sheet()["Skill" + num + "Rank"]) * (sheet()["Skill" + num + "CC"].checked ? 2 : 1);
//	}
//
//	// Set the value.
//	document.getElementById("totalbaseranks").innerHTML = total;
//	document.getElementById("totalforceranks").innerHTML = total;
//
//}

// void SkillCalc(node)
// Recalculates the skill modifier for a skill. Function expects one of
// the input nodes for the skill row to be passed to it.
function SkillCalc(node)
{

	// Determine which skill is being adjusted (the first 7 chars of the
	// node name are always "SkillXX", regardless of which row the input is
	// from.
	var skill = String(node.name).substr(0, 7);
	var trained = 0;
	var skillFocus = 0;
	var cond = parseInt(sheet()["CondVal"].value);
	
	if (sheet()[skill + "Trained"].checked) {
		trained = 5;
	}
	if (sheet()[skill + "SkillFocus"].checked) {
		skillFocus = 5;
	}

	ZeroFill(
		sheet()[skill + "AbMod"],
		sheet()[skill + "HalfLevel"],
		sheet()[skill + "MiscMod"]);

	sheet()[skill + "Mod"].value = Add(
		sheet()[skill + "AbMod"].value,
		sheet()[skill + "HalfLevel"].value,
		trained,
		skillFocus,
		cond,
		sheet()[skill + "MiscMod"].value);
	
	if (sheet()[skill].value == "initiative") {
		sheet()["InitTotalMod"].value = sheet()[skill + "Mod"].value;
	}
}

// void SkillLookUp(node)
// Performs a lookup of the skill name to try to find the skill's
// primary ability. If the skill is found, the ability is set then the
// onchange events for the ability modifier is triggered.
function SkillLookUp(node, extended)
{

	// Parse the info from the node.
	var skill = GetText(node);

	if (typeof skillKeys[skill] == "undefined")
	{
		return;
	}

	sheet()[node.name + "Ab"].value = abilityKeys[skillKeys[skill][0]];

	if (skillKeys[skill][1] == 1 && extended) {
		sheet()[node.name + "D"].checked = true;
	}

//	if (extended)
//		sheet()[node.name + "Feat"].value = skillKeys[skill][2];

	// Determine if the skill is a class skill or not.
	// if (classSkills[node.value])
	//   node.parentNode.parentNode.cells[2].firstChild.checked = _getClassBitSet() & classSkills[node.value] ? "" : "checked";
	SkillLookUpKeyAb(sheet()[node.name + "Ab"]);
}

// void SkillLookUpKeyAb(node)
// Retrieves the skills key ability modifier and recalculates the skill
// modifier accordingly. The node passed to this function should be the
// Key Ability node.
function SkillLookUpKeyAb(node)
{

	// Can't make any assumptions about the node value, since the user may
	// have written anything.
	var ability = GetText(node);
  
	if (ability == "str") ability = "Str";
	else if (ability == "dex") ability = "Dex";
	else if (ability == "con") ability = "Con";
	else if (ability == "int") ability = "Int";
	else if (ability == "wis") ability = "Wis";
	else if (ability == "cha") ability = "Cha";
	else
	{
		// Not a valid ability name.
		return;
	}

	// If we don't have a modifier, return without doing anything else.
	if (!(sheet()[ability + "Mod"].value.length || sheet()[ability + "TempMod"].value.length))
		return;

	// Determine if skill is cross-class.
//	var skillRow = node.parentNode.parentNode;

//	// If the skill name is found in our classSkills hash.
//	if (classSkills[skillRow.cells[0].firstChild.value])
//		// Set the CC checkbox accordingly.
//		skillRow.cells[8].firstChild.checked = _getClassBitSet() & classSkills[skillRow.cells[0].firstChild.value] ? "" : "checked";

	// If a temp mod exists, use it, otherwise use the regular one.
	var mod = String(sheet()[ability + "TempMod"].value).length > 0
		? GetNum(sheet()[ability + "TempMod"])
		: GetNum(sheet()[ability + "Mod"]);
		sheet()[node.name + "Mod"].value = mod;


	SkillCalc(node);
}

// void SkillSort(sortfunc)
// Sorts the skill table according to the sorting function that is passed
// to sortfunc. SkillSort contains members that can act as sorting
// functions for the Array.sort() member.
function SkillSort(sortfunc)
{
	// Create a shortcut to the rows of the skills table.
	var rows = document.getElementById("skills").rows;

	// Now copy all the data in each row (the first two are headers and
	// the last is a footer).
	var rows_c = new Array();
	for (var i = 2; i < rows.length - 1; i++)
	{
		r = new Object();
		r.skill = rows[i].cells[0].firstChild.value;
		r.ab = rows[i].cells[1].firstChild.value;
		r.mod = rows[i].cells[2].firstChild.value;
		r.half = rows[i].cells[4].firstChild.value;
		r.abmod = rows[i].cells[6].firstChild.value;
		r.trained = rows[i].cells[8].firstChild.checked;
		r.skillfocus = rows[i].cells[10].firstChild.checked;
		r.misc = rows[i].cells[12].firstChild.value;
		rows_c.push(r);
	}

	// Sort the data.
	rows_c.sort(sortfunc);

	// Now, restore the sorted data.
	for (var i = 2; i < rows.length -1; i++)
	{
		var r = rows_c.shift();
		rows[i].cells[0].firstChild.value = r.skill;
		rows[i].cells[1].firstChild.value = r.ab;
		rows[i].cells[2].firstChild.value = r.mod;
		rows[i].cells[4].firstChild.value = r.half;
		rows[i].cells[6].firstChild.value = r.abmod;
		rows[i].cells[8].firstChild.checked = r.trained;
		rows[i].cells[10].firstChild.checked = r.skillfocus;
		rows[i].cells[12].firstChild.value = r.misc;
	}

	//now do it again for the force skills
//	rows = document.getElementById("forceskills").rows;
//	rows_c = new Array();
//	for (var i = 2; i < rows.length - 3; i++)
//	{
//		r = new Object();
//		r.skill = rows[i].cells[0].firstChild.value;
//		r.ab = rows[i].cells[1].firstChild.value;
//		r.d = rows[i].cells[2].firstChild.checked;
//		r.feat = rows[i].cells[3].firstChild.value;
//		r.cc = rows[i].cells[4].firstChild.checked;
//		r.mod = rows[i].cells[5].firstChild.value;
//		r.abmod = rows[i].cells[7].firstChild.value;
//		r.rank = rows[i].cells[9].firstChild.value;
//		r.misc = rows[i].cells[11].firstChild.value;
//		rows_c.push(r);
//	}

//	// Sort the data.
//	rows_c.sort(sortfunc);
//
//	// Now, restore the sorted data.
//	for (var i = 2; i < rows.length-2; i++)
//	{
//		var r = rows_c.shift();
//		rows[i].cells[0].firstChild.value = r.skill;
//		rows[i].cells[1].firstChild.value = r.ab;
//		rows[i].cells[2].firstChild.checked = r.d;
//		rows[i].cells[3].firstChild.value = r.feat;
//		rows[i].cells[4].firstChild.checked = r.cc;
//		rows[i].cells[5].firstChild.value = r.mod;
//		rows[i].cells[7].firstChild.value = r.abmod;
//		rows[i].cells[9].firstChild.value = r.rank;
//		rows[i].cells[11].firstChild.value = r.misc;
//	}

}

SkillSort.ByName = function(a, b)
{
	if ((a.skill.length == 0) && (b.skill.length == 0))
		return 0;
	else if (a.skill.length == 0)
		return 1;
	else if (b.skill.length == 0)
		return -1;
	return a.skill.localeCompare(b.skill);
}

SkillSort.ByAbility = function(a, b)
{
	if ((a.ab.length == 0) && (b.ab.length == 0))
		return SkillSort.ByName(a, b);
	else if (a.ab.length == 0)
		return 1;
	else if (b.ab.length == 0)
		return -1;

	// Custom order:
	var key = {'str': 1, 'dex': 2, 'con': 3, 'int': 4, 'wis': 5, 'cha': 6};
	var comp = key[a.ab.toLowerCase()] - key[b.ab.toLowerCase()];
	if (comp)
		// If different, return the comparison.
		return comp;
	else
		// If equal, return the result of sorting by name.
		return SkillSort.ByName(a, b);
}

SkillSort.ByTrained = function(a, b)
{
	if (a.trained && b.trained)
		return SkillSort.ByName(a, b);
	else if (!a.trained && !b.trained)
		return SkillSort.ByName(a, b);
	else
		return a.trained ? -1 : 1;
}

SkillSort.BySkillFocus = function(a, b)
{
	if (a.skillfocus && b.skillfocus)
		return SkillSort.ByName(a, b);
	else if (!a.skillfocus && !b.skillfocus)
		return SkillSort.ByName(a, b);
	else
		return a.skillfocus ? -1 : 1;
}

SkillSort.ByMod = function(a, b)
{
	return SkillSort._ByNumber(a, b, "mod");
}

SkillSort.ByAbMod = function(a, b)
{
	return SkillSort._ByNumber(a, b, "abmod");
}

SkillSort.ByMisc = function(a, b)
{
	return SkillSort._ByNumber(a, b, "misc");
}

SkillSort._ByNumber = function(a, b, prop)
{
	numa = parseFloat(a[prop]);
	numb = parseFloat(b[prop]);
	if ((isNaN(numa)) && (isNaN(numb)))
		return SkillSort.ByName(a, b);
	else if (isNaN(numa))
		return 1;
	else if (isNaN(numb))
		return -1;
	if (numa == numb)
		return SkillSort.ByName(a, b);
	else
		return (numa > numb) ? -1 : 1;
}

// Fill the skill table with the core SWRPG skill set.
function SkillAutoFill()
{

	// Verify before continuing.
	if (!confirm("AutoFill will initialize the skill table with the core SWRPG skill set. This will clear any existing data.\n\nAre you sure you want to continue?"))
		return;

	// First clear the table.
	_skillClear();
	_skillFill();
}

// Clear the entire skill table.
function SkillClear()
{

	// Verify before actually clearing.
	if (!confirm("Clearing the skill table will remove ALL skill data.\n\nAre you sure you want to continue?"))
		return;

	_skillClear();
//	SkillCalcRanks();
}

// Update the cross-class checkboxes according to the class information.
//function SkillsUpdateCC()
//{
//	if (!confirm("UpdateCC will compare your skills against the classes the your character has been assigned and determine if each skill is a class skill or not. This method will usually only work for skills that have been assigned via AutoFill and for the core SWRPG lasses...\n\nDo you wish to continue?"))
//		return;
//
//	// Create a shortcut to the rows of the skills table.
//	var rows = document.getElementById("skills").rows;
//	var classes = _getClassBitSet();
//	var unresolved = new Array();
//	for (var i = 2; i < rows.length - 1; i++)
//	{
//		if (i==42)
//			continue;
//		var skill_name = rows[i].cells[0].firstChild.value;
//		var skill_cc = rows[i].cells[4].firstChild;
//		if (skill_name.length == 0)
//			continue;
//		if (classSkills[skill_name])
//			skill_cc.checked = classes & classSkills[skill_name] ? "" : "checked";
//		else if (forceSkills[skill_name])
//			skill_cc.checked = classes & forceSkills[skill_name] ? "" : "checked";
//		else
//			unresolved.push(skill_name);
//	}
//
//	SkillCalcRanks();
//
//	if (unresolved.length > 0)
//	{
//		var msg = "Failed to resolve the following skills:\n";
//		for (var i in unresolved)
//			msg += unresolved[i] + ", ";
//		//alert(msg);
//	}
//}

//////////////////////////////////////////////////////////////////////////
// Internal functions

// Clear the skill table.
function _skillClear()
{
	var rows = document.getElementById("skills").rows;
	for (var i = 2; i < rows.length - 1; i++)
	{
		rows[i].cells[0].firstChild.value = '';
		rows[i].cells[1].firstChild.value = '';
		rows[i].cells[2].firstChild.value = '';
		rows[i].cells[4].firstChild.value = '';
		rows[i].cells[6].firstChild.value = '';
		rows[i].cells[8].firstChild.checked = false;
		rows[i].cells[10].firstChild.checked = false;
		rows[i].cells[12].firstChild.value = '';
	}

}

// Fill the skill table with the SWRPG skillset.
function _skillFill()
{
	var row = 2;
	var skilltable = document.getElementById("skills");
	row = 2;
	for (var skill in skillKeys)
	{
		// Don't actually print out the language skill.
		if (skill == 'Speak Language')
			continue;

		// Don't alter if we already have some data.
		// (Can happen from an legacy character on first load).
		if (skilltable.rows[row].cells[0].firstChild.value)
			continue;

		// Set the skill and the key ability.
		skilltable.rows[row].cells[0].firstChild.value = skill;
		SkillLookUp(skilltable.rows[row].cells[0].firstChild, false);
		row++;
	}
	CalcHalfLevel();
}

// void _calcSkills(ability)
// Resets the ability modifier and recalculates the skills whose key
// ability match skillname.
function _calcSkills(ability)
{
	var numskills = document.getElementById("skills").rows.length - 2;
	for (var i = 1; i <= numskills; i++)
	{
		var num = FormatNumber(i);
		if (String(sheet()["Skill" + num + "Ab"].value).toLowerCase() == ability)
			SkillLookUpKeyAb(sheet()["Skill" + num + "Ab"]);
	}
}

// number CalcHalfLevel()
// Returns the rounded number calculated from the character level.
function CalcHalfLevel()
{
	var halfLevel = parseInt(sheet()["Level"].value);
	
	if (isNaN(halfLevel))
		return;
	
	if ((halfLevel % 2) == 1)
		halfLevel--;
		
	halfLevel = halfLevel / 2;
	
	var numskills = document.getElementById("skills").rows.length - 2;
	for (var i = 1; i <= numskills; i++)
	{
		var num = FormatNumber(i);
		sheet()["Skill" + num + "HalfLevel"].value = halfLevel;
		SkillCalc(sheet()["Skill" + num + "HalfLevel"]);
	}
}

function ConditionPenalty(node)
{
	var val = 0;
	
	switch (String(node)) {
		case "2":
		val = -1;
		break
		case "3":
		val = -2;
		break
		case "4":
		val = -5;
		break
		case "5":
		val = -10;
		break
		default:
		val = 0;
	}
	
	sheet()["CondVal"].value = val;
}

function ChangeCondition()
{
	var numskills = document.getElementById("skills").rows.length - 2;
	for (var i = 1; i <= numskills; i++)
	{
		var num = FormatNumber(i);
		SkillCalc(sheet()["Skill"+num]);
	}
	
	SaveCalc("Fort");
	SaveCalc("Reflex");
	SaveCalc("Will");
}