var baseUserVersion;
var appVersion;
var currentFileBeingPatched = "";

var FAVORITE_SUFFIX	= "Fav";
var MMSTRING_NAME 	= "mmstring:name";
var MMSTRING_LABEL	= "mmstring:label";

var PATCH_CONFIG_FILE_TAG		= "configfile";
var PATCH_REMOVE_TAG			= "remove";
var PATCH_INSERT_TAG			= "insert";
var PATCH_MOVE_TAG				= "move";
var PATCH_REMOVE_SEPARATOR_TAG	= "removeseparator";
var PATCH_INSERT_SEPARATOR_TAG	= "insertseparator";
var PATCH_REMOVE_RETAIN_TAG		= "removeretain";
var PATCH_REPLACE_MMSTRINGS_TAG	= "replacemmstrings";


var forceCopiedFiles;

function isDOMRequired()
{
	return false;
}

function receiveArguments()
{
    baseUserVersion = arguments[0];
	appVersion = arguments[1];
}

function onApplyPatch()
{
	var patchNum = parseFloat( baseUserVersion );
	var appNum	= parseFloat( appVersion );
	
	var patchIncrements = 0.1;
	
	if( patchNum == 0 || appNum == 0 )
		return;
	
	// forceCopiedFiles keeps track of the list of files which have been forcefully copied from 
	// installation configuration folder into the user configuration folder. Forceful copy of a
	// file is done whenever an error occured while applying patch
	forceCopiedFiles = new Array();
	
	while( patchNum < appNum )
	{
		var patchFileName = dw.getConfigurationPath() + "/" + patchNum.toString() + ".xml";
		
		//alert( "applying patch from " + patchFileName );
		
		applyPatchFromFile( patchFileName );
		
		patchNum += patchIncrements;
	}
}

function applyPatchFromFile( patchFileName )
{
	var patchDOM = dw.getDocumentDOM( patchFileName );
    
    if( !patchDOM )
        return; // nothing to do, we couldn't get the dom object
    
	var configFiles = patchDOM.getElementsByTagName( PATCH_CONFIG_FILE_TAG );
	
	for( var fileIdx = 0; configFiles && fileIdx < configFiles.length; ++fileIdx )
	{	
        try {
			currentFileBeingPatched = configFiles[fileIdx].name;
			
			if( currentFileBeingPatched == "" || forceCopiedFiles.indexOf( currentFileBeingPatched ) != -1 )
				continue;
			
			var configFileAbsPath = dw.getUserConfigurationPath() + currentFileBeingPatched;            
			
			var theDOM = dw.getDocumentDOM( configFileAbsPath, false );
            
			if( !theDOM )
			{
				forceCopyFile();
				continue;
			}
			
	
			var result =
			scanRemoveSeparators(
								configFiles[fileIdx],	    /* Config file DOM */
								theDOM );					/* resultDOM */
			
			//alert( "result scanRemoveSeparators() = " + result );
			
			result = result && 
			scanRemoveElements( 
							   configFiles[fileIdx],	    /* Config file DOM */
							   theDOM); 					/* resultDOM */
	
			//alert( "result scanRemoveElements() = " + result );
			
			result = result && 
			scanMoveElements(
							 configFiles[fileIdx],	    /* Config file DOM */
							 theDOM);					/* resultDOM */

			//alert( "result scanMoveElements() = " + result );

			result = result && 
			scanInsertElements(
							   configFiles[fileIdx],	    /* Config file DOM */
							   theDOM);					/* resultDOM */

			//alert( "result scanInsertElements() = " + result );
			
			result = result && 
			scanRemoveRetainElements(
									 configFiles[fileIdx],	    /* Config file DOM */
									 theDOM);					/* resultDOM */

			//alert( "result scanRemoveRetainElements() = " + result );

			
			result = result && 
			scanInsertSeparators(
								 configFiles[fileIdx],	    /* Config file DOM */
								 theDOM);					/* resultDOM */
			//alert( "result scanInsertSeparators() = " + result );

			result = result &&
			scanChangesInMMStrings(
								 configFiles[fileIdx],	    /* Config file DOM */
								 theDOM);					/* resultDOM */
			//alert( "result scanChangesInMMStrings() = " + result );

			result = result && DWfile.write(configFileAbsPath, theDOM.documentElement.outerHTML);
			//alert( "result DWfile.write() = " + result );
			
			if( !result )
				forceCopyFile();
		}
		catch( e ) {
			// eat the exception
		}
		
	}
}
function getElementsById(id, theDOM)
{
	var n = theDOM.getElementById(id);
	var a = n;
	var elements = [];
	var i;
	while(n)
	{
		elements.push(n);
		n.id = "different-id";
		n = theDOM.getElementById(id);
	}
	
	for(i = 0;i < elements.length; ++i) {
        elements[i].id = id;      
    }
	
	return elements;
}

