/*
The behavior's job is to decorate a syntax block.
The behavior works in two modes: decorate the current element, or decorate all PREs marked with the AUTOHILITE expando.

The advantage to the latter mode is that only a single instance of the behavior need be attached to process the entire document.
This works well when the document uses consistent markup for sample code. Attaching one behavior per element wastes resources unnecessarily.

The behavior exposes TOPICNAME and PERSISTENTNAME properties so that the author doesn't have to specify these in the HILITE expando of every
element to be decorated. It's up to the user to set these expandos prior to attaching the behavior.

Future enhancements:
1) In batch mode, rather than processing PREs only, expose a property ELEMENTSTODECORATE that specifies a
	semi-colon delimited list of tags that should be inspected for the AUTOHILITE attribute
2) Expose distinct properties for the different marker/text colors
*/

var debug = 0;
var m_sTopicName = null; // runtime name of the topic
var m_sPN = null; // persistent name of the topic
var m_oRng = null; // TextRange representing the current element
var m_sBM = null; // TextRange bookmark
var m_bAutoHilite = false; // indicates that we should decorate the current element only
var m_sMarkerColor = "green"; // color for comment delimeters
var m_sTextColor = "green"; // color for text within comments
var m_bScriptPage = false;//Indicates if the page is a script page


var COMMAND	 = 'CMD';
var OBJECT	 = 'OBJ';
var METHOD	 = 'MTH';
var EVENT	 = 'EVT';
var PROPERTY = 'PTY';
var CELLBODY_CSS_CLASS = 'cCellBody';
var CELLBODY_BGCOLOR = '#ffffc0';		// Background color for non-inherited members

window.onload = function () {

	if ( !document.all ) return;

	do_tables();

	var sKeywords = "";
	var arrKeywords = new Array();
	
	// Determine the type of page and get the command/object/method/property name.
	var sFlag = '';
	var sObjectName = '';
	var sMemberName = '';
	var sCommandName = '';

	var collAnchors = document.anchors;
	for (var i=0; i<collAnchors.length; i++ ) 
	{
		// Does it have a type attribute (use it to determine
		// type of reference entry)
		if ( collAnchors(i).type ) 
		{
			sFlag = collAnchors(i).type;
			
			// A little double-checking to make sure I have the right ancestor
			var currNode = collAnchors(i);
			var sInnerText = "";
			do 
			{
				// Test the current element to see if it's the one we want
				if ( currNode.className == "h2sHeading2split" ) 
				{
					sInnerText = currNode.innerText;
					break;
				}
				
				// If it wasn't the right one, grab the parent
				currNode = currNode.parentElement;
			} while ( currNode != document.documentElement );
			
			switch ( sFlag ) 
			{
				case OBJECT :
					sObjectName = sInnerText;
					break;
				case COMMAND :
					sCommandName = sInnerText;
					break;
				case METHOD :
				case PROPERTY :
					/(\w+) /.test(sInnerText);
					sMemberName = RegExp.$1;
					break;
			}
			break;
		}
	}


	// Change the background color of non-inherited properties and methods.
	// And build a list of keywords for highlighting in code samples on the Object page.
	if ( sFlag == OBJECT )
	{
		var collLinks = document.links;

		for (var i=0; i<collLinks.length; i++ )
		{
			var oLink = collLinks(i);
			var sHref = oLink.href;
			var s = sHref.indexOf(sObjectName + '_');
			if ( s > 0 )
			{
				if ( debug ) alert( sHref );
				if ( oLink.className == CELLBODY_CSS_CLASS && oLink.parentNode.className == CELLBODY_CSS_CLASS )
				{
					oLink.parentNode.parentNode.style.background=CELLBODY_BGCOLOR;
					var t = s + sObjectName.length + 1;
					var u = sHref.indexOf( '.htm' );
					if ( debug ) alert( sHref.substr( t, u-t ) );
					arrKeywords.push(sHref.substr( t, u-t ));
				}
			}
		}

	}

	// If the method or property can be used by scripted operators and particle events,
	// replace the asterisk in the main heading with an icon that has a fancy tooltip
	if ( sFlag == METHOD ||  sFlag == PROPERTY )
	{
		insertImage( sFlag );
	}

	
	switch ( sFlag )
	{
		case OBJECT:
			sKeywords = arrKeywords.join(';');
			break;
		case METHOD:
		case PROPERTY:
			sKeywords = sMemberName;
			break;
		
		case COMMAND:
			sKeywords = sCommandName;
		
	}
	


	handle_docready( sKeywords );

}


