/**************************************************************************************************
 *  Ragnarok Online Skill Planner by Guillaume "gn0me" VanderEst <gui@exodusmedia.ca>
 *  Based upon original programming by Jakob "Antialize" Truelsen (www.ragnarokhq.com/skillsim/)
 **************************************************************************************************/

// Constants for splitting the strings passed from PHP..
split_job 		= "~";
split_skill 	= ",";
split_level 	= " ";

function update()
{
	// Cycle through the jobs, force each to update..
	for (i in jobs) {
		job = jobs[i];
		job.update();
	}
}

/***************
* JOB FUNCTIONS
****************/

function job(job_id,job_name,job_points,job_level,job_code)
{
	this.id 		= Number(job_id);		// 0,1,2
	this.job 		= job_level;
	this.code 		= job_code;				// Code for the job "job_id" in the database
	
	this.name 		= job_name 				// "Novice"
	this.maxpoints 	= Number(job_points);	// 49 or 69 at the moment..
	this.points		= 0;					// Points being used
//	this.overflow 	= 0; 					// Points that are being overflowed!

	this.clear		= job_clear;			// Remove all skills for only one job (and those affected by it.)
	this.update 	= job_update;			// Function to update the job's points
	this.skills		= new Array();			// The skills currently loaded
}
function job_update()
{
	// Cosmetically update the table, so that it resizes itself..
	// Hide the skill selector if there's nothing in it.
	selector = gE( "job" + this.job + "_select");

	this.points = 0;
	
	for (skill in skills)
	{
		skill = skills[skill];
		
		if (skill.added)
		{
			if (skill.job == this.id)
			{
				this.points = (Number(this.points) + Number(skill.level));
			}
		} else {
			// lollerskates.
		}		
	}
	
	total = gE("job"+this.id+"_total");
	overflow = gE("job"+this.id+"_overflow");
	remain = gE("job"+this.id+"_remain");

	total.innerHTML = (this.points) + "/" + this.maxpoints;
	if (this.points > this.maxpoints)
	{
		remain.innerHTML 	= 0;
		overflow.innerHTML 	= "<span style='color:red;font-size:14px;'>"+(this.points - this.maxpoints)+"</span>";
	} else {
		remain.innerHTML 	= this.maxpoints - this.points;
		overflow.innerHTML 	= 0;
	}
	
	// TO MAKE THE SKILL LIST KEEP GROWING I ADDED THE FOLLOWING LINES
	// IF YOU DO NOT, THE SKILLS WILL GO OUT OF THE TABLE BOUNDS BECAUSE
	// THE TABLE DOES NOT ALWAYS KEEP GETTING BIGGER WITH THE ADDITION OF SKILLS
	gE("job"+this.id+"_skills").setAttribute( "style" , "height:1px;" );
	gE("job"+this.id+"_skills").setAttribute( "style" , "height:auto;" );
}
function job_clear(job_id)
{
	if (confirm(string_clear))
	{
		for (skill in skills)
		{
			skill = skills[skill];
			if (skill.job == this.id)
			{
				skill.remove();
			}
		}
	}
}
//==================================================================================

function skill(skill_id,skill_name,job_level,skill_levels,skill_requirements,skill_image,skill_implemented)
{
	this.job = Number(job_level);	// 0,1,2 -- Novice, first class, second class.

	this.id = skill_id;				// "idname"
	this.name = skill_name;			// "Full Name"
	this.image = skill_image;		// Image icon
	this.children = new Array();	// Children, which will be checked!
	this.parents = new Array();		// Parents, used for level checking when skills are removed.
	this.skill_requirements = skill_requirements;
	this.requirements = new Array();	// Requirements for the skill.. "sm_bash 1,nv_basic 9"
	this.implemented = Number(skill_implemented);

	this.minlevel = 0;
	this.maxlevel = Number(skill_levels);
	this.level = 0;					// Current level, usually 0

	this.added = false; 			// Currently added?
	this.object = null; 			// Object that is controlled by the skill..

	// Functions..
	this.add = skill_add;			// Add a skill to the calc..
	this.remove = skill_remove;		// Remove a skill from the calc..
	this.info = skill_info;			// Load a window with information on the skill.. or maybe a popup box
	this.update = skill_update;		// Update the level selector.
									
 	// Add the item to the skill select..
	if (list = gE( "job"+this.job+"_select" ))
	{
		list.appendChild ( this.object = document.createElement("option") );
		this.object.setAttribute ("value",this.id);
		this.object.innerHTML = this.name;
//		this.object = gE(this.id);
	}
}