function scanRemoveSeparators( configNode, resultDOM )
{
	var removeItems = configNode.getElementsByTagName( PATCH_REMOVE_SEPARATOR_TAG );
	
    var retValue = true;
	
	for( var removeId = 0; retValue && removeItems && removeId < removeItems.length; ++removeId )
	{
		var anchorNode;

		if( removeItems[removeId].after )
		{
			anchorNode = resultDOM.getElementById( removeItems[removeId].after );
			
			if( !anchorNode )
				anchorNode = resultDOM.getElementById( removeItems[removeId].after + FAVORITE_SUFFIX );
			
			if( anchorNode )
			{
				var nextSibling = anchorNode.nextSibling;
				if( nextSibling && nextSibling.nodeType == 1 && nextSibling.tagName.toLowerCase() == "separator" )
					nextSibling.outerHTML = "";
			}
            else
				retValue = false;
		}
		else if( removeItems[removeId].before )
		{
			anchorNode = resultDOM.getElementById( removeItems[removeId].before );
			
			if( !anchorNode )
				anchorNode = resultDOM.getElementById( removeItems[removeId].before + FAVORITE_SUFFIX );
			
			if( anchorNode )
			{
				var previousSibling = anchorNode.previousSibling;
				if( previousSibling && previousSibling.nodeType == 1 && previousSibling.tagName.toLowerCase() == "separator" )
					previousSibling.outerHTML = "";
			}
            else
                retValue = false;
		}
        else
            retValue = false;
	}
    return retValue;
}

function scanInsertSeparators( configNode, resultDOM )
{
	var insertItems = configNode.getElementsByTagName( PATCH_INSERT_SEPARATOR_TAG );
	
    var retValue = true;
    
	for( var insertId = 0; retValue && insertItems && insertId < insertItems.length; insertId++ )
	{
		var anchorNode;
		var separatorOuterHTML = "<separator />";

		if( insertItems[insertId].after )
		{
			anchorNode = resultDOM.getElementById( insertItems[insertId].after );

			if( !anchorNode )
				anchorNode = resultDOM.getElementById( insertItems[insertId].after + FAVORITE_SUFFIX );
			
			if( anchorNode )
				anchorNode.outerHTML += separatorOuterHTML;
            else
                retValue = false;
		}
		else if( insertItems[insertId].before )
		{
			anchorNode = resultDOM.getElementById( insertItems[insertId].before );
			
			if( !anchorNode )
				anchorNode = resultDOM.getElementById( insertItems[insertId].before + FAVORITE_SUFFIX );
			
			if( anchorNode )
				anchorNode.outerHTML = separatorOuterHTML + anchorNode.outerHTML;
            else
                retValue = false;
		}
        else
            retValue = false;
	}
    return retValue;
}


