function customOnLoad() {
    // Insert custom code here

	if (equalsIgnoreCase(applicationName,"plantest")) {
		if (equalsIgnoreCase(formName,"TestForm")) {

		    z_custom_repeatMbrLabels();

		}
	}
}

function validateForm()
{
	// Insert custom code here
	return true;
}
function customSaveFormPost() {
    // Insert custom code here
    return;
}

function drawCustomButtons() {
	// This function is called when the data entry page is being created. It allows the addition of
    // custom button(s) to the UI of this page. The custom buttons will appear on the same row as the
    // Save, Refresh, etc. buttons after all of the built-in buttons.
    //
    // Custom buttons may either be links to other web resources (HTML, PDF, etc) or they may be set up to
    // launch further custom JavaScript code.
    //
	// use DrawCmdBtn(btnId, stText, stHRef, stClick, stToolTip) where
	//		sText = the text which appears on the button
	//		stHRef = the URL which the browser will go to if the button is clicked (use null if invoking a JavaScript function)
	//		stClick = the JavaScipt code to be executed when the button is clicked (use null if using a URL)
	//		stTooltip = the tooltip which appears if the mouse hovers over the button
	
	
	if (equalsIgnoreCase(applicationName,"plantest")) {
		//if (equalsIgnoreCase(formName,"TestForm")) {

		    // if you are displaying multiple buttons, you can use a table to organize the layout
			document.writeln('<table cellspacing=0 cellpadding=0 border=0><tr><td>');

			// the DrawCmdBtn produces a simple button along the lines of the Save button.
			// the parameters are a label for the button itself
			// the URL to open when the button is clicked
			// the JavaScript to run when the button is clicked
			// the tooltip which displays when the user hovers over the button with the mouse
			// the URL or the JavaScript can be empty or they can be used together
			// the following code creates a button which, when clicked, will open the pdf file
			// BudgetProcess.pdf in the current window.
			//DrawCmdBtn("BudgetBtn", "Budgeting Process", "BudgetProcess.pdf", "", "View the budgeting process guidelines");


			DrawCmdBtn("CustomHighlightBtn", "Highlight Rows", null, "z_custom_highlight_rows()", "Highlights rows containing partial given string");

			document.writeln('</td><td>&nbsp;</td><td>');

			// the following code creates a button which, when clicked, will run the
			// JavaScript method called userValidate (defined below).
			DrawCmdBtn("CustomSearchBtn1", "Search Row", null, "z_custom_row_search(true)", "Search for first row containing partial given string");
			
			document.writeln('</td><td>&nbsp;</td><td>');
			
			DrawCmdBtn("CustomSearchBtn2", "Find Next", null, "z_custom_row_search(false)", "Search for next row containing partial given string");

			document.writeln('</td></tr></table>');
		//}
	}
}

function customCellEnterPre(row, col, cell) {
	// Insert custom code here
	return true;
}

function customCellEnterPost(row, col, cell) {
	// Insert custom code here
	return;
}

function customCellValidatePre(row, col, cell) {
	// Insert custom code here
	return true;
}

function customCellValidatePost(row, col, cell) {
	// Insert custom code here
	return;
}

function customSpread_Pre(row,col) {
    // Insert custom code here
    return true;
}

function customSpread_Post(row,col) {
    // Insert custom code here
    return;
}

// ========================================================

var z_custom_last_search_match = ""; //page variable needed to reset previous search
var z_custom_last_search_color = ""; //page variable needed to reset previous search
var z_custom_last_search_borderColor = ""; //page variable needed to reset previous search
var z_custom_last_search_borderStyle = ""; //page variable needed to reset previous search
var z_custom_last_search_borderWidth = ""; //page variable needed to reset previous search
var z_custom_last_search_fontWeight = ""; //page variable needed to reset previous search

var z_previous_search_string = "";
var z_arr_previous_matches = new Array();


