/*
* Copyright (c) 2006-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 "CmdGlobals.h"
#ifdef __WIN__
#pragma warning(disable:4786)
#endif

#include <vector>
#include <algorithm>
#include "PlatformData.h"
#include "XMLUtils.h"
#include "XMLStringConst.h"
#include "Utils.h"
#include "BBCFileUtils.h"
#include "HAException.h"


const char* XML_FILE_ID_ATTRIBUTE = "id";

/**
 * Generic utility function, which checks whether the given object is
 * in the vector.
 */
template <typename C>
inline bool IsObjectInVector(const vector<C>& v, const C& o)
{ 
    return std::find(v.begin(), v.end(), o) != v.end();
}

// Convert to proper dir-separator
string& FixPathString(string& str)
{
    string::size_type dirSepInd = str.find_first_of("\\/");
    if( dirSepInd != string::npos && str.at(dirSepInd) != DIR_SEPARATOR )
    {        
        replaceChar(str, str.at(dirSepInd), DIR_SEPARATOR);
    }
    return str;
}

/**
 *
 */
ComponentFile::ComponentFile()
:
iComponent(0)
{}

/**
 *
 */
ComponentFile::ComponentFile(const string& ID, Component* comp)
: 
iID(ID),
iComponent(comp)
{ }

/**
 *
 */
ComponentFile::ComponentFile(const ComponentFile &rhs)
:
iID(rhs.ID()),
iName(rhs.FileName()),
iPath(rhs.Path()),
iComponent(rhs.GetComponent())
{ }

/**
 *
 */
ComponentFile::~ComponentFile()
{ }

/**
 *
 */
const string& ComponentFile::ID() const
{
    return iID;
}

/**
 *
 */
const string& ComponentFile::FileName() const
{
    return iName;
}

/**
 *
 */
const string& ComponentFile::Path() const
{
    return iPath;
}

/**
 *
 */
void ComponentFile::SetID(const string& ID)
{
    iID = ID;
}

/**
 *
 */
void ComponentFile::SetFileName(const string& name)
{
    iName = name;
}

/**
 *
 */
void ComponentFile::SetPath(const string& path)
{
    iPath = path;
}

/**
 *
 */
Component* ComponentFile::GetComponent() const
{
    return iComponent;
}

/**
 *
 */
void ComponentFile::SetComponent(Component* comp)
{
    iComponent = comp;
}

/**
 *
 */
string ComponentFile::ForcedInclude()
{
return iForcedInclude;
}

pair<string,string>& ComponentFile::APIinfo()
{
    return iApiInfo;
}

/**
 *
 */
const ComponentFile& ComponentFile::operator= (const ComponentFile& rhs)
{
    if( &rhs != this )
    {
        iID = rhs.ID();
        iName = rhs.FileName();
        iPath = rhs.Path();
        iComponent = rhs.GetComponent();
    }
    return *this;
}

/**
 *
 */
bool ComponentFile::operator== (const ComponentFile& rhs) const
{
    return  iID == rhs.ID() &&
//            iName == rhs.iName &&
//            iPath == rhs.iPath &&
            iComponent == iComponent;
}

/**
 *
 */
void ComponentFile::ProcessAttributes(XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* node)
{
    // Read "fileid"-attribute:
    const XMLCh* fileIdAttr = GetAttribute(node, XML_FILE_ID_ATTRIBUTE);
    if( fileIdAttr )
    {
        string str(toString(fileIdAttr));
        iID = FixPathString(toLower(str));        
    }
}

/**
 * Reads child elements from the parsed XML (DOM) data. This baseclass implementation
 * processes the "filename", "relativepath" and "include" elements, which are common 
 * to all component files.
 */
