/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
#include "CdlCompilerToolkit/CdlTkProcess.h"
#include <iomanip>
using namespace std;

namespace CdlCompilerToolkit {


//
// CleanupResetPtr
//

class CleanupResetPtr
	{
public:
	CleanupResetPtr(const CCdlTkInterface*& aPtr) : iPtr(aPtr), iValue(aPtr) {}
	~CleanupResetPtr() { iPtr = iValue; }
private:
	const CCdlTkInterface*& iPtr;
	const CCdlTkInterface* iValue;
	};


//
// CCdlTkWriteCdlFile
//

CCdlTkWriteCdlFile::CCdlTkWriteCdlFile(const CCdlTkInterface& aCdl)
: iCdl(&aCdl)
	{
	}

CCdlTkWriteCdlFile::~CCdlTkWriteCdlFile()
	{
	}

void CCdlTkWriteCdlFile::Process()
	{
	// this function modifies iCdl, but CleanupResetPtr will restore it at the end (it's also exception safe)
	CleanupResetPtr resetPtr(iCdl);

	CCdlTkFileCleanup tempFile;
	CdlTkUtil::OpenTempOutput(iOut, tempFile);
	string targetName = iCdl->FileName();

	WriteHeaderComment();
	int count = 0;
	while (iCdl)
		{
		if (count++)
			WriteSeparator("Header");
		WriteHeader();
		if (!iCdl->Cpp().empty())
			{
			WriteSeparator("C++");
			WriteCpp();
			}
		if (!iCdl->DataTypeTranslations().empty())
			{
			WriteSeparator("Translation");
			WriteTranslation();
			}
		if (!iCdl->ApiList().empty())
			{
			WriteSeparator("API");
			WriteApi();
			}
		iCdl = iCdl->Extension();
		}

	iOut.close();
	CdlTkUtil::ExportFile(tempFile, targetName);

	// resetPtr dtor will restore iCdl to original value
	}

void CCdlTkWriteCdlFile::WriteHeaderComment()
	{
	iOut << "// " << iCdl->FileName() << endl;
	iOut << "// This file was generated by:" << endl;
	iOut << "// " << CdlTkUtil::CommandLine() << endl;
	iOut << iCdl->AdditionalComment() << endl;
	}

void CCdlTkWriteCdlFile::WriteHeader()
	{
	const CCdlTkInterfaceHeader& header = iCdl->Header();
	if (!header.Name().empty())
		iOut << "Name: " << header.Name() << endl;
	iOut << "Version: " << header.Version().Major() << "." << header.Version().Minor() << endl;
	if (header.Uid())
		iOut << "UID: 0x" << setbase(16) << setw(8) << setfill('0') << header.Uid() << endl;
	const CCdlTkInterfaceHeader::CFlags& flags = header.Flags();
	for (int ii=0; ii<flags.Count(); ii++)
		{
		if (flags.IsSet(ii))
			iOut << "Flag: " << flags.FlagName(ii) << endl;
		}
	}

void CCdlTkWriteCdlFile::WriteSeparator(const string& aSection)
	{
	iOut << endl;
	iOut << "%% " << aSection << endl;
	iOut << endl;
	}

void CCdlTkWriteCdlFile::WriteCpp()
	{
	const CCdlTkCpp& cpp = iCdl->Cpp();
	if(cpp.size())
		{
		CCdlTkCpp::const_iterator pStart = cpp.begin();
		CCdlTkCpp::const_iterator pFinish = cpp.end() ;

		// ignore the first line if it's empty
		if(pStart->empty())
			++pStart;
		// if the last line isn't empty, move the iterator back to the end
		if(!(--pFinish)->empty())
			++pFinish;

		for (CCdlTkCpp::const_iterator pLine = pStart; pLine != pFinish; ++pLine)
			{
			iOut << *pLine << endl;
			}
		}
	}

void CCdlTkWriteCdlFile::WriteTranslation()
	{
	const CCdlTkDataTypeTranslations& translations = iCdl->DataTypeTranslations();
	for (CCdlTkDataTypeTranslations::const_iterator pTrans = translations.begin(); pTrans != translations.end(); ++pTrans)
		{
		if (pTrans->Source() == CCdlTkDataTypeTranslation::EFromCdl)
			{
			iOut << pTrans->Type() << " # " << pTrans->Definition() << " # " << pTrans->PointerReference() << endl;
			}
		}
	}

void CCdlTkWriteCdlFile::WriteApi()
	{
	const CCdlTkApiList& apiList = iCdl->ApiList();
	for (CCdlTkApiList::const_iterator pApi = apiList.begin(); pApi != apiList.end(); ++pApi)
		{
		CCdlTkApi& api = **pApi;
		iOut << api.Comment();
		iOut << api.ReturnType() << " " << api.Name() << api.ParamsTypeAndNameList() << ";" << endl;
		iOut << endl;
		}
	}

}	// end of namespace CdlCompilerToolkit