function scanRemoveElements( configNode, resultDOM )
{
	var removeItems = configNode.getElementsByTagName( PATCH_REMOVE_TAG );
    
    var retValue = true;

	for( var removeId = 0; retValue && removeItems && removeId < removeItems.length; ++removeId )
	{	
		var elementsToDelete = removeItems[removeId].childNodes;
		
		for( var elt = 0; retValue && elementsToDelete && elt < elementsToDelete.length; ++elt )
		{
			if( elementsToDelete[elt].nodeType == 1 )
			{
				var elementList = getElementsById( elementsToDelete[elt].id, resultDOM);
				var found = false;
				if( elementList.length > 0 )
				{
					for(var idx = 0; elementList[idx]; idx++)
					{	
						if( elementsToDelete[elt].parentId )
						{	
							if(elementList[idx].parentNode.id == elementsToDelete[elt].parentId )
							{
								elementList[idx].outerHTML = "";
								found = true;
								break;
							}
						}
						else
						{ 
							elementList[idx].outerHTML = "";
							found = true;
						} 
					}
				}
				if( !found )
				{
					var elementListFav = getElementsById( elementsToDelete[elt].id + FAVORITE_SUFFIX, resultDOM); 
					if( elementListFav.length > 0 )
					{
						for(var idx = 0; elementListFav[idx]; idx++)
							elementListFav[idx].outerHTML = "";
					}
					else
						retValue = false;
				} 
			}
		}
	}

    return retValue;
}

function scanInsertElements( configNode, resultDOM )
{
	var insertItems = configNode.getElementsByTagName( PATCH_INSERT_TAG );
	
    var retValue = true;
    
	for( var insertId = 0; retValue && insertItems && insertId < insertItems.length; ++insertId )
	{
		var anchorNode;
			
		if( insertItems[insertId].insertAfter )
		{
			anchorNode = resultDOM.getElementById( insertItems[insertId].insertAfter );
			
			if( !anchorNode )
				anchorNode = resultDOM.getElementById( insertItems[insertId].insertAfter + FAVORITE_SUFFIX );
			
			if( anchorNode )
                anchorNode.outerHTML += "\n" + insertItems[insertId].innerHTML;
            else
                retValue = false;
		}
		else if( insertItems[insertId].insertBefore )
		{
			anchorNode = resultDOM.getElementById( insertItems[insertId].insertBefore );
			
			if( !anchorNode )
				anchorNode = resultDOM.getElementById( insertItems[insertId].insertBefore + FAVORITE_SUFFIX );
			
            if( anchorNode )
                anchorNode.outerHTML = insertItems[insertId].innerHTML + "\n" + anchorNode.outerHTML;
            else
                retValue = false;
		}
		else if( insertItems[insertId].prependTo )
		{
			anchorNode = resultDOM.getElementById( insertItems[insertId].prependTo );
			
			if( !anchorNode )
				anchorNode = resultDOM.getElementById( insertItems[insertId].prependTo + FAVORITE_SUFFIX );
			
			if( anchorNode )
            {
                var anchorNodeChildren = anchorNode.childNodes;
                    
                if( anchorNodeChildren && anchorNodeChildren.length > 0 )
                    anchorNodeChildren[0].outerHTML = insertItems[insertId].innerHTML + "\n" + anchorNodeChildren[0].outerHTML;
                else
                    anchorNode.innerHTML = insertItems[insertId].innerHTML + "\n" + anchorNode.innerHTML;
            }
            else
                retValue = false;

		}
		else if( insertItems[insertId].appendTo )
		{
			anchorNode = resultDOM.getElementById( insertItems[insertId].appendTo );
			
			if( !anchorNode )
				anchorNode = resultDOM.getElementById( insertItems[insertId].appendTo + FAVORITE_SUFFIX );
			
            if( anchorNode )
            {
                var anchorNodeChildren = anchorNode.childNodes;
				
                 if( anchorNodeChildren && anchorNodeChildren.length > 0 )
                    anchorNodeChildren[anchorNodeChildren.length - 1].outerHTML += "\n" + insertItems[insertId].innerHTML;
                else
                    anchorNode.innerHTML += "\n" + insertItems[insertId].innerHTML;
            }
            else
                retValue = false;
		}
         else
             retValue = false;
	}
    
    return retValue;
}