bool ComponentFile::ProcessChildElement(XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* node, PlatformData* platform)
{    
    if( node->getNodeType() != DOMNode::ELEMENT_NODE )
        return false;

    bool properChild = false;

    const XMLCh* elementtype = node->getNodeName();
    if( elementtype )
    {
        string elemtypeStr(toString(elementtype));

		//Handle the API info.
		if( elemtypeStr == PLATFORM_ELEMENT_API_NAME )
        {
			XERCES_CPP_NAMESPACE_QUALIFIER DOMElement* apiNode = (DOMElement*)node;
			char* apiname = _X( apiNode->getAttribute( _X( "name" ) ) );
			char* apiCategory = _X( apiNode->getAttribute( _X( "category" ) ) );

			iApiInfo.first = apiname;
			iApiInfo.second = apiCategory;

			_XX(apiname);
			_XX(apiCategory);
        }
        if( elemtypeStr == PLATFORM_ELEMENT_INCLUDE )
        {
            // Handle include element
            const XMLCh* nodeVal = node->getTextContent();
            if( nodeVal )
            {
                string tempStr(toString(nodeVal));
                iIncludes.push_back(FixPathString(toLower(tempStr)));
                properChild = true;
            }
        }
        else if( elemtypeStr == PLATFORM_ELEMENT_INCLUDEPATH )
        {
            // Include paths:
            const XMLCh* nodeVal = node->getTextContent();
            if( nodeVal )
            {
                string tempStr(toString(nodeVal));
                iIncludePaths.push_back(FixPathString(toLower(tempStr)));                
                properChild = true;
            }
        }
        else if( elemtypeStr == PLATFORM_ELEMENT_FORCEDINCLUDE )
        {
            // Forced Include:
            const XMLCh* nodeVal = node->getTextContent();
            if( nodeVal )
            {
                iForcedInclude=toString(nodeVal);
                properChild = true;
            }
        }
    }
    return properChild;
}

/**
 *
 */
const vector<string>& ComponentFile::IncludePaths() const
{
    return iIncludePaths;
}

/**
 *
 */
void ComponentFile::AddIncludePath(const string& incPath)
{
    if( IsObjectInVector<string>(iIncludePaths, incPath) == false )
        iIncludePaths.push_back(incPath);
}

const vector<string>& ComponentFile::Includes() const
{
    return iIncludes;
}

void ComponentFile::AddInclude(const string& incHdr)
{
    if( IsObjectInVector<string>(iIncludes, incHdr) == false )
        iIncludes.push_back(incHdr);
}

void ComponentFile::SetIncludes(const vector<string>& incs)
{
    iIncludes = incs;
}

ParsedElement::ParsedElement()
{}

ParsedElement::~ParsedElement()
{}

/**
 * Initializes the element using parsed XML (DOM) data. This method initiates
 * attribute processing, child element processing and adds the element to
 * the platform data object.
 */
bool ParsedElement::Initialize(DOMNode* node, PlatformData* platform)
{
    if( node == 0 || platform == 0 )
        return false;

    iRootDir = platform->GetRootDir();

    // Read and process attributes of xml-element:
    ProcessAttributes(node);
                
    // Process child elements:
    DOMNodeList* childNodes = node->getChildNodes();
    XMLSize_t childListLen = 0;
    if( childNodes )
    {
        childListLen = childNodes->getLength();
        for( XMLSize_t cI = 0; cI < childListLen; ++cI )
        {
            DOMNode* childNode = childNodes->item(cI);
            if( childNode )
            {                
                ProcessChildElement(childNode, platform);                
            }
        }
    }

    // Add this element to a proper container of the platform data object:
    return AddToPlatform(platform);
}

/**
 *
 */
Project::Project()
{}

/**
 *
 */
Project::Project(const string& prjID, Component* comp) 
: ComponentFile(prjID, comp)
{ }
 
/**
 *
 */
Project::~Project()
{ }

/**
 * Adds this project element to platform's project list.
 */
bool Project::AddToPlatform(PlatformData* platform)
{
    return platform->AddProject(this);
}

/**
 * Processes the given child element. Project can have following
 * child elements:
 *  - includepath
 *  - source
 */
bool Project::ProcessChildElement(DOMNode* child, PlatformData* platform)
{   
    if( ComponentFile::ProcessChildElement(child, platform) == true )
        return true;

    bool properChild = false;
    const XMLCh* childtype = child->getNodeName();
    if( childtype )
    {
        string childtypeStr(toString(childtype));
        const XMLCh* nodeVal = child->getTextContent();
        if( nodeVal )
        {                        
            if( childtypeStr == PLATFORM_ELEMENT_SOURCE )
            {
                Source* srcObj = new Source();
                if( srcObj->Initialize(child, platform) )
                {
                    iSourceObjs.push_back(srcObj);
                    properChild = true;
                }
                else
                    delete srcObj;
            }
        }
    }
    return properChild;
}

/**
 * 
 */
const FileList& Project::Sources() const
{
    return iSourceObjs;
}

/**
 * 
 */