function skill_add()
{
	/* Add a skill.
	 * --------------
	 * - Recursively check for parent skills and add them to PARENTS.
	 * - Update the counter.
	 */
	 if (!this.added)
	 {
		// Skill does not exist on the calculator yet, adding it.
		if (this.maxlevel > 0)
		{
			if ((this.minlevel == 0) && (this.level == 0))
			{
				this.minlevel 	= 1;
				this.level 		= 1;
			}
			// Else, it's already been set by the recursive function below.
		} else {
			// Quest.
			this.minlevel 	= 0;
			this.level 		= 0;
			this.maxlevel	= 0;
		}
		
		// Remove it from the pulldown list.
		this.object.parentNode.removeChild( this.object );

		// + Create row of data.
		list = gE( "job" + this.job + "_skills" );
		list.appendChild ( this.object = document.createElement( "tr" ) );
		this.object.setAttribute("class", "skill_implemented_" + this.implemented);
		// skill_image
 		this.object.appendChild ( td = document.createElement( "td" ) );
		td.setAttribute( "class" , "skill_image" );
		td.appendChild ( skill_image = document.createElement( "img" ) );
		skill_image.setAttribute( "width" , "24" );
		skill_image.setAttribute( "height" , "24" );
		skill_image.setAttribute( "src" , this.image );
		// skill_name
		this.object.appendChild ( td = document.createElement( "td" ) );
		td.setAttribute( "class" , "skill_name" );
		td.setAttribute( "width" , "100%" );
		td.appendChild ( skill_name = document.createElement( "span" ) );
		if (!this.implemented)
			skill_name.innerHTML = "<a href='javascript:skills[\"" + this.id + "\"].info();'>" + this.name + "</a><div class='skill_notes'>( " + string_notimplemented + " )</div><div class='requirements' id='"+this.id+"_requirements'></div>";
		else
			skill_name.innerHTML = "<a href='javascript:skills[\"" + this.id + "\"].info();'>" + this.name + "</a><div class='requirements' id='"+this.id+"_requirements'></div>";
		
		// trashcan
		this.object.appendChild ( td = document.createElement( "td" ) );
		td.setAttribute( "class" , "skill_trash" );
		td.appendChild ( skill_trash = document.createElement( "span" ) );
		skill_trash.innerHTML = "<a href='javascript:skills[\"" + this.id + "\"].remove();'><img src='http://skillsim.gn0.me/img/delete.gif' border=0 alt='' /></a>";
		// skill_level
 		this.object.appendChild ( td = document.createElement( "td" ) );
		td.setAttribute( "class" , "skill_level" );
		td.setAttribute( "id" , this.id + "_level" );
		td.setAttribute( "nowrap" , 1 );

		if (this.maxlevel > 0)
		{
			td.appendChild ( level_select = document.createElement( "select" ) );
			level_select.setAttribute ( "id" , this.id );
	
			if( document.all ) // Internet Explorer
				level_select.attachEvent( "onchange" , change );
			else // Mozilla DOM
				level_select.addEventListener( "click" , change , false );
		
			for (i = 1; i<=this.maxlvl; i++)
			{
				level_select.appendChild ( level_option = document.createElement( "option" ) );
				level_option.setAttribute ( "id" , this.id + "_" + i );
				level_option.setAttribute ( "value" , i );
				level_option.innerHTML = i;
			}
		} else {
			td.appendChild ( level_select = document.createElement( "div" ) );
			level_select.setAttribute ( "class" , "level_quest" );
			level_select.innerHTML = string_quest;
		}
		
		// Recursively check for parent skills.
		if (this.requirements.length)
		{
			tmpRequirements = this.requirements;
			for (requirement in tmpRequirements)
			{
				requirement = this.requirements[requirement];
				
				reqSkill = requirement[0];
				reqLevel = Number(requirement[1]);

				// Make levels for the requirements update.
				if (reqLevel > reqSkill.minlevel)
					reqSkill.minlevel = reqLevel;
				if (reqSkill.minlevel > reqSkill.level)
					reqSkill.level = reqSkill.minlevel;
					
				// Add the requirement and such.
				reqSkill.children[reqSkill.children.length] = this;

				if (!reqSkill.added)
					reqSkill.add();
				else
					reqSkill.update();	
			}	
		}		
		
		printskills[printskills.length] = this;
		
		// Add the skill, all the requirements have been fulfilled.
		this.added = true;
		this.update();
	}
}
function skill_remove()
{
	/* Remove a skill.
	 * -----------------
	 * - Recursively check CHILDREN and force them to remove too.
	 * - Set their levels to 0.
	 * - Update the counter.
	 */
	 if (this.added)
	 {
		// Skill is active, remove it. 
		// Add the item to the skill select..
		this.object.parentNode.removeChild( this.object );

		// Add the item to the skill select..
		if (list = gE( "job"+this.job+"_select" ))
		{
			list.appendChild ( this.object = document.createElement("option") );
			this.object.setAttribute ("value",this.id);
			this.object.innerHTML = this.name;
		}

		// Remove it from the skill list.
		this.added 		= false;
		this.minlevel 	= 0;
		this.level 		= 0;

		// Remove all children skills.
		while (this.children.length)
		{
			child = this.children.shift();
			child.remove();
		}

		// All requirements no longer have to be at their required level, so
		// go through all of them and find out what their minlevel needs to be.
		if (this.requirements)
		{
			for (requirement in this.requirements)
			{
				requirement = this.requirements[requirement][0];
				
				// Set MINLEVEL to 1 (skill is active so needs to be at least 1)
				// and then go through all the children to find which level it needs to be.
				requirement.minlevel = 1;
				
				for (child in requirement.children)
				{
					if (requirement.children[child] == this)
					{
						requirement.children.splice(child,1);
					} else {
						child = requirement.children[child];
							
						for (tmpRequirement in child.requirements)
						{
							tmpRequirement 	= child.requirements[tmpRequirement];
							tmpSkill		= tmpRequirement[0];
							tmpLevel		= Number(tmpRequirement[1]);
							
							if (tmpSkill == requirement)
							{
								if (tmpLevel > requirement.minlevel)
								{
									requirement.minlevel 	= tmpLevel;
								}
							}
						}
					}
				}
				requirement.update();
			}
		}
		
		// Remove it from the printskills list.
		for (i = 0;i<printskills.length;i++)
		{
			printskills = printskills;
			printskill = printskills[i];
			if  (printskill == this)
				printskills.splice(i,1);
		}
	
	}
	
	this.update();
}
function skill_update()
{
	/* Update a skill.
	 * -----------------
	 * - Draw the list of levels. 
	 */

	level_select = gE( this.id );
	if (this.added)
	{	
		if (this.maxlevel > 0)
		{
			if (Number(this.minlevel) == Number(this.maxlevel)) {
				// THERE IS ONLY ONE LEVEL (THE MAX LEVEL) IN THE LIST.. 
				// RATHER THAN DRAW THE WHOLE THING AND REMOVE LIKE 90%
				// OF THE ITEMS, JUST MAKE ONE ITEM..
				
				// CLEAR THE LIST
				for (i = 1; i<=this.maxlevel; i++)
					if (level_option = gE( this.id + "_" + i ))
						level_option.parentNode.removeChild( level_option );
				// ADD ONE ITEM
				level_select.appendChild ( level_option = document.createElement( "option" ) );
				level_option.setAttribute ( "id" , this.id + "_" + this.level );
				level_option.setAttribute ( "value" , this.level );
				if (this.level < 10)
					level_option.innerHTML = this.level + "  ";
				else
					level_option.innerHTML = this.level;
	
				level_select.setAttribute ( "style" , "color: white;font-weight: bold;background-color: #FF0000;" );
				level_select.style.visibility = 'visible';
			} else {
				// THERE ARE MULTIPLE LEVELS
	
				// Clear the list..
				for (i = 1; i<=this.maxlevel; i++)
					if (level_option = gE( this.id + "_" + i ))
						level_option.parentNode.removeChild( level_option );
						
				// Re-add the list..
				for (i = (this.minlevel) ? this.minlevel : 1; i<=this.maxlevel; i++)
				{
					level_select.appendChild ( level_option = document.createElement( "option" ) );
					level_option.setAttribute ( "id" , this.id + "_" + i );
					level_option.setAttribute ( "value" , i );
					if (i < 10)
						level_option.innerHTML = i + "  ";
					else
						level_option.innerHTML = i;
				}
				
				if (level_option = gE( this.id + "_" + this.level ))
					if (document.all)
						level_select.selectedIndex = this.maxlevel-this.minlevel-(this.maxlevel-this.level);
					else
						level_select.selectedIndex = level_option.index;
					
				
				// Make sure the level selector is showing
				level_select.setAttribute ( "style" , "" );
				level_select.style.visibility = 'visible';
			}
			if (Number(this.maxlevel) == 1)
				level_select.setAttribute ( "style" , "color: white;font-weight: bold;background-color: #FF0000;" );
				
			/**
			 * Is this skill required by anything? If so.. write it!
			 */
			reqs = gE(this.id+"_requirements");
			if ((this.id != "nv_basic") && this.children.length)
			{
				reqs.innerHTML = string_requiredby+" ";
				x = 0;
				for (child in this.children)
				{
					x++;
					if (x > 1) reqs.innerHTML = reqs.innerHTML + ", ";
					reqs.innerHTML = reqs.innerHTML + this.children[child].name;
				}
			} else {
				reqs.innerHTML = "";
			}
			/* End of requirement listing.. */
		}
	}
	// Update the job skillpoints counter.
	jobs[this.job].update();
}