function scanMoveElements( configNode, resultDOM )
{
	var moveItems = configNode.getElementsByTagName( PATCH_MOVE_TAG );
    
    var retValue = true;

	for( var moveId = 0; retValue && moveItems && moveId < moveItems.length; ++moveId )
	{
		var elementsToDelete = moveItems[moveId].childNodes;
			
		var outerHTMLBackup = "";
						
		for( var elt = 0; retValue && elementsToDelete && elt < elementsToDelete.length; ++elt )
		{
			if( elementsToDelete[elt].nodeType == 1 )
			{
				var elementToDelete = resultDOM.getElementById( elementsToDelete[elt].id );
				
				if( !elementToDelete )
					elementToDelete = resultDOM.getElementById( elementsToDelete[elt].id + FAVORITE_SUFFIX );
				
				if( elementToDelete )
				{
					outerHTMLBackup += "\n" + elementToDelete.outerHTML;
					elementToDelete.outerHTML = "";
				}
				else
					retValue = false;
			}
		}
			
		if( moveItems[moveId].insertAfter )
		{
			anchorNode = resultDOM.getElementById( moveItems[moveId].insertAfter );
			
			if( !anchorNode )
				anchorNode = resultDOM.getElementById( moveItems[moveId].insertAfter + FAVORITE_SUFFIX );
			
			if( anchorNode )
                anchorNode.outerHTML += outerHTMLBackup;
            else
                retValue = false;
		}
		else if( moveItems[moveId].insertBefore )
		{
			anchorNode = resultDOM.getElementById( moveItems[moveId].insertBefore );
			
			if( !anchorNode )
				anchorNode = resultDOM.getElementById( moveItems[moveId].insertBefore + FAVORITE_SUFFIX );
			
			if( anchorNode )
                anchorNode.outerHTML = outerHTMLBackup + anchorNode.outerHTML;
            else
                retValue = false;
		}
		else if( moveItems[moveId].prependTo )
		{
			anchorNode = resultDOM.getElementById( moveItems[moveId].prependTo );
			
			if( !anchorNode )
				anchorNode = resultDOM.getElementById( moveItems[moveId].prependTo + FAVORITE_SUFFIX );
			
			if( anchorNode )
            {
                var anchorNodeChildren = anchorNode.childNodes;
                if( anchorNodeChildren && anchorNodeChildren.length > 0 )
                    anchorNodeChildren[0].outerHTML = outerHTMLBackup + anchorNodeChildren[0].outerHTML;
                else
                    anchorNode.innerHTML = outerHTMLBackup + anchorNode.innerHTML;
            }
            else
                retValue = false;
		}
		else if( moveItems[moveId].appendTo )
		{
			anchorNode = resultDOM.getElementById( moveItems[moveId].appendTo );
			
			if( !anchorNode )
				anchorNode = resultDOM.getElementById( moveItems[moveId].appendTo + FAVORITE_SUFFIX );
			
			if( anchorNode )
            {
                var anchorNodeChildren = anchorNode.childNodes;
                if( anchorNodeChildren && anchorNodeChildren.length > 0 )
                    anchorNodeChildren[anchorNodeChildren.length - 1].outerHTML += "\n" + outerHTMLBackup;
                else
                    anchorNode.innerHTML += outerHTMLBackup;
            }
            else
                retValue = false;
		}
        else
            retValue = false;
	}
    
    return retValue;
}

function scanChangesInMMStrings( configNode, resultDOM )
{
    var retValue = true;
	var replaceNodes = configNode.getElementsByTagName( PATCH_REPLACE_MMSTRINGS_TAG );

	for( var idx = 0; retValue && idx < replaceNodes.length; ++ idx )
	{
		var mmStringElements = replaceNodes[idx].childNodes;
		for( var elt = 0; retValue && mmStringElements && elt < mmStringElements.length; ++elt )
		{
			var elementList = getElementsById( mmStringElements[elt].id, resultDOM );
			if( elementList.length > 0 )
				retValue = changeMMStringForElements( elementList, mmStringElements[elt] );
			else
			{
				var elementListFav = getElementsById( mmStringElements[elt].id + FAVORITE_SUFFIX, resultDOM );
				if( elementListFav.length > 0 )
					retValue = changeMMStringForElements( elementListFav, mmStringElements[elt] );
				else
					retValue = false;
			}
		}
	}

	return retValue;
}