string Project::PrettyPrint(int indentSpaces) const
{
    string ret;
    for( int i = 0; i < indentSpaces; ++i )
    {
        ret += " ";
    }
    ret += string("Project ID: ") + iID + "\n";
    for( int i = 0; i < indentSpaces; ++i )
    {
        ret += " ";
    }
    ret += "Sources:\n";
    for( FileList::const_iterator s = iSourceObjs.begin(); s != iSourceObjs.end(); ++s )
    {
        ret += (*s)->PrettyPrint(indentSpaces+2);
    }
    return ret;
}

/**
 * Header
 */
Header::Header()
:
iCachedIncludes(0),
iCachedIncludePaths(0),
iCachedForcedInclude("")
{}
/**
 * 
 */
Header::Header(const string& hdrID, Component* comp) 
: 
ComponentFile(hdrID, comp),
iCachedIncludes(0),
iCachedIncludePaths(0),
iCachedForcedInclude("")
{ }

/**
 * 
 */
Header::~Header()
{ 
    delete iCachedIncludes;
    delete iCachedIncludePaths;
}

/**
 * 
 */
Header::STATUS Header::Status() const
{
    return iStatus;
}

/**
 * 
 */
void Header::SetStatus(Header::STATUS s)
{
    iStatus = s;
}

/**
 * 
 */
bool Header::AddToPlatform(PlatformData* platform)
{
    return platform->AddHeader(this);
}

/**
 *
 */
string Header::PrettyPrint(int indentSpaces) const
{
    string ret;
    for( int i = 0; i < indentSpaces; ++i )
    {
        ret += " ";
    }
    ret += string("Header ID: ") + iID + "\n";

    return ret;
}

void Header::ProcessAttributes(XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* node)
{
    /**
     * Header element uses absolute path as a key, since that way it is easier
     * to map this element to the filenames used in Analyser. Absolute path
     * is calculated merging the root directories given in parameters (i.e BASELINEDIR
     * and CURRENTDIR).
     */
    const XMLCh* fileIdAttr = GetAttribute(node, XML_FILE_ID_ATTRIBUTE);
    if( fileIdAttr )
    {
        string tempStr(toString(fileIdAttr));
        FixPathString(toLower(tempStr));
        // Merge root and element directories.
        // START -- Support for multiple header directories --
        list<pair<string, bool> > fullID = BBCFileUtils::MergeDirs(iRootDir, tempStr);
        list<pair<string, bool> >::iterator fulliterbegin = fullID.begin();
        for(; fulliterbegin != fullID.end(); fulliterbegin++)
        {
          if( fulliterbegin->second )
          {
            iID = fulliterbegin->first;
          }
        }
        // END -- Support for multiple header directories --
    }
}

/**
 * When IncludesForHeader() method of PlatformData is called, PlatformData
 * retrieves the additional include directives from all the sources in the 
 * component and caches the include directives to Header object, so next 
 * time the retrival is faster. 
 */

/**
 * 
 */
const vector<string>* Header::CachedIncludes() const
{
    return iCachedIncludes;
}

/**
 * 
 */
void Header::SetCachedIncludes(vector<string>* incs)
{
    if( iCachedIncludes )
        delete iCachedIncludes;
    iCachedIncludes = incs;
}

/**
 * When IncludesPathsForHeader() method of PlatformData is called, PlatformData
 * retrieves the include paths from all the projects in the component and 
 * caches the include paths to Header object, so next time the retrival is
 * faster.
 */

/**
 *
 */
const vector<string>* Header::CachedIncludePaths() const
{
    return iCachedIncludePaths;
}

/**
 *
 */
void Header::SetCachedIncludePaths(vector<string>* incPaths)
{
    if( iCachedIncludePaths )
        delete iCachedIncludePaths;
    iCachedIncludePaths = incPaths;
}


/**
 * When IncludesForHeader() method of PlatformData is called, PlatformData
 * retrieves the additional forced include directive from the component
 * and caches the forced include directive to Header object, so next 
 * time the retrival is faster. 
 */

/**
 * 
 */
string Header::CachedForcedInclude() const
{
    return iCachedForcedInclude;
}

string Header::CachedSource() const
{
	return iCacheSrcObj;
}

/**
 * 
 */
void Header::SetCachedForcedInclude(string finc)
{
    iCachedForcedInclude = finc;
}