function z_custom_row_search(reset_search)
{
	/*
	Author: Dragos Matachescu
	Hyperion Planning version: 9.3.1
	Copyright: free for all, no guarantees etc.
	Description:
	
	Function finds first match of a row header containing a given text.

	The rows of the form are inside the div id="rowHeadDiv_0" and the cells inside the div id="dataDiv_0". Both divs are scrollable, but the cells div controls the scrolling of the rows div, and not the other way around (that is why searching for the row name with the default browser scrolls only the rows div and not the cells div. 

	So:
	- search in the content of the rows div to identify the id of the row header that contains the searched string. It will be something like id=V_0_127x0 - no double quotes ! (even if html source shows them)
	- obtain the id of the div of the first cell in the row by replacing x0 with x1  (V_0_127x0 becomes V_0_127x1)
	- inject a dummy focusable element in the cell
	- focus on that element, this will force the browser to scroll the cells div, which will trigger the scroll of the rows div.
	- remove the dummy element.

	*/

	//<div id="rowHeadDiv_0" class=rowHead > ... <DIV id="V_0_127x0" title="350000"><IMG SRC="Images/spacer.gif" HEIGHT=1 WIDTH=30 alt="">350000</DIV> ... </div>
	//<div id="dataDiv_0" class="data" > ... <td><DIV class="" id="V_0_127x1"><nobr>400</nobr></DIV></td> ... </div>

	//<DIV id="V_0_248x0" title="350000">
	//<DIV class="" id="V_0_248x2">

	//<DIV id="V_0_126x1" title="350000">
	//<td><DIV class="" id="V_0_126x2"><nobr>400</nobr></DIV></td>

	var z_row_div, z_s, z_re, z_rows_div_initial_html, z_arr, z_row_id, i;
	var z_cell_id, z_cell_div, z_cell_div_initial_html, z_cell_div_initial_html, z_cell_div_NEW_html, z_bullseye, z_cell_found;

	if(reset_search)
	{
		z_previous_search_string = "";
		z_arr_previous_matches = new Array(); //reset array of previous matches
	}


	//reset previous search
	z_row_div = document.getElementById(z_custom_last_search_match);
	if(z_row_div) 
	{
		z_row_div.style.color = z_custom_last_search_color;
		z_row_div.style.borderColor = z_custom_last_search_borderColor;
		z_row_div.style.borderStyle = z_custom_last_search_borderStyle;
		z_row_div.style.borderWidth = z_custom_last_search_borderWidth;
		z_row_div.style.fontWeight = z_custom_last_search_fontWeight;
	}


	if(z_previous_search_string == "" && reset_search)
	{
		z_s = window.prompt("Enter partial row name to search for (string must contain only 0-9a-zA-Z_):","");
		z_previous_search_string = z_s;
		z_arr_previous_matches = new Array();
	}
	else
		z_s = z_previous_search_string;


	if(z_s)
	{
		//-- clean search string, allow only 0-9,a-z,A-Z,_ characters
		z_re = new RegExp("[\\W]+", "gi");
		z_s = z_s.replace(z_re, "");

		//-- search for target row
		z_rows_div = document.getElementById("rowHeadDiv_0");
		z_rows_div_initial_html = z_rows_div.innerHTML;
		//window.prompt("found", z_rows_div_initial_html); // ... in fact is <DIV id=V_0_127x0 title=350000> that needs to be searched, not <DIV id="V_0_127x0" title="350000"> as html source of the page shows - useful to the guy that will port this to some new Planning version...
		
		z_re = new RegExp("<DIV id=([\\w]+x[\\w]+) title=[^>]*" + z_s + "[^>]*>", "gi");
		
		z_arr = z_re.exec(z_rows_div_initial_html);
		
		var z_new_match_found = false;

		while(z_arr && !z_new_match_found)
		{
			if(z_arr.length > 1)
			{
				//evaluates the finding, if is not in the array, add it, otherwise search next
				z_row_id = z_arr[1];
				//window.alert(z_row_id);
				if(!z_is_in_arr_previous_matches(z_row_id))
				{
					z_new_match_found = true;
					z_arr_previous_matches.push(z_row_id);
					z_custom_last_search_match = z_row_id;
					
					//-- paint the text in red
					z_row_div = document.getElementById(z_row_id);
					z_custom_last_search_color = z_row_div.style.color;
					z_custom_last_search_borderColor = z_row_div.style.borderColor;
					z_custom_last_search_borderStyle = z_row_div.style.borderStyle;
					z_custom_last_search_borderWidth = z_row_div.style.borderWidth;
					z_custom_last_search_fontWeight = z_row_div.style.fontWeight;
					z_row_div.style.color="red";
					z_row_div.style.borderColor = "red";
					z_row_div.style.borderStyle = "dashed";
					z_row_div.style.borderWidth = "thin";
					z_row_div.style.fontWeight = "bold";
					


					z_cell_id = "";
					z_cell_div = "";
					z_cell_div_initial_html = "";

					//-- search first nearby data cell (for the case we have more than one dimensions as row headers)
					z_cell_found = false;
					for(i=0; i<22; i++) //cannot have more than 22 dimensions on rows anyway, we will find something for sure, also it always is at least one column of cells
					{
						z_cell_id = z_row_id.replace(/x[0-9]+/, "x" + i);
						z_cell_div = document.getElementById(z_cell_id);
						if(z_cell_div)
						{
							z_cell_div_initial_html = z_cell_div.innerHTML;
							if (z_cell_div_initial_html.search(/<nobr>/i) != -1) //<nobr> is in all data cells ... if Hyperion will not use that in the future, bad luck then
							{
								z_cell_div_NEW_html = "<input type=\"text\" size=\"1\" id=\"z_bullseye\">" + z_cell_div_initial_html;
					
								//-- inject html
								z_cell_div.innerHTML = z_cell_div_NEW_html;

								//-- focus on element to force automatic browser scroll
								z_bullseye = document.getElementById("z_bullseye");
								z_bullseye.focus();

								//-- redo html
								z_cell_div.innerHTML = z_cell_div_initial_html;

								z_cell_found = true;

								break;
							}
						}
					}

					if(!z_cell_found)
					{
						window.alert("You have some weird form or is not proper version of Planning! \n Please contact application administrator and report this error!");
						z_previous_search_string = "";
						z_arr_previous_matches = new Array();
						break; //we don't search for more matches, otherwise we will get this popup for each occurence
					}
				}
			}
			
			z_arr = z_re.exec(z_rows_div_initial_html);
		}


		if(!z_new_match_found)
		{
			window.alert("No match found !");

			z_arr_previous_matches = new Array(); //reset array of previous matches, further "Find Next" action will start from beginning.
		}
	}
}

