/*
* 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 "CdlTkPriv.h"
#include <fstream>
#include <iomanip>
#include <iostream>
using namespace std;

namespace CdlCompilerToolkit {


CCdlTkWriteClientHeader::CCdlTkWriteClientHeader(const CCdlTkInterface& aCdl)
: iCdl(aCdl)
	{
	AssertInterfaceNotExtended(iCdl);
	}

CCdlTkWriteClientHeader::~CCdlTkWriteClientHeader()
	{
	}

void CCdlTkWriteClientHeader::Process()
	{
	string baseName = CdlBaseNameAndPath(iCdl);

	string commonHeaderName(baseName + KCommonHeader);
	CCdlTkWriteCommonDefs::ExportCommonDefs(iCdl, commonHeaderName);

	CCdlTkFileCleanup temp;
	ofstream out;
	CdlTkUtil::OpenTempOutput(out, temp);
	string clientHeaderName(baseName + ".h");
	ProcessApi(out, clientHeaderName);
	out.close();
	CdlTkUtil::ExportFile(temp, clientHeaderName);
	}

const string KClientApi = "$COMMENT $INDENT inline $TYPE $NAME $PARAMS $CONST\t\t{ $RETURN $CALL; }";
const string KClientDataCall = "*($TYPE)($SCOPE::GetData($UID, EApiId_$NAME))";
const string KClientFuncCall = "(*($TYPE)($SCOPE::GetFunction($UID, EApiId_$NAME)))($PARAMS)";

void CCdlTkWriteClientHeader::WriteApi(const CCdlTkApi& aApi, ofstream& aStream, bool aCInstanceMember, const string& aIndent) const
	{
	CdlTkUtil::CReplaceSet callSet;
	callSet.Add("$TYPE", aApi.PointerType());
	callSet.Add("$SCOPE::", aCInstanceMember ? "" : "CdlEngine::");
	callSet.Add("$UID, ", aCInstanceMember ? "" : "KCdlInterfaceUid, ");
	callSet.Add("$NAME", aApi.Name());
	callSet.Add("$PARAMS", aApi.IsFunc() ? aApi.AsFunc().ParamNameList() : "");
	string call = CdlTkUtil::MultiReplace(callSet, aApi.IsFunc() ? KClientFuncCall : KClientDataCall);

	string comment = CdlTkUtil::Replace("//", aIndent+"//", aApi.Comment());

	CdlTkUtil::CReplaceSet apiSet;
	apiSet.Add("$TYPE", ClientReturnType(aApi));
	apiSet.Add("$NAME ", aApi.Name());
	apiSet.Add("$PARAMS ", aApi.IsFunc() ? aApi.ParamsTypeAndNameList() : string("()"));
	apiSet.Add("$CONST", aCInstanceMember ? " const" : "");
	apiSet.Add("$RETURN ", (!aApi.IsFunc() || !aApi.IsVoidReturn()) ? "return " : "");
	apiSet.Add("$CALL", call);
	apiSet.Add("$INDENT ", aIndent);
	apiSet.Add("$COMMENT ", comment);
	string api = CdlTkUtil::MultiReplace(apiSet, KClientApi);

	aStream << api << endl;
	aStream << endl;
	}

string CCdlTkWriteClientHeader::ClientReturnType(const CCdlTkApi& aApi) const
	{
	string ret = aApi.ReturnType();
	if (!aApi.IsFunc())
		ret += " const&";
	return ret;
	}


const string KBodyStart = "\
/*\n\
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).\n\
* All rights reserved.\n\
* This component and the accompanying materials are made available\n\
* under the terms of \"Eclipse Public License v1.0\"\n\
* which accompanies this distribution, and is available\n\
* at the URL \"http://www.eclipse.org/legal/epl-v10.html\".\n\
*\n\
* Initial Contributors:\n\
* Nokia Corporation - initial contribution.\n\
*\n\
* Contributors:\n\
*\n\
* Description:\n\
*\n\
*/\n\n\
// This file was generated by:\n\
// $CMDLINE\n\
// It contains the client API.\n\
// It should not be modified manually.\n\
\n\
$ADDITIONAL\
#ifndef $CDLGUARD\n\
#define $CDLGUARD\n\
\n\
#include <CdlEngine.h>\n\
#include <$FILE.common.h>\n\
\n\
namespace $CDLNS\n\
{\n\
\n\
class CInstance;\n\
\n\
// Standard interface functions \n\
inline void LoadCustomisationL(const TCdlRef& aRef)                          { CdlEngine::LoadCustomisationL(aRef); }\n\
inline void LoadCustomisationL(const TDesC& aLibName, TInt aInstId)          { TCdlRef ref = { aInstId, { KCdlInterfaceUidValue }, &aLibName }; LoadCustomisationL(ref); }\n\
inline void RequireCustomisationL()                                          { CdlEngine::RequireCustomisationL(&KCdlInterface); }\n\
inline TBool IsCustomisationStarted()                                        { return CdlEngine::IsCustomisationStarted(&KCdlInterface); }\n\
inline const CInstance& CustomisationInstance()                              { return (const CInstance&)(CdlEngine::CustomisationInstance(KCdlInterfaceUid)); }\n\
inline void SetCustomisationChangeObserverL(MCdlChangeObserver* aObserver)   { CdlEngine::SetCustomisationChangeObserverL(aObserver, KCdlInterfaceUid); }\n\
\n\
inline const TCdlRef& LastAccessedRef()                                      { return CdlEngine::LastAccessedRef(KCdlInterfaceUid); }\n\
inline void FileNameRelativeToLastAccessedInstance(TFileName& aFileName)     { CdlEngine::FileNameRelativeToLastAccessedInstance(KCdlInterfaceUid, aFileName); }\n\
\n\
\n\
// CDL API functions, as defined in $FILE\n\
\n";

const string KPragmaMinTypeInfo = "\
#ifdef __VC32__\n\
#pragma component(mintypeinfo, $ONOFF)\n\
#endif\n\
\n";

const string KBodyMid = "\
\n\
\n\
class CInstance : public CCdlInstance\n\
\t{\n\
public:\n\
\tenum { ETypeId = KCdlInterfaceUidValue };\n\
\n\
\tinline static const CInstance& CustomisationInstance()                                                    { return (const CInstance&)(CdlEngine::CustomisationInstance(KCdlInterfaceUid)); }\n\
\tinline static CInstance* NewL(const TCdlRef& aRef, const CCdlInstance* aSubLayer = NULL)                  { return (CInstance*) CCdlInstance::NewL(aRef, &KCdlInterface, aSubLayer); }\n\
\tinline static CInstance* NewLC(const TCdlRef& aRef, const CCdlInstance* aSubLayer = NULL)                 { return (CInstance*) CCdlInstance::NewLC(aRef, &KCdlInterface, aSubLayer); }\n\
\tinline static CInstance* NewL(const TDesC& aLibName, TInt aImplId, const CCdlInstance* aSubLayer = NULL)  { TCdlRef ref = { aImplId, { KCdlInterfaceUidValue }, &aLibName }; return NewL(ref, aSubLayer); }\n\
\tinline static CInstance* NewLC(const TDesC& aLibName, TInt aImplId, const CCdlInstance* aSubLayer = NULL) { TCdlRef ref = { aImplId, { KCdlInterfaceUidValue }, &aLibName }; return NewLC(ref, aSubLayer); }\n\
\n\
\tinline const CInstance* SubLayer()                                                                        { return static_cast<const CInstance*>(CCdlInstance::SubLayer()); }\n\
\n\
// CDL API functions, as defined in $FILE\n\
\n";

const string KBodyEnd = "\
private:\n\
\tCInstance();\n\
\t};\n\
\n";

const string KBodyEndNameSpace = "\
} // end of namespace $CDLNS\n\
#endif // $CDLGUARD\n";

const unsigned int KMsvcClassMaxSize = 1000;
const string KTypeInfoOn = "on";
const string KTypeInfoOff = "off";

void CCdlTkWriteClientHeader::ProcessApi(ofstream& aStream, const string& aFileName) const
	{
	CdlTkUtil::CReplaceSet replace;
	replace.Add("$FILE", CdlTkUtil::ToLower(CdlTkUtil::StripPath(iCdl.FileName())));
	replace.Add("$CDLGUARD", HeaderGuardName(iCdl.FileName()));
	replace.Add("$CDLNS", iCdl.NamespaceName());
	replace.Add("$CMDLINE", CdlTkUtil::CommandLine());
	replace.Add("$ADDITIONAL", iCdl.AdditionalComment());

	bool tooMuchTypeInfo = iCdl.ApiList().size() > KMsvcClassMaxSize;

	aStream << CdlTkUtil::MultiReplace(replace, KBodyStart);

	CCdlTkApiList::const_iterator pApi;
	for (pApi = iCdl.ApiList().begin(); pApi != iCdl.ApiList().end(); ++pApi)
		WriteApi(**pApi, aStream, false, "");

	if(tooMuchTypeInfo)
		aStream << CdlTkUtil::Replace("$ONOFF", KTypeInfoOn, KPragmaMinTypeInfo);

	aStream << CdlTkUtil::MultiReplace(replace, KBodyMid);

	for (pApi = iCdl.ApiList().begin(); pApi != iCdl.ApiList().end(); ++pApi)
		WriteApi(**pApi, aStream, true, "\t");

	aStream << CdlTkUtil::MultiReplace(replace, KBodyEnd);

	if(tooMuchTypeInfo)
		aStream << CdlTkUtil::Replace("$ONOFF", KTypeInfoOff, KPragmaMinTypeInfo);

	aStream << CdlTkUtil::MultiReplace(replace, KBodyEndNameSpace);
	}


}	// end of namespace CdlCompilerToolkit