void Header::SetCachedSourceFile (string srcObj)
{
	iCacheSrcObj = srcObj;
}
/**
 * Source
 */
Source::Source()
{}

/**
 * 
 */
Source::Source(const string& srcID, Component* comp) 
: ComponentFile(srcID, comp)
{ }

/**
 * 
 */
Source::~Source()
{ }

/**
 * 
 */
bool Source::AddToPlatform(PlatformData* platform)
{
    return platform->AddSource(this);
}

/**
 *
 */
string Source::PrettyPrint(int indentSpaces) const
{
    string ret;
    for( int i = 0; i < indentSpaces; ++i )
    {
        ret += " ";
    }
    ret += string("Source ID: ") + iID + "\n";
    for( int i = 0; i < indentSpaces; ++i )
    {
        ret += " ";
    }
    ret += "Include directives:\n";
    for( vector<string>::const_iterator inc = iIncludes.begin(); inc != iIncludes.end(); ++inc )
    {
        for( int i = 0; i < indentSpaces+2; ++i )
        {
            ret += " ";
        }
        ret += *inc + "\n";
    }

    return ret;
}

/**
 * Component
 */
Component::Component()
{ }

/**
 *
 */
Component::Component(const string& compID, Component* comp)
: 
ComponentFile(compID, comp)
{ }

/**
 *
 */
Component::~Component()
{ }
   
/**
 *
 */
const FileList& Component::Headers() const
{
    return iHeaders;
}

/**
 *
 */
FileList& Component::Headers()
{
    return iHeaders;
}

/**
 *
 */
const FileList& Component::Projects() const
{
    return iProjects;
}

/**
 *
 */
FileList& Component::Projects()
{
    return iProjects;
}

/**
 *
 */
void Component::AddHeader(ComponentFile* hdr)
{ 
    if( IsObjectInVector<ComponentFile*>(iHeaders, hdr) == false )
    {
        iHeaders.push_back(hdr);
    }
}

/**
 *
 */
void Component::AddProject(ComponentFile* prj)
{ 
    if( IsObjectInVector<ComponentFile*>(iProjects, prj) == false )
    {
        iProjects.push_back(prj);
    }
}

/**
 * Processes child elements. Component can have following child elements:
 *  - Header
 *  - Project reference
 */
bool Component::ProcessChildElement(DOMNode* child, PlatformData* platform)
{   
    if( ComponentFile::ProcessChildElement(child, platform) == true )
        return true;

    bool properChild = false;
    const XMLCh* childtype = child->getNodeName();
    if( childtype )
    {
        string childtypeStr(toString(childtype));
        if( childtypeStr == PLATFORM_ELEMENT_HEADER )
        {            
            Header* hdr = new Header();
			string headerID(this->ID());
            if( hdr->Initialize(child, platform) )
			{
				if(headerID == PLATFORM_IGNORED_COMPONENT )
					hdr->SetStatus(Header::HDR_STATUS_IGNORE);

				XERCES_CPP_NAMESPACE_QUALIFIER DOMElement* hdrNode = (DOMElement*)child;
				char* headername = _X( hdrNode->getAttribute( _X( "id" ) ) );
				string header (headername);
				header = FixPathString(toLower(header)); 
				int loc = header.find_last_of(DIR_SEPARATOR);
				if(loc != -1 )
				{
					// store header file name and path from header id tag only.
					hdr->SetFileName(header.substr(loc+1,string::npos));
					hdr->SetPath(header.substr(0,loc));
				}
				_XX(headername);

				hdr->SetComponent(this);
				iHeaders.push_back(hdr);
				properChild = true;
			}
            else
            {                
                delete hdr;                
            }
        }
        else if( childtypeStr == PLATFORM_ELEMENT_PROJECT )
        {            
            Project* prj = new Project();
            if (prj->Initialize(child, platform) )
            {
                prj->SetComponent(this);
                iProjects.push_back(prj);
                properChild = true;
            }
            else
            {
                delete prj;
            }
        }       
    }
    return properChild;
}

/**
 *
 */
bool Component::AddToPlatform(PlatformData* platform)
{
    return platform->AddComponent(this);
}

/**
 *
 */
