// VcprojSync.cpp : Defines the entry point for the console application.
//
#include "Xml\Xml.h"
#include <Windows.h>
#include <shlwapi.h>

#pragma comment( lib, "shlwapi.lib" )


using std::string;

//////////////////////////////////////////////////////////////////////////
void replace_str( string &str,const char* strOld,const char* strNew )
{
	size_t nSourceLen = strlen(strOld);
	if (nSourceLen == 0)
		return;

	const char* strStart = str.c_str();
	const char* strEnd = str.c_str() + str.length();
	const char* strTarget;
	while (strStart < strEnd)
	{
		while ((strTarget = strstr(strStart, strOld)) != NULL)
		{
			int pos = strTarget - strStart;
			str.replace( pos,nSourceLen,strNew );
			return;
		}
	}
}

//////////////////////////////////////////////////////////////////////////
void ReplaceConfigName( XmlNodeRef &node,const string &fromPlatform,const string &toPlatform )
{
	if (node->isTag("FileConfiguration"))
	{
		XmlString config;
		if (node->getAttr("Name",config))
		{
			if (strstr(config.c_str(),fromPlatform.c_str()) != 0)
			{
				// replace it.
				replace_str( config,fromPlatform.c_str(),toPlatform.c_str() );
				node->setAttr("Name",config);
			}
		}
	}
	else
	{
		for (int i = 0; i < node->getChildCount(); i++)
		{
			ReplaceConfigName( node->getChild(i),fromPlatform,toPlatform );
		}
	}
}

//////////////////////////////////////////////////////////////////////////
bool DeleteFileConfiguration( XmlNodeRef &node,const string &configName )
{
	if (node->isTag("FileConfiguration"))
	{
		XmlString config;
		if (node->getAttr("Name",config))
		{
			if (strstr(config.c_str(),configName.c_str()) != 0)
			{
				// replace it.
				return true;
			}
		}
	}
	else
	{
		for (int i = 0; i < node->getChildCount(); )
		{
			if (DeleteFileConfiguration( node->getChild(i),configName ))
			{
				node->deleteChildAt(i);
			}
			else
			{
				i++;
			}
		}
	}
	return false;
}

//////////////////////////////////////////////////////////////////////////
void ReplaceFileRelativePath( XmlNodeRef &node,const string &dir )
{
	if (node->isTag("File"))
	{
		XmlString file;
		if (node->getAttr("RelativePath",file))
		{
			string filename = file;
			if (strstr(filename.c_str(),".\\") == filename.c_str())
			{
				filename = filename.substr(2);
			}
			filename = dir + filename;
			node->setAttr("RelativePath",filename.c_str());
		}
	}
	else
	{
		for (int i = 0; i < node->getChildCount(); i++)
		{
			ReplaceFileRelativePath( node->getChild(i),dir );
		}
	}
}

int main(int argc, char* argv[])
{
	char dir[_MAX_PATH];
	GetCurrentDirectory(100,dir);

	if (argc < 3)
	{
		printf( "Not enough arguments specified.\n\n");

		printf( "Usage:\n");
		printf( "     VcprojSync.exe SourceProject.vcproj TargetProject.vcproj\n");
		return 0;
	}

	printf( "Converting %s to %s\n",argv[1],argv[2] );

	char srcFile[_MAX_PATH];
	char trgFile[_MAX_PATH];
	_fullpath( srcFile,argv[1],sizeof(srcFile) );
	_fullpath( trgFile,argv[2],sizeof(trgFile) );

	XmlParser xmlParse;
	XmlNodeRef rootSrc = xmlParse.parse( srcFile );
	XmlNodeRef rootTrg = xmlParse.parse( trgFile );

	if (!rootSrc)
	{
		printf( "Error, Cannot parse XML from file %s\n",srcFile );
		return 1;
	}
	if (!rootTrg)
	{
		printf( "Error, Cannot parse XML from file %s\n",trgFile );
		return 1;
	}

	XmlNodeRef FilesSrc = rootSrc->findChild("Files");
	rootTrg->deleteChild("Files");
	rootTrg->addChild(FilesSrc);

	ReplaceConfigName( rootTrg,"Win32","Xenon" );
	DeleteFileConfiguration( rootTrg,"Profile" );
	DeleteFileConfiguration( rootTrg,"Debug64" );
	DeleteFileConfiguration( rootTrg,"Release64" );

	//////////////////////////////////////////////////////////////////////////
	// Create relative path between projects.
	//////////////////////////////////////////////////////////////////////////
	char relativePath[_MAX_PATH];
	char srcpath[_MAX_PATH];
	char trgpath[_MAX_PATH];
	_splitpath( srcFile,NULL,srcpath,NULL,NULL );
	_splitpath( trgFile,NULL,trgpath,NULL,NULL );
	if (PathRelativePathTo( relativePath,trgpath,FILE_ATTRIBUTE_DIRECTORY,srcpath, FILE_ATTRIBUTE_DIRECTORY ))
	{
		if (strlen(relativePath) > 0)
		{
			printf( "RelativePath is prefexed with: %s\n",relativePath );
			ReplaceFileRelativePath( rootTrg,relativePath );
		}
	}
	//////////////////////////////////////////////////////////////////////////

	rootTrg->saveToFile( trgFile );

	return 0;
}