function changeMMStringForElements( elementList, mmStringElement )
{
	var retValue = true;

	if( !mmStringElement || mmStringElement.nodeType != 1 )
		return true; // nothing to be done, this might be a comment node from patch file
	
	for(var idx = 0; retValue && idx < elementList.length; idx++)
	{
		if( elementList[idx].name )
		{
			elementList[idx].removeAttribute("name");
			var attrname = mmStringElement.getAttribute( MMSTRING_NAME );
			
			if( attrname )
				elementList[idx].setAttribute( MMSTRING_NAME, attrname );
			else
				retValue = false;
		}
		
		if( elementList[idx].label )
		{
			elementList[idx].removeAttribute("label");
			var attrlabel = mmStringElement.getAttribute( MMSTRING_LABEL );
			
			if( attrlabel )
				elementList[idx].setAttribute( MMSTRING_LABEL, attrlabel );
			else
				retValue = false;
		}
	}
	
	return retValue;
}


function scanRemoveRetainElements( configNode, resultDOM )
{
    var retValue = true;

	var rmrtItems = configNode.getElementsByTagName( PATCH_REMOVE_RETAIN_TAG );

	for( var idx = 0; retValue && rmrtItems && idx < rmrtItems.length; ++idx )
	{
		var newNodeInnerHTML = "";
		var removeRetainElements = rmrtItems[idx].childNodes;
			
		for( var elt = 0; removeRetainElements && elt < removeRetainElements.length; ++elt )
		{
			var node = resultDOM.getElementById( removeRetainElements[elt].id );
			var mychildren = node.childNodes;
				
			for( var childid = 0; mychildren && childid < mychildren.length; ++childid )
				if( mychildren[childid].tagName.toLowerCase() == "separator" )
					mychildren[childid].outerHTML = "";
				
			newNodeInnerHTML += node.innerHTML;
				
			node.outerHTML = "";
		}
			
		if( newNodeInnerHTML && rmrtItems[idx].xmlnodetype.toLowerCase() == "menu" )
		{
			var targetNode = resultDOM.getElementById( rmrtItems[idx].id );
				
			var nodeBegin = "<menu "+MMSTRING_NAME+"=\"" + rmrtItems[idx].name + "\" id=\"" + rmrtItems[idx].id + "\">";
			var nodeEnd = "</menu>";
			var anchorNode;
				
			if( targetNode )
			{
				targetNode.innerHTML += newNodeInnerHTML;
			}
			else
			{
				if( rmrtItems[idx].insertAfter )
				{
					anchorNode = resultDOM.getElementById( rmrtItems[idx].insertAfter );
                    if( anchorNode )
                        anchorNode.outerHTML = anchorNode.outerHTML + nodeBegin + newNodeInnerHTML + nodeEnd;
                    else
                        retValue = false;
				}
				else if( rmrtItems[idx].insertBefore )
				{
					anchorNode = resultDOM.getElementById( rmrtItems[idx].insertBefore );
					if( anchorNode )
                        anchorNode.outerHTML = nodeBegin + newNodeInnerHTML + nodeEnd + anchorNode.outerHTML;
                    else
                        retValue = false;
				}
				else if( rmrtItems[idx].prependTo )
				{
					anchorNode = resultDOM.getElementById( rmrtItems[idx].prependTo );
					if( anchorNode )
                        anchorNode.innerHTML = nodeBegin + newNodeInnerHTML + nodeEnd + anchorNode.innerHTML;
                    else
                        retValue = false;
				}
				else if( rmrtItems[idx].appendTo )
				{
					anchorNode = resultDOM.getElementById( rmrtItems[idx].appendTo );
					if( anchorNode )
                        anchorNode.innerHTML = anchorNode.innerHTML + nodeBegin + newNodeInnerHTML + nodeEnd;
                    else
                        retValue = false;
				}
                else
                    retValue = false;
			}
			deleteNodeIfNoValidChildren( resultDOM, rmrtItems[idx].id );
		}
		
		else if( newNodeInnerHTML && rmrtItems[idx].xmlnodetype.toLowerCase() == "category" )
		{
			var targetNode = resultDOM.getElementById( rmrtItems[idx].id );
				
			var nodeBegin = "<category "+MMSTRING_NAME+"=\"" + rmrtItems[idx].name + "\" folder=\"Miscellaneous\"" + " id=\"" + rmrtItems[idx].id + "\">";
			var nodeEnd = "</category>";
			var anchorNode;
				
			if( targetNode )
			{
				targetNode.innerHTML += newNodeInnerHTML;
			}
			else
			{
				if( rmrtItems[idx].insertAfter )
				{
					anchorNode = resultDOM.getElementById( rmrtItems[idx].insertAfter );
					
					if( !anchorNode )
						anchorNode = resultDOM.getElementById( rmrtItems[idx].insertAfter + FAVORITE_SUFFIX );
					
                    if( anchorNode )
                        anchorNode.outerHTML = anchorNode.outerHTML + nodeBegin + newNodeInnerHTML + nodeEnd;
                    else
                        retValue = false;
				}
				else if( rmrtItems[idx].insertBefore )
				{
					anchorNode = resultDOM.getElementById( rmrtItems[idx].insertBefore );
					
					if( !anchorNode )
						anchorNode = resultDOM.getElementById( rmrtItems[idx].insertBefore + FAVORITE_SUFFIX );
					
					if( anchorNode )
                        anchorNode.outerHTML = nodeBegin + newNodeInnerHTML + nodeEnd + anchorNode.outerHTML;
                    else
                        retValue = false;
				}
				else if( rmrtItems[idx].prependTo )
				{
					anchorNode = resultDOM.getElementById( rmrtItems[idx].prependTo );
					
					if( !anchorNode )
						anchorNode = resultDOM.getElementById( rmrtItems[idx].prependTo + FAVORITE_SUFFIX );
					
					if( anchorNode )
                        anchorNode.innerHTML = nodeBegin + newNodeInnerHTML + nodeEnd + anchorNode.innerHTML;
                    else
                        retValue = false;
				}
				else if( rmrtItems[idx].appendTo )
				{
					anchorNode = resultDOM.getElementById( rmrtItems[idx].appendTo );
					
					if( !anchorNode )
						anchorNode = resultDOM.getElementById( rmrtItems[idx].appendTo + FAVORITE_SUFFIX );
					
					if( anchorNode )
                        anchorNode.innerHTML = anchorNode.innerHTML + nodeBegin + newNodeInnerHTML + nodeEnd;
                    else
                        retValue = false;
				}
                else
                    retValue = false;
			}
			deleteNodeIfNoValidChildren( resultDOM, rmrtItems[idx].id );
		}
	}
    
    return retValue;
}