string Component::PrettyPrint(int indentSpaces) const
{
    string ret;
    for( int i = 0; i < indentSpaces; ++i )
    {
        ret += " ";
    }
    ret += string("Component ID: ") + iID + "\n";
    for( int i = 0; i < indentSpaces; ++i )
    {
        ret += " ";
    }
    ret += "Headers:\n";
    for( FileList::const_iterator h = iHeaders.begin(); h != iHeaders.end(); ++h )
    {        
        ret += (*h)->PrettyPrint(indentSpaces+2);
    }

    for( int i = 0; i < indentSpaces; ++i )
    {
        ret += " ";
    }
    ret += "Projects\n";

    for( FileList::const_iterator p = iProjects.begin(); p != iProjects.end(); ++p )
    {
        ret += (*p)->PrettyPrint(indentSpaces+2);
    }

    return ret;
}

/**
 * PlatformData contains all the elements defined in the platrofm input file.
 * It parses the XML-file and populates the internal containers. It also
 * has different kind of methods for retrieving the data and the associations
 * between elements.
 */
PlatformData::PlatformData(const string& pfVersion, const string& rootDir)
:
iDOMParser(0),
iDOMDoc(0),
iDOMRootElement(0),
iPfVersion(pfVersion),
iRootDir(rootDir)
{ }

/**
 *
 */
PlatformData::~PlatformData()
{
    if (iDOMParser != NULL)
    {
        iDOMParser->resetDocumentPool();
        iDOMParser->release();
        iDOMParser = NULL;
    }

    CFileMap::iterator i;

    for( i = iHeadersById.begin(); i != iHeadersById.end(); ++i )
    {
        delete i->second;
    }

    for( i = iProjectsById.begin(); i != iProjectsById.end(); ++i )
    {
        delete i->second;
    }

    for( i = iSourcesById.begin(); i != iSourcesById.end(); ++i )
    {
        delete i->second;
    }

    for( ComponentList::iterator ic = iCList.begin(); ic != iCList.end(); ++ic )
    {
        delete ic->second;
    }
}

/**
 *
 */
void PlatformData::Initialize(const string& dataFileName)
{
    // First read and parse the XML-file:
    int ret = 0;
    if (iDOMParser != NULL) 
    {
        iDOMParser->resetDocumentPool();
        iDOMParser->release();
        iDOMParser = 0;
    }
    cout << "Parsing platform data for " << iPfVersion << "...";
    try {
        ret = ParseXMLFile(dataFileName, iDOMParser, iDOMDoc, iDOMRootElement);
    }
    catch (HAException&)
    {
        cout.flush();
        cerr.flush();
        cerr << "Failed!" << endl;
        if( iDOMParser )
        {
            iDOMParser->resetDocumentPool();
            iDOMParser->release();
            iDOMParser = 0;
        }
        throw;
    }
    cout << "Done." << endl;

    // Then traverse the DOM tree and populate the containers:
    cout << "Initializing platform data for " << iPfVersion << "...";
    try {
        InitializeElements();
    }
    catch( HAException& )
    {
        cerr << "Failed." << endl;
        iDOMParser->resetDocumentPool();
        iDOMParser->release();
        iDOMParser = 0;
        throw;
    }
    cout << "Done." << endl;
    iDOMParser->resetDocumentPool();
    iDOMParser->release();
    iDOMParser = 0;    
    cout << "Platform " << iPfVersion << " successfully initialized from platform " << iVersionStr << " data!"  << endl << endl;
}

/**
 *
 */
bool PlatformData::AddComponent(Component* comp)
{
    return iCList.insert(make_pair<string, Component*>( comp->ID(), comp )).second;
}

/**
 *
 */
bool PlatformData::AddProject(Project* prj)
{
    if( iProjectsById.insert(make_pair<string, ComponentFile*>(prj->ID(), prj)).second == false )
        return false;

    return true;
}

/**
 *
 */
bool PlatformData::AddSource(Source* src)
{
    if( iSourcesById.insert(make_pair<string, ComponentFile*>(src->ID(), src)).second == false )
        return false;

    return true;
}

/**
 *
 */
bool PlatformData::AddHeader(Header* hdr)
{
    if( iHeadersById.insert(make_pair<string, ComponentFile*>(hdr->ID(), hdr)).second == false )
        return false;
        
    return true;
}

/**
 * Factory method for creating element objects.
 */