function do_tables()
{
	var cloTables = document.all.tags('TABLE');
	
	for (var i=0; i<cloTables.length; i++ )	
	{
		if ( cloTables(i).className == 'TableColumn' || cloTables(i).className == 'TablePage' )
		{
			var cloRows = cloTables(i).rows;
			for ( var j=0; j<cloRows.length; j++ )
			{
				var cloCells = cloRows(j).cells;
				if ( cloCells.length > 0 && cloCells(0).children(0).className == "chCellHeading" )
				{
					for (var k=0; k<cloCells.length; k++ )	
					{
						cloCells(k).style.background = "#B7C7EF";
					}
				}
				
			}
		}
		if ( cloTables(i).className == 'Parameters')
		{
			var cloRows = cloTables(i).rows;
			for ( var j=0; j<cloRows.length; j++ )
			{
				cloRows(j).cells(0).width = 210
			}
		}

	}
	
}






var oPopup = window.createPopup();

function hideTooltip()
{
	oPopup.hide();
}

function showTooltip( sHref, sMemberType )
{

	oPopup.document.body.style.fontFamily="Verdana,Arial";
	oPopup.document.body.style.fontSize="11px";

	var sOnClick = " onclick='parent.location.href=this.href'";
	var sTitle = " title='What You Can Call from a Scripted Operator or a Particle Event'";
	var s = "<div style='background:#ffffd0;padding:6px;border:1px solid black;height:55;'>";
	s = s + "<p>This " + sMemberType + " can be used in scripted operators and particle events.<br>";
	s = s + "Scripted operators and particle events can use only a <a href='" + sHref + "'" + sOnClick + sTitle + ">subset</a> of the object model. Methods and properties that you can use are marked with this symbol <img src='op.gif' style='position:relative;bottom:-2px'>, or with an asterisk (*).";
	s = s + "</p>";
	s = s + "</div>";

	oPopup.document.body.innerHTML = s;

	// This code is copied from
	// http://msdn.microsoft.com/library/default.asp?url=/workshop/author/om/popup_overview.asp
	//
	var popupBody = oPopup.document.body;
	// The following popup object is used only to detect what height the 
	// displayed popup object should be using the scrollHeight property. 
	// This is important because the size of the popup object varies 
	// depending on the length of the definition text. This first 
	// popup object is not seen by the user.
	oPopup.show(0, 0, 300, 0);
	var realHeight = popupBody.scrollHeight;
	// Hides the dimension detector popup object.
	oPopup.hide();
	// Shows the actual popup object with correct height.
	oPopup.show(15, 15, 300, realHeight, event.srcElement);
	//
	// End copied code

}