//--------------

function z_is_in_arr_previous_matches(z_row_id)
{
	var i;
	for(i=0; i < z_arr_previous_matches.length; i++)
		if(z_arr_previous_matches[i] == z_row_id)
			return true;

	return false;
}

//--------------

function z_custom_highlight_rows()
{
	/*
	Author: Dragos Matachescu
	Hyperion Planning version: 9.3.1
	Copyright: free for all, no guarantees etc.
	Description:

	Function works in a similar way with z_custom_row_search, but:
	- it does not scroll the form.
	- it finds all occurences of given search strings in the rows headers and highlights the rows

	Function is helpful in a form that has supress missing data to highlight the rows that appear only from time to time (for example, highlight adjustment accounts in a form that shows also the adjusted accounts, and only a few of the accounts are adjusted).

	*/

	var z_s, z_color, z_re, z_rows_div, z_rows_div_initial_html, z_arr, matches_found, z_row_id;

	z_s = window.prompt("Enter partial row name to search for (you can repeat this operation for more names, string must contain only 0-9a-zA-Z_):","");
	if(z_s)
		z_color = window.prompt("Write color code to highlight (ex: red, yellow, blue):","blue");

	if(z_s && z_color)
	{
		//-- clean search string, allow only 0-9,a-z,A-Z,_ characters
		z_re = new RegExp("[\\W]+", "gi");
		z_s = z_s.replace(z_re, "");

		//-- search for target rows
		z_rows_div = document.getElementById("rowHeadDiv_0");
		z_rows_div_initial_html = z_rows_div.innerHTML;
		//window.prompt("found", z_rows_div_initial_html); // ... in fact is <DIV id=V_0_127x0 title=350000> that needs to be searched, not <DIV id="V_0_127x0" title="350000"> as html source of the page shows - useful to the guy that will port this to some new Planning version...
		
		z_re = new RegExp("<DIV id=([\\w]+x[\\w]+) title=[^>]*" + z_s + "[^>]*>", "gi");
		
		z_arr = z_re.exec(z_rows_div_initial_html);
		matches_found = 0;
		while(z_arr)
		{
			if(z_arr.length > 1)
			{
				z_row_id = z_arr[1];
				//window.alert(z_row_id);
				
				//-- paint the text in color
				z_row_div = document.getElementById(z_row_id);
				z_row_div.style.color = z_color;
				z_row_div.style.fontWeight = "bold";

				matches_found += 1;
			}

			z_arr = z_re.exec(z_rows_div_initial_html);
		}

		if(matches_found == 0)
			window.alert("No match found !");
		else
			window.alert("Found " + matches_found + " matches.");
	}
}