ParsedElement* PlatformData::CreateElement( XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* node )
{
    const string elementType( toString( node->getNodeName() ));
    ParsedElement* elem = 0;

    if( elementType == PLATFORM_ELEMENT_COMPONENT )
    {
        elem = new Component();
    }                
    else if( elementType == PLATFORM_ELEMENT_PROJECT )
    {
        elem = new Project();            
    }        
    else if( elementType == PLATFORM_ELEMENT_SOURCE )
    {
        elem = new Source();            
    }

    return elem;
}

/**
 * Traverses through the DOM-tree and builds element objects.
 */
void PlatformData::InitializeElements()
{
    if( iDOMDoc == 0 || iDOMRootElement == 0)
        throw HAException(string("Platform ") + string(iPfVersion) + string(" initialization failed.\n"));
    DOMNodeIterator* domIter = iDOMDoc->createNodeIterator(iDOMRootElement, DOMNodeFilter::SHOW_ELEMENT, NULL, true);
    if( domIter == 0 )
        throw HAException(string("Platform ") + string(iPfVersion) + string(" initialization failed.\n"));
    DOMNode* root = domIter->getRoot();
    if( root )
    {
        const XMLCh* platformVersion = GetAttribute(root, KXMLPlatformVersion);
        if( platformVersion )
            iVersionStr = toString(platformVersion);
    }
    DOMNode* nodeIter = 0;
    ParsedElement* elem = 0;
    while( (nodeIter = domIter->nextNode()) != 0 )
    {
        elem = CreateElement(nodeIter);
        if( elem && elem->Initialize(nodeIter, this) == false )
        {
            delete elem;            
        }
    }

    domIter->release();
}

/**
 * 
 */
const CFileMap& PlatformData::HeadersById() const
{
    return iHeadersById;
}

/**
 * 
 */
const CFileMap& PlatformData::ProjectsById() const
{
    return iProjectsById;
}

/**
 * 
 */
CFileMap& PlatformData::ProjectsById()
{
    return iProjectsById;
}

/**
 * 
 */
const CFileMap& PlatformData::SourcesById() const
{
    return iSourcesById;
}

/**
 * Finds include paths defined in the projects belonging to the 
 * same component than the header.
 */
const vector<string>& PlatformData::IncludePathsForHeader(const string& headerID)
{
    CFileMap::const_iterator hdrIter = iHeadersById.find(headerID);
    if( hdrIter != iHeadersById.end() )
    {
        Header* hdrObj = dynamic_cast<Header*>(hdrIter->second);
        if( hdrObj )
            return IncludePathsForHeader(hdrObj);
    }

    return iDummyStringVector;
}

/**
 * Finds include paths defined in the projects belonging to the 
 * same component than the header.
 */
const vector<string>& PlatformData::IncludePathsForHeader(Header* hdrObj)
{
    if( hdrObj == 0 )
        return iDummyStringVector;

    // First try to find includes from the cache:
    const vector<string>* cached = hdrObj->CachedIncludePaths();
    if( cached )
    {
        return *cached;
    }
    
    auto_ptr<vector<string> > newVector(new vector<string>());        
    Component* comp = 0;

    if( (comp = hdrObj->GetComponent()) != 0 )
    {
        // First insert the include paths defined in component level:
        newVector->insert(newVector->end(), comp->IncludePaths().begin(),  comp->IncludePaths().end());

        const FileList& prjs = comp->Projects();
        for( FileList::const_iterator prj = prjs.begin(); prj != prjs.end(); ++prj )
        {
            Project* prjObj = dynamic_cast<Project*>(*prj);
            if( prjObj )
            {
                const vector<string>& iPaths = prjObj->IncludePaths();
                vector<string>::const_iterator ip = iPaths.begin();

                for( ; ip != iPaths.end(); ++ip )
                {
                    if( !IsObjectInVector(*newVector, *ip) )
                    {
                        newVector->push_back(*ip);
                    }
                }
            }
        }
    }

    const vector<string>& hdrIncs = hdrObj->IncludePaths();
    for( vector<string>::const_iterator i = hdrIncs.begin(); i != hdrIncs.end(); ++i )
    {
        if( !IsObjectInVector(*newVector, *i) )
        {
            newVector->push_back(*i);
        }
    }

    // variable to track whether project has been found
    bool found = false;
    // Find a project in the platform data which includes the header under analysis and
    // add all paths in the mmp file as dependencies before compilation. 
    for( CFileMap::const_iterator pIter = iProjectsById.begin(); pIter != iProjectsById.end() && !found; ++pIter )
    {
        //First iterate over projects
        Project* prj = dynamic_cast<Project*>(pIter->second);
        const FileList& src = prj->Sources();
        FileList::const_iterator sIter = src.begin();
        for(;sIter != src.end() && !found; ++sIter)
        {
            // then search each source include in individual projects
            Source* so = dynamic_cast<Source*>(*sIter);
            const vector<string>& inc = so->Includes();
            vector<string>::const_iterator iIter = inc.begin();
            for(;iIter != inc.end() && !found; ++iIter)
            {
                string::size_type dirEnd = (*iIter).find_last_of('/\\');
                // IF header found
                if( (dirEnd == string::npos && *iIter == hdrObj->FileName()) ||
                    (dirEnd != string::npos && string((*iIter).begin()+dirEnd+1, (*iIter).end()) == hdrObj->FileName()))
                {
                    const vector<string>& tmp = prj->IncludePaths();
					if( IsObjectInVector<string>(tmp, hdrObj->Path()) )
					{
						vector<string>::const_iterator str = tmp.begin();
						for(;str != prj->IncludePaths().end(); ++str)
						{
							// only include paths which are not already present
							if( !IsObjectInVector<string>(*newVector, *str) )
							{
								newVector->insert(newVector->end(), *str);
								found = true;
							}
						}
					}
                }
            }
        }
    }
    hdrObj->SetCachedIncludePaths(newVector.release());
    return *(hdrObj->CachedIncludePaths());
}