//
// This function shall delete the "Missing Extensions" under "Insert" menu if it doesn't finally have a valid element node underneath.
// Similar case for "Miscellaneous" category in Insert panel as well
//
function deleteNodeIfNoValidChildren( resultDOM, eltId )
{
	var targetNode = resultDOM.getElementById( eltId );
	
	if( targetNode )
	{
		var mychildren = targetNode.childNodes;
		var foundValidElementNodes = false;
		
		for( var childid = 0; mychildren && childid < mychildren.length; ++childid )
			if( mychildren[childid].nodeType == 1 )
			{
				foundValidElementNodes = true;
				break;
			}
		
		if( !foundValidElementNodes )
			targetNode.outerHTML = "";
	}
}


function forceCopyFile()
{
    //alert( "forceCopyFile : filename = " + currentFileBeingPatched );

    if( currentFileBeingPatched != "" && 
		forceCopiedFiles.indexOf( currentFileBeingPatched ) == -1 )
		/* If the file was forcefully copied earlier, it'll be in the array, skip the copy!
		   Copy only if we are copying this file for the first time */
    {
        var appConfigFile   = dw.getConfigurationPath() + "/" + currentFileBeingPatched;
        var userConfigFile  = dw.getUserConfigurationPath() + currentFileBeingPatched;
        //alert( "appConfigFile = " + appConfigFile + ", userConfigFile = " + userConfigFile );
		DWfile.remove( userConfigFile );
		DWfile.copy( appConfigFile, userConfigFile );
		forceCopiedFiles.push( currentFileBeingPatched );
    }
}