//--------------

//Selection of Rows and Columns
function z_custom_rowHeadClick(targetObj, gridIndex, event) 
{
	/*
	Author: Hyperion
	Co-author: Dragos Matachescu
	Hyperion Planning version: 9.3.1
	Copyright: free for all, no guarantees etc.
	Description: helper function for function z_custom_repeatMbrLabels()
	*/

    setCurrentGrid(gridIndex);
	//var eventSource = event.srcElement || event.target || event.currentTarget; // original Hyperion version which does not allow embedded tables
	var eventSource = targetObj;
	eventSource = getEnclosingHeader(eventSource);
	if (eventSource) {
		var row = getRowFromObject(eventSource, 2);
		var span = eventSource.rowSpan;
		if ((!isFinite(span)) || (span <= 0)) {
			span = 1;
		}
		if (event.shiftKey) {
			selectEndRows(row,row + (span - 1));
		} else {
			selectStartRows(row,row + (span - 1));
		}
	}
}

//--------------

function z_helper_createNewTHInnerHTML(p6, p8, has_spacer)
{
	/*
	Author: Dragos Matachescu
	Hyperion Planning version: 9.3.1
	Copyright: free for all, no guarantees etc.
	Description: helper function for function z_custom_repeatMbrLabels()
	*/

	var i, re, new_p8;

	/* clean p8 of ids */
	re = new RegExp("id=([^ ]+)", "gi");
	p8_no_id = p8.replace(re, " ");

	if(has_spacer == 0)
	{
		new_p8 = '<TABLE class=outsideLeft cellSpacing=0 cellPadding=0 border=0 width="100%">';
		new_p8 = new_p8 + '<tr><td class=rowHeader_2 style="height:23;">' + p8 + "</td></tr>" + "\n"; //need to use <td> instead of <th> to avoid entering infinite loop because of arr_row_headers = rows_div.getElementsByTagName("th"); for(i=0; i<arr_row_headers.length; i++)

		for(i=1; i<parseInt(p6); i++)
			if(i == (parseInt(p6) - 1))
				new_p8 = new_p8 + '<tr><td class=rowHeader_2 style="height:25;">' + p8_no_id + "</td></tr>" + "\n";
			else
				new_p8 = new_p8 + '<tr><td class=rowHeader_2 style="height:25;">' + p8_no_id + "</td></tr>" + "\n";
		new_p8 = new_p8 + "</TABLE>";
	}
	else
	{
		new_p8 = '<TABLE class=outsideLeft cellSpacing=0 cellPadding=0 border=0 width="100%">';
		new_p8 = new_p8 + '<tr><td class=rowHeader_2 style="height:24;">' + p8 + "</td></tr>" + "\n"; //need to use <td> instead of <th> to avoid entering infinite loop because of arr_row_headers = rows_div.getElementsByTagName("th"); for(i=0; i<arr_row_headers.length; i++)

		for(i=1; i<parseInt(p6); i++)
			if(i == (parseInt(p6) - 1))
				new_p8 = new_p8 + '<tr><td class=rowHeader_2 style="height:24;">' + p8_no_id + "</td></tr>" + "\n";
			else
				new_p8 = new_p8 + '<tr><td class=rowHeader_2 style="height:25;">' + p8_no_id + "</td></tr>" + "\n";
		new_p8 = new_p8 + "</TABLE>";
	}

	return new_p8;
}