/**
 * Finds include directives used with this header when the header
 * is compiled. Algorithm finds the <code>Header</code> object using 
 * the given ID and then calls overloaded <code>IncludesForHeader</code> 
 * using the <code>Header</code> object.
 */
const vector<string>& PlatformData::IncludesForHeader( const string& headerID )
{
    CFileMap::const_iterator hdrIter = iHeadersById.find(headerID);
    if( hdrIter != iHeadersById.end() )
    {
        Header* hObj = dynamic_cast<Header*>(hdrIter->second);
        if( hObj )
            return IncludesForHeader(hObj);
    }
    return iDummyStringVector;
}

void PlatformData::IncludesFromSource(const Header* hObj, const Source* srcObj, vector<string>& includes) const
{
    const vector<string>& includeDirectives = srcObj->Includes();
    vector<string>::const_iterator inc = includeDirectives.begin();
    for( ; inc != includeDirectives.end(); ++inc )
    {
        string::size_type dirEnd = (*inc).find_last_of("/\\");

        if( (dirEnd == string::npos && *inc == hObj->FileName()) ||
            (dirEnd != string::npos && string(inc->begin()+dirEnd+1, inc->end()) == hObj->FileName()))
        {
            // The header was found. Take all the preceding include directives:
            for( vector<string>::const_iterator tempIt = includeDirectives.begin(); tempIt != inc; ++tempIt)
            {
                if( IsObjectInVector(includes, *tempIt) == false )
                {                            
                    includes.push_back(*tempIt);
                }        
            }
            break;
        }
    }
}

/**
 * Finds include directives used with this header when the header
 * is compiled. Algorithm find first all the projects belonging
 * to the same component than the given <code>Header</code> object.
 * Then it finds all the source files belonging to the projects.
 * Then it scans the source files and if a source file includes
 * this header, all the preceding include directives in that source
 * file are inserted to the result vector.
 *
 * An example:
 *
 * Header, id: epoc32/include/hdr1.h, belongs to component c, which
 * contains one project p.mmp. Project p.mmp contains two source files:
 * s1.cpp and s2.cpp. Source s1.cpp includes hdrX.h, hdrY.h and hdr1.h 
 * (in that order). Source s2.cpp does not include the hdr1.h at all.
 * The returned headers in above example would be hdrX.h and hdrY.h.
 */