function skill_info()
{
	/* A popup window for the skill's information.
	 */
	var skill_info = window.open( "info.php?id=" + this.id , "skill_info","location=0,toolbar=0,menubar=0,scrollbars=1,resizable=1,status=0,width=640,height=480", true);
	skill_info.focus();
}
// ========================================================
function change(e)
{
	/* Pulldown-based level change.
	 * ------------------------------
	 * - When changed, this function is activated.
	 * - Updates the skill's LEVEL value.
	 */
	 
	if( document.all ) //The way to go usning MicrosoftInternetExplore
		object = event.srcElement;
	else //The way to go usning Mozilla Geko DOM
		object = e.currentTarget;
		
	skill = skills[object.id];
	job = jobs[skill.job];

	skill.level = object.value;
	jobs[skill.job].update();
//	update();
}
function add(level)
{
	/* Button based add event..
	 */
	if (loaded)
	{
		list = gE( "job"+level+"_select" );
		if (list.value)
		{
			skill = skills[list.value];
			skill.add();
		}
	}
}
function info(level)
{
	if (loaded)
	{
		list = gE( "job"+level+"_select" );
		if (list.value)
			skills[list.value].info();
	}
}

// =============================================
function build_print()
{
	/* Check the document for ability to print, if so..
	 * then load a page for the skill list output!
	 */
//	cookie = "<?= $_GET["id"]; ?>";		// Start the cookie by defining the job being simulated..
//	cookie += "¿";
	cookie = "";

	jobcount = 0;
	for (job in jobs)
	{
		tmpJobs = jobs;
		job = tmpJobs[job];
		
		jobcount++;
		if (jobcount > 1)
			cookie += "|";
		cookie += job.code;
		cookie += split_job;

		
		skillcount = 0;
		for (skill in printskills)
		{
			tmpSkills = printskills;
			skill = tmpSkills[skill];
			
			if (skill.added && (skill.job == job.id))
			{
				skillcount++;
				if (skillcount > 1)
					cookie += split_skill;	// Skill seperator
				cookie += skill.id;
				cookie += split_level;		// ID/Level seperator
				cookie += skill.level;
	
			}
		}
	}
	var printurl = "print.php?raw=" + cookie;
	var printwindow = window.open( printurl );
//	var printwindow = window.open( printurl, "Ragnarok Online Skill Simulator", "toolbar=1,location=1,directories=0,status=0,menubar=1,scrollbars=1,resizable=1,width=750,height=600", true );
}
function build_cookie()
{
	/* Function to create a cookie of the current build.
	 * ---------------------------------------------------
	 * - Prefix with JOB.ID.
	 */
	cookie = jobid;		// Start the cookie by defining the job being simulated..
	cookie += split_job;

	skillcount = 0;
	for (skill in skills)
	{
		skill = skills[skill];
		if (skill.added)
		{
			skillcount++;
			if (skillcount > 1)
				cookie += split_skill;	// Skill seperator
			cookie += skill.id;
			cookie += split_level;		// ID/Level seperator
			cookie += skill.level;

		}
	}
	return cookie;
}
function build_save()
{
	/* Save the current build!
	 * ------------------------
	 * + Create a cookie string..
	 * + Save the cookie..
	 */
	var expire = new Date();
//	expire.setTime(expire.getTime() + 1000*60*60*24*30); // NEVER EXPIRE, BWAHA
	
//	document.cookie = "name = " + slot.value + "; value\" = " + escape(cookie) + "; expires=" + expire.toGMTString();
//	alert (cookie);
	if (document.all)
		gE("save_list").setAttribute( "value", build_cookie() );
	else
		gE("save_list").value = build_cookie();
//	save_list.value = build_cookie();
	alert(string_save);
}
function build_url()
{
	/* Save the current build!
	 * ------------------------
	 * + Create a cookie string..
	 * + Save the cookie..
	 */
	var expire = new Date();
//	expire.setTime(expire.getTime() + 1000*60*60*24*30); // NEVER EXPIRE, BWAHA
	
//	document.cookie = "name = " + slot.value + "; value\" = " + escape(cookie) + "; expires=" + expire.toGMTString();
//	alert (cookie);
	save_list = gE("save_list");
	cookie = build_cookie();
	while (cookie.indexOf(" ") > -1)
		cookie = cookie.replace(" ","%20");
	prompt(string_url,"http://skillsim.gn0.me/?q="+jobid+"&cookie="+cookie);
}
function build_load(load_force)
{
	/* Load the build from the cookie.
	 * ---------------------------------
	 * - Get the cookie from the textbox.
	 */
	cookie = String(gE("save_list").value).split(split_job);
	
	if ((cookie.length > 1) || (load_force))
	{
		if ((jobid != cookie[0]) && (!load_force))
		{
			if (confirm(string_load_different))
			{
				document.location = "?id="+cookie[0]+"&cookie="+cookie[0]+split_job+cookie[1];
			}
		} else {
			if ((load_force) || (confirm(string_clear)))
			{
				build_clear(true); // skip confirmation
				rawSkills = cookie[1].split(split_skill);
				for (rawSkill in rawSkills)
				{
					rawSkill = rawSkills[rawSkill];
					rawSkill = rawSkill.split(split_level);
					
					if (skill = skills[rawSkill[0]])
					{
						level = Number(rawSkill[1]);
						
						skill.level = level;
						skill.add();
					}
				}
			}
		}
	
		split_job 		= "~";
		split_skill 	= ",";
		split_level 	= " ";
	}
}