//--------------

var z_custom_repeatMbrLabels_alreadyRan = 0; //we want to make sure run this only once

function z_custom_repeatMbrLabels()
{
	/*
	Author: Dragos Matachescu
	Hyperion Planning version: 9.3.1
	Copyright: free for all, no guarantees etc.
	Description: the function simulates "Repeat Member Labels" from Excel Spreadsheet Plugin
	*/

	/*
	<TH class=rowHeader_2 id=M_0_4x0 style="TEXT-ALIGN: left" onclick="rowHeadClick(0, event)" noWrap align=left rowSpan=3>
	<DIV id=V_0_4x0 title=411100><IMG height=1 alt="" src="Images/spacer.gif" width=105>411100</DIV></TH>
	*/

	/* from file c:\Hyperion\deployments\Tomcat5\HyperionPlanning\webapps\HyperionPlanning\ui_themes\tadpole\planning.css

	.rowHeader_2 {
		height:25;
		border:solid thin;
		border-width:1;
		border-color: #8C8E8C;
		background-color:#CBDAE7;
	}
	*/

	var i, j, rows_div, arr_row_headers, row_header_initial_html, row_header_rowspan, row_header_NEW_html;

	//-- search for target rows
	if(z_custom_repeatMbrLabels_alreadyRan == 0)
	{
		z_custom_repeatMbrLabels_alreadyRan = 1;

		rows_div = document.getElementById("rowHeadDiv_0");
		if(rows_div)
		{
			arr_row_headers = rows_div.getElementsByTagName("th");
			if(arr_row_headers)
			{
				for(i=0; i<arr_row_headers.length; i++)
				{
					row_header_initial_html = arr_row_headers[i].innerHTML;
					if (row_header_initial_html.search(/<div id=V_[0-9]+_[0-9]+x[0-9]+ /gi) != -1)
					{
						row_header_rowspan = arr_row_headers[i].rowSpan;

						if(row_header_initial_html.search(/spacer\.gif/gi) != -1)
							row_header_NEW_html = z_helper_createNewTHInnerHTML(row_header_rowspan, row_header_initial_html, 1); //with spacer.gif
						else
							row_header_NEW_html = z_helper_createNewTHInnerHTML(row_header_rowspan, row_header_initial_html, 0); //no spacer.gif

						/* function rowHeadClick() is defined in EnterData.js, so if we are going to inject a table inside the original <TH> element (we need the table to duplicate the nice Planning looks), we need to "hide" this table and make the browser believe we are still in the original <TH>. To do that, we replace the handler rowHeadClick() with a custom z_custom_rowHeadClick() event handler that does not take the event source object from the event - this is wrong, because in case of the embedded table, the source object will be a cell from the embedded table instead of the original TH element, so the event handler on original TH element will not obtain from the event object the original TH (itself), but one of the cells of the embedded table (a child of his), which is wrong -, but it takes it as parameter, and we make sure we pass the right parameter */
						arr_row_headers[i].onClick = "z_custom_rowHeadClick(this, 0, event)";
						arr_row_headers[i].innerHTML = row_header_NEW_html;
					}
				}
			}
		}
	}
}