const vector<string>& PlatformData::IncludesForHeader(Header* hObj, Header* baseHObj)
{
	string tempSpurceObj;
    if( hObj == 0 )
        return iDummyStringVector;

    if( hObj->CachedIncludes() != 0 )
        return *(hObj->CachedIncludes());

           
    // Start build new include list:
    auto_ptr<vector<string> > newVector(new vector<string>());        
    Component* comp = 0;

    if( (comp = hObj->GetComponent()) != 0 )
    {
        //set the forced header for this header
        hObj->SetCachedForcedInclude(comp->ForcedInclude());
        // Insert include directives defined in component level:
        newVector->insert(newVector->end(), comp->Includes().begin(), comp->Includes().end());

        // Then find all the sources that are including this header and get all the preceding include
        // directives from the sources. The shortest list will do.

        const FileList& projects = comp->Projects(); // All the projects in this component
        FileList::const_iterator fIter = projects.begin();

        // Get needed source files from the projects of this component:
        FileList srcObjs;
        for( ; fIter != projects.end(); ++fIter )
        {
            Project* prj = dynamic_cast<Project*>(*fIter);        
            if( prj )
            {                    
                srcObjs.insert(srcObjs.end(), prj->Sources().begin(), prj->Sources().end());
            }
        }

        // Next we investigate the include directives of each source file
        // and get all the headers that are included before the given 
        // header file.
        auto_ptr<vector<string> > includesFromSrc(0);
        for( FileList::iterator src = srcObjs.begin(); src != srcObjs.end(); ++src )
        {
            Source* srcObj = dynamic_cast<Source*>(*src);        
            if( srcObj == 0 )
                continue;

            const vector<string>& includeDirectives = srcObj->Includes();
            vector<string>::const_iterator inc = includeDirectives.begin();
            auto_ptr<vector<string> > tmpIncludes(new vector<string>());
           
            IncludesFromSource(hObj, srcObj, *tmpIncludes);
            if( includesFromSrc.get() == 0 ||
                (tmpIncludes->size() > 0 && (tmpIncludes->size() < includesFromSrc->size() || includesFromSrc->size()==0) ))
            {
				tempSpurceObj = srcObj->ID();
                includesFromSrc = tmpIncludes; // Get the smallest possible set of additional includes.
            }
        }
        if( includesFromSrc.get() )
        {
            newVector->insert(newVector->end(), includesFromSrc->begin(), includesFromSrc->end());
        }
    }

    if( newVector->size() == 0 )
    {
        // No includes found. Let's try to find some source from other components. First one will do...
        for( CFileMap::const_iterator s = iSourcesById.begin(); s != iSourcesById.end(); ++s )
        {
            auto_ptr<vector<string> > tmpIncludes(new vector<string>());
            Source* sO = dynamic_cast<Source*>(s->second);
            if( sO )
            {
                IncludesFromSource(hObj, sO, *tmpIncludes);
                if( tmpIncludes->size() > 0 )
				{
					string curSrc;
					string baseSrc;
					if ( baseHObj != NULL) // IncludesForHeader() is called for current sdk
					{
						string::size_type loc = sO->ID().find_last_of('/\\');
						if(loc != string::npos )
							curSrc = sO->ID().substr(loc+1 , string::npos);
						loc = string::npos;
						loc = baseHObj->CachedSource().find_last_of('/\\');
						if(loc != string::npos)
							baseSrc = baseHObj->CachedSource().substr(loc+1, string::npos);
					}
					// If the header is of baseline sdk or the current headers source file name is same as baseline's source file,
					// In both of these cases , the dependent headers will be taken from platform data file
					if(baseHObj == NULL || (baseSrc.size() > 0 && baseSrc == curSrc) )
					{
						newVector->insert(newVector->end(), tmpIncludes->begin(), tmpIncludes->end());
					}
					else // as current header's source file is not same as basiline's, so baseline's cacheinclude will be taken for current header too.
					{
						newVector->insert(newVector->end(), baseHObj->CachedIncludes()->begin(), baseHObj->CachedIncludes()->end());
					}
					break;
				}
            }
        }
    }    
    hObj->SetCachedIncludes(newVector.release());
	if(baseHObj == NULL) // IncludesForHeader() is called for baseline sdk, so get the source file name in cache
	{
		hObj->SetCachedSourceFile(tempSpurceObj);
	}
    return *(hObj->CachedIncludes());
}
/**
 *
 */
string PlatformData::PrettyPrint() const
{
    string ret("PLATFORM version: ");
    ret += iVersionStr + "\n";
   
    for( ComponentList::const_iterator c = iCList.begin(); c != iCList.end(); ++c )
    {
        ret += c->second->PrettyPrint();
    }
    return ret;
}

/**
 *
 */
const ComponentList& PlatformData::Components() const
{
    return iCList;
}

/**
 *
 */
const string& PlatformData::GetRootDir() const
{
    return iRootDir;
}