function build_clear(clear_skip)
{
	/* Clear the build.
	 * ------------------
	 * - Clear all the job variables.
	 * - Set all skills to unset.
	 * - Set skill levels to 0.
	 * - Set skill children to null.
	 */
	 if (clear_skip || confirm(string_clear))
	 {
		for (skill in skills)
		{
			skills[skill].remove();	
		}
	 }
}

// ===================================================

function init()
{
	/* Initialize the calculator.
	 * ----------------------------
	 * - Split the RAWJOBS and the RAWSKILLS.
	 * - Create objects out of both.
	 */
	joblist = rawjobs.split(split_job);
	for (i=0; i<(joblist.length); i++)
	{
		rawjob = joblist[i].split("|");
		
		job_id 		= rawjob[0];
		job_name 	= rawjob[1];
		job_points 	= rawjob[2];
		job_code 	= rawjob[3];
		job_level 	= i;
		
		jobs[job_id] = new job(job_id,job_name,job_points,job_level,job_code);
		
		filler = gE("job"+job_id+"_filler");
		filler.parentNode.removeChild( filler );
	}

	skill_list = rawskills.split(split_job);
	for (i=0; i<(skill_list.length); i++)
	{
		rawskill = skill_list[i].split("|");
		
		skill_id 				= rawskill[0];
		skill_name 				= rawskill[1];
		skill_job				= rawskill[2];
		skill_max				= rawskill[3];
		skill_reqs				= rawskill[4];
		skill_image				= rawskill[5];
		skill_implemented 	= Number(rawskill[6]);

		skills[skill_id] = new skill(skill_id,skill_name,skill_job,skill_max,skill_reqs,skill_image,skill_implemented);
		// + Add the skill to the job's skill list.
	
		job = jobs[skill_job];
		job.skills[job.skills.length] = skills[skill_id];
	}

	// Make the requirements for the skill into objects.
	for (skill in skills)
	{
		skill = skills[skill];
		skill_requirements = skill.skill_requirements;
		
		if (skill_requirements.length)
		{
			tmpRequirements = skill_requirements.split(",");
			for (i = 0; i < tmpRequirements.length; i++)
			{
				tmpReq 		= tmpRequirements[i].split(" ");
						
				tmpSkill	= tmpReq[0];
				tmpLevel	= tmpReq[1];

				skill.requirements[skill.requirements.length] = new Array(skills[tmpSkill],tmpLevel);
			}
		}
//		skill_requirements = "";
	}

	// loaded var activated
	loaded = true;

	// do the last actions
	update();
	if (gE("save_list").value)
		build_load(true);
}

function error(error,raw)
{
	if (confirm(error + "\n\nWould you like to inform the webmaster of the error?\n(Your information will be kept confidential.)"))
	{
		gE("iframe").src = "http://skillsim.gn0.me/error.php?subject=SKILLSIM ERROR - " + raw;
	}

}
function debug(message)
{
	gE("debug").innerHTML = gE("debug").innerHTML + message + "\n";
}