function insertImage( sFlag )
{
	switch ( sFlag )
	{
		case METHOD:
			var sMemberType = "method";
			break;
		case PROPERTY:	// Property
			var sMemberType = "property";
			break;
	}
	
	
	var collLinks = document.links;
	
	for (var i=0; i<collLinks.length; i++ )
	{
		if ( collLinks(i).href.indexOf( 'ScriptedOperatorLimitations' ) > -1 )
		{
			var sHref = collLinks(i).href;
			if ( /(\w+\.htm#\w+)/.test( collLinks(i).href ) ) 
			{
				var sTarget = RegExp.$1;
			}

			var sTmp =  "<img src='op.gif' border='0' onmouseover='showTooltip(\"";
// With this I get an Expected Hexadecimal Digit error in the ch.
//			sTmp = sTmp + collLinks(i).href + "\", \"" + sThisMember;
			sTmp = sTmp + sTarget + "\", \"" + sMemberType;
			sTmp = sTmp + "\")'>";
			collLinks(i).innerHTML = sTmp;

			break;
		}
			
			
	}
	
}

function handle_docready( keywords )
{

	m_oRng = window.document.body.createTextRange();
	if (!m_oRng)
	{
		return;
	}
	var colMeta=window.document.all.tags("META");
	if (colMeta)
	{
		for (var iMETAs=0; iMETAs<colMeta.length; iMETAs++)
		{
			if (colMeta[iMETAs].getAttribute("content")=="'scr'" && colMeta[iMETAs].getAttribute("name")=="devlang")
			{
				m_bScriptPage=true;
			}
		}
	}
	if (m_bAutoHilite) // we're attached directly to the element we've been asked to hilite
	{
		DecorateElement(element);
	}
	else
	{
		// walk the entire topic, and decorate special block elements
		var oPREs = window.document.all.tags("PRE");
		var iPREs = oPREs.length;
		if (iPREs == 0)
		{
			return;
		}

		for (var iPRE = 0; iPRE < iPREs; iPRE++)
		{
			var oPRE = oPREs[iPRE];
			var sClassName = oPRE.className;
			var re = /Python|JScript|VBScript|Cplusplus|^cwC$|PerlScript/i;
			var arrTmp = sClassName.match(re);
			
			var sLang = "";
			if ( arrTmp != null ) 
				var sLang = arrTmp[0];
			
			// only auto-hilite the contents if the feature has been enabled for this PRE
			//if (oPRE.getAttribute("AUTOHILITE"))
			//{
				DecorateElement(oPRE, keywords, sLang );
			//}
		}
	}

}

function DecorateElement(oElem, keywords, sLang )
{

	m_oRng.moveToElementText(oElem);
	m_sBM = m_oRng.getBookmark(); // save our place in case we have to move the range
	HiliteComments(m_oRng, sLang );
	if( sLang.length > 0 ) 
	{
		HiliteTokens(oElem, m_oRng, keywords );
	}
    if (oElem.previousSibling && oElem.previousSibling.ShowHideType )
    {
	  toggle(oElem.previousSibling);
    }
}

// restore our place
function RestoreRange()
{
	m_oRng.moveToBookmark(m_sBM);
}

// Dispatch calls to the various routines that hilite different code comment types
function HiliteComments(oRng, sLang )
{
	if ( sLang.length == 0 ) return;
	//alert( sLang );
	switch ( sLang.toLowerCase() ) {
		case "cplusplus":
		case "cwc":
		case "jscript" :
			HiliteCStyleComments(oRng);
			HiliteSingleLineComment(oRng, "//");
			break;
		case "vbscript" :
			HiliteSingleLineComment(oRng, "'");
			break;
		case "python" :
		case "perlscript" :
			HiliteSingleLineComment(oRng, "#");
			break;
	}
	if (m_bScriptPage)
	{
		HiliteHTMLComments(oRng);
	}
}

// Hilites comments of the following form
//      // C++ or JScript comment
//      '  VB(S) comment
//      # Perl(Script) or Python comment
function HiliteSingleLineComment(oRng, sToken)
{
	if (typeof(sToken) != "string")
	{
		return;
	}

	var oRngStart = oRng.duplicate();
	var oRngEnd;
	
	while (oRngStart.findText(sToken, 1000000) && oRng.inRange(oRngStart))
	{
		// handle exceptions
		if (sToken == "//")
		{
			var sBM = oRngStart.getBookmark();
			oRngStart.move("character", -1);
			oRngStart.moveEnd("character", 1);
			var sPrecedingChar = oRngStart.text;
			oRngStart.moveToBookmark(sBM);
			if (sPrecedingChar == ":") // the token is likely part of an http (or some other protocol) link
			{
			   oRngStart.collapse(false);
			   continue;
			}
			else if (sPrecedingChar == "-") // part of a DOCTYPE decl?
			{
				oRngStart.move("character", -2);
				oRngStart.moveEnd("character", 1);
				var sQuote = oRngStart.text;
				if (/(["'])/.test(sQuote))
				{
					oRngStart.collapse(false);
					if (oRngStart.findText(RegExp.$1)) // look for matching quote at the end of the DOCTYPE
					{
						oRngStart.collapse(false);
						continue;
					}
					else
					{
						// bad news
						return;
					}
				}
				else
				{
					oRngStart.moveToBookmark(sBM); // reset and proceed
				}
			}
		}

		oRngStart.execCommand("ForeColor", false, m_sMarkerColor);
		oRngStart.collapse(false);
		oRngEnd = oRngStart.duplicate();
		if (oRngEnd.findText("\r", 1000000))
		{
			oRngStart.setEndPoint("EndToStart", oRngEnd);
		}
		else
		{
			// comment is the last line in the block
			oRngStart.setEndPoint("EndToEnd", oRng);
		}
		oRngStart.execCommand("ForeColor", false, m_sTextColor);
	}

}

// Hilite C-style comments in the specified range
function HiliteCStyleComments(oRng)
{
	var oRngStart = oRng.duplicate();
	var oRngEnd;

	while (oRngStart.findText("/*", 1000000) && oRng.inRange(oRngStart))
	{
		oRngStart.execCommand("ForeColor", false, m_sMarkerColor);
		oRngStart.collapse(false);
		oRngEnd = oRngStart.duplicate();
		if (!oRngEnd.findText("*/", 1000000))
		{
			break; // bad news; couldn't find closing comment. Bail.
		}
		oRngEnd.execCommand("ForeColor", false, m_sMarkerColor);
		oRngStart.setEndPoint("EndToStart", oRngEnd);
		oRngStart.execCommand("ForeColor", false, m_sTextColor);
	}
}

// Hilite HTML-style comments in the specified range
function HiliteHTMLComments(oRng)
{
	var oRngStart = oRng.duplicate();
	var oRngEnd;
	while (oRngStart.findText("<!--") && oRng.inRange(oRngStart))
	{
		// Check for a conditional IE comment
		oRngStart.setEndPoint( "EndToEnd", oRng );
		if ( /<!--\s*\[\s*if/.test( oRngStart.text ) )
		{
			oRngEnd = oRngStart.duplicate();
			if ( oRngEnd.findText( ">" ) )
			{	// Skip conditional comment
				oRngStart.setEndPoint( "StartToEnd", oRngEnd );
			}
			continue;
		}
		else
		{	// Reset text range
			oRngStart.findText("<!--");
		}

		oRngStart.moveEnd("character", -2); // back up to exclude the --
		oRngStart.execCommand("ForeColor", false, m_sMarkerColor);
		oRngStart.collapse(false);
		oRngEnd = oRngStart.duplicate();
		if (!oRngEnd.findText("-->"))
		{
			break; // bad news; couldn't find closing comment. Bail.
		}
		oRngEnd.moveStart("character", 2); // roll forward to exclude the --
		oRngEnd.execCommand("ForeColor", false, m_sMarkerColor);
		oRngStart.setEndPoint("EndToStart", oRngEnd);
		oRngStart.execCommand("ForeColor", false, m_sTextColor); // hilite the comment text
	}
}

// Apply hiliting to the keywords identified in the semi-colon delimited string associated with the HILITE attribute.
function HiliteTokens(oElement, oRng, keywords )
{
	var oRegEmptyStr = new RegExp("^\\s*$");

	// process any author-defined tokens
//	var sTokens = oElement.getAttribute("HILITE");
	var sTokens = keywords;
	if (!sTokens && !m_sTopicName && !m_sPN)
	{
		return; // nothing to hilite
	}

	var aTokens; // array of tokens to search for

	if (sTokens)
	{
		aTokens = sTokens.split(";");
	}
	else
	{
		aTokens = new Array();
	}

	// if available, append the topic's runtime and persistent name to the list
	if (m_sTopicName) aTokens[aTokens.length] = m_sTopicName;
	if (m_sPN) aTokens[aTokens.length] = m_sPN;

	var ahTokens = new Array(); // hash of tokens we've already searched for to prevent accidental toggling

	var oRngTemp = oRng.duplicate();
	for (var iToken = 0; iToken < aTokens.length; iToken++)
	{
		var sToken = aTokens[iToken];
		// watch out for dupe tokens
		if (oRegEmptyStr.test(sToken) || ahTokens[sToken])
		{
			continue;
		}

		ahTokens[sToken] = 1;

		while (oRngTemp.findText(sToken, 1000000, 6) && oRng.inRange(oRngTemp))
		{
			// Hilight the token if it is not in a comment ("Green" = 32768)
			if ( oRngTemp.queryCommandValue("ForeColor") != 32768 )		
			{
				oRngTemp.execCommand("BackColor", false, "Yellow");
				oRngTemp.execCommand("ForeColor", false, "Black");
			}
			oRngTemp.collapse(false);
		}

		oRngTemp.moveToBookmark(m_sBM); // reset the temporary range for the next iteration

	}
}
