/*
* 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 <time.h>
#include <map>
#include <list>
#include <algorithm>
#include <assert.h>
#include <fstream>
#include <stdlib.h>
#include <boost/thread.hpp>
#include <boost/bind.hpp>

#ifdef __WIN__
#include <io.h>
#include <direct.h>
#include <windows.h>
#else
#include <unistd.h>
#endif
#include "Analyser.h"
#include "CPPParser.h"
#include "CommandLine.h"
#include "CommandFile.h"
#include "BBCFileUtils.h"
#include "HAException.h"
#include "BBCAnalyser.h"
#include "AnalyserParams.h"
#include "MacroAnalyser.h"
#include "Utils.h"
#include "PlatformData.h"

const int KMaxDirLength=1024;

boost::mutex m;
boost::mutex::scoped_lock lock(m,false); //for synchronizing creation & destruction of threads in gHeaderThreads

boost::thread_group gComponentThreads;
boost::thread_group gHeaderThreads;

boost::thread* gpComponentThreads[MAX_THREAD_COUNT];
boost::thread* gpHeaderThreads[MAX_THREAD_COUNT2];

XERCES_CPP_NAMESPACE_USE
typedef pair<string,string> stringpair;
//the total number of files to be processed
static int _total_files = 0;
//the number of files that have been processed
static int _current_files = 0;

// make sure globbing is turned off when GCC is used
int _CRT_glob = 0;

// Fill the headers having API Info in global vector, so that report generator can access it.
vector<pair<string,stringpair> > HeaderInfoList; // vector<pair< headerfile name, pair<API name, API category>>>

// ----------------------------------------------------------------------------
// Analyser::Analyser
// Constructor
// ----------------------------------------------------------------------------
//
Analyser::Analyser(char** args, int argc) : iCPPParser(NULL)
{
    iCmdLine = new CommandLine(args, argc);
    iUseBaselinePlatformData = false;   
    iUseCurrentPlatformData = false;
    iBasePlatformData = 0;
    iProductPlatformData = 0;
}

// ----------------------------------------------------------------------------
// Analyser::Analyser
// Constructor
// ----------------------------------------------------------------------------
//
Analyser::Analyser()
{
    
}

// ----------------------------------------------------------------------------
// Analyser::Analyser
// Destructor
// ----------------------------------------------------------------------------
//
Analyser::~Analyser()
{
    delete iCmdLine;
    iCmdLine = NULL;
    if (iCPPParser != NULL)
    {
        delete iCPPParser;
        iCPPParser = NULL;
    }
    if (iBasePlatformData)
    {
      delete iBasePlatformData;
      iBasePlatformData = 0;
    }
    if ( iProductPlatformData)
    {
      delete iProductPlatformData;
      iProductPlatformData = 0;
    }
}

// ----------------------------------------------------------------------------
// Analyser::validateHeaders
// validates header for include guards
// ----------------------------------------------------------------------------
//
void Analyser::validateHeaders(vector<pair<string, string> >& aFiles, vector<pair<string, string> >& aUnsuccessful)
{
	int count = 0;
	string input;
	string files[2];
	bool exists[2];
	string guard[2];
	vector<string> guards[2];

	vector< pair<string, string> >::iterator fileStart = aFiles.begin();
	vector< pair<string, string> >::iterator fileEnd = aFiles.end();
	//vector used to temporarily hold file pairs with include guards
	vector< pair<string, string> > temp;
	while(fileStart != fileEnd )
	{
		files[0] = fileStart->first;
		files[1] = fileStart->second;
		for(int i=0; i<2; i++)
		{

			//check for include guard in Base header
			exists[i] = guardExists(files[i], guard[i]);
		}
		//if either Base or Current header in the PAIR do not have include guards
		//add the file pair to RemovedFiles list.
		if( !exists[0] || !exists[1] )
			aUnsuccessful.push_back(*fileStart);
		else 
		{
			if ( find(guards[0].begin(),guards[0].end(),guard[0]) == guards[0].end() && find(guards[1].begin(),guards[1].end(),guard[1]) == guards[1].end())
			{
				guards[0].push_back(guard[0]);
				guards[1].push_back(guard[1]);
				temp.push_back(*fileStart);			
			}
			else
			{
				aUnsuccessful.push_back(*fileStart);
			}
		}
	
		++fileStart;
	}
	guards[0].clear();
	guards[1].clear();
	aFiles.clear();
	aFiles = temp;
}

// ----------------------------------------------------------------------------
// Analyser::guardExists
// guard Exists checs to see if the input file has include guards
// ----------------------------------------------------------------------------
//
bool Analyser::guardExists(const string& aFile, string& aGuard)
{
	bool exists = false;
	string guard("");
	string input("");
	string temp("");
	//macro used in the #ifndef line
	pair<string,string> macroOne;
	//macro #defined subsequently
	pair<string,string> macroTwo;
	int linenum = 0;
	//linenum containing the #ifndef statement
	int ifndefline = 0;

	ifstream fileRead(aFile.c_str(), ios::in);
	if( !fileRead.is_open())
		throw HAException("Header file does not exist");;
	while( !fileRead.eof() )
	{
		linenum++;
		temp = getLine(fileRead);
		input = trimWhiteSpace(temp);
		// Check if #ifndef are being used
		// Get the MACRO string if they are present
		if(input.substr(0,7) == "#ifndef") 
		{
			macroOne = MacroAnalyser::FindMacro(input);
			ifndefline = linenum;
		}
		// checks for the usage of #if (!defined ...) in include guard defns
		else if (input.substr(0,3) == "#if")
		{
			string tempstr("!defined");
			//strip all braces from the Macro string
			while(input.find("(") < input.length())
			{
				replaceChar(input,'(',' ');
				replaceChar(input,')',' ');
			}
			//get the actual MACRO string after required temp modifications
			string::size_type index = input.find(tempstr);
			if (index == string::npos)
			  continue;
			index = index + tempstr.length();
			tempstr = input.substr( index );
			input = trimWhiteSpace(tempstr);
			pair<string,string> temppair(input, "");
			macroOne = temppair;
			ifndefline = linenum;
		}
		// Check if #define is used 
		else if (input.substr(0, 7) == "#define")
		{
			macroTwo = MacroAnalyser::FindMacro(input);
			//if macro strings used in both #ifndef and #define are same
			//consider that include guard exists
			//also verify that #define follows #if
			if( macroTwo.first == macroOne.first && macroTwo.second == macroOne.second && ifndefline < linenum )
			{
				exists = true;
				aGuard = macroOne.first;
			}
			break;
		}
		// additional statement will be used for early termination of the loop
		// in cases with no "include" guards
		else if( input.substr(0, 8) == "#include") 
		{
			exists = false;
			break;
		}
	}
	fileRead.close();
	return exists;
}

// ----------------------------------------------------------------------------
// Analyser::readParameters
// readParameters should be called so that first is called baseline command
// and after that current command, otherwise it doesn't work
// ----------------------------------------------------------------------------
//
void Analyser::readParameters(basetype type, list<pair<string, string> >& files, string& forcedheaders)
{    
    string headerset;
    string dir;
    string file;
    string platform;
    string forcedheadersfile;
    string forcedheaders_file;
    string version;
    string versionstr;
    BBCFileUtils* fileUtils = NULL;
    static basetype first = type;

    if (first != EBase)
    {
        cout << "Error: Parameter read has been called in wrong order.";
        exit(3);
    }

    switch(type)
    {
    case EBase:
        dir = BASELINEDIR;
        file = BASELINE;
        platform = BASELINEPLAT;
        forcedheadersfile = BASEFORCEDHEADERSFILE;
        version = BASELINEVERSION;
        versionstr = "BASELINE";
        break;
    case ECurrent:
        dir = CURRENTDIR;
        file = CURRENT;
        platform = CURRENTPLAT;
        forcedheadersfile = CURRENTFORCEDHEADERSFILE;
        version = CURRENTVERSION;
        versionstr = "CURRENT";
        break;
    default:
        cout << "Error: Unknown type (not baseline, nor current).";
        exit(3);
    }
  
    // Query the baseline-related command line parameters
    // since validation has passed, none of these should really
    // cause an exception
    try
    {
        if( iParams.parameterExists(BASEPLATFORMDATA))
        {
            iUseBaselinePlatformData = true;
            string pfdir(BBCFileUtils::getFullPath(iParams.getParameter(BASEPLATFORMDATA)));
            if (!BBCFileUtils::isValidFilename(pfdir))
            {
                throw HAException("Baseline platform data file '" + pfdir + "' is not valid.");
            }
            iParams.storeParameter(BASEPLATFORMDATA, pfdir);
        }
        if( iParams.parameterExists(CURRENTPLATFORMDATA))
        {
            iUseCurrentPlatformData = true;         
            string pfdir(BBCFileUtils::getFullPath(iParams.getParameter(CURRENTPLATFORMDATA)));
            if (!BBCFileUtils::isValidFilename(pfdir))
            {
                throw HAException("Current platform data file '" + pfdir + "' is not valid.");
            }
            iParams.storeParameter(CURRENTPLATFORMDATA, pfdir);
        }
        if (iParams.parameterExists(TEMPDIR))
        {
            string tempdir(BBCFileUtils::getFullPath(iParams.getParameter(TEMPDIR)));
            iParams.storeParameter(TEMPDIR, tempdir);
            if (!BBCFileUtils::isValidDirectory(tempdir))
            {
                throw HAException("Temporary directory '" + tempdir + "' is not valid directory.");
            }
        }
        if (iParams.parameterExists(REPORTFILE))
        {
            string reportfile(BBCFileUtils::getFullPath(iParams.getParameter(REPORTFILE)));
            iParams.storeParameter(REPORTFILE, reportfile);
            if (rightmostDirSeparatorIndex(reportfile) == reportfile.length() - 1 || BBCFileUtils::isValidDirectory(reportfile))
            {
                throw HAException("No filename given for report file.");
            }
            string reportdir = reportfile.substr(0, rightmostDirSeparatorIndex(reportfile));
            
            if (reportdir.size() == ANALYSER_REPORT_DIR_SIZE)
            {
                reportdir += DIR_SEPARATOR;
            }
            if (!BBCFileUtils::isValidDirectory(reportdir))
            {
                throw HAException("Directory for report file is non-existent.");
            }
        }
        if (iParams.parameterExists(HEADERSET))
        {
            iHeaderSetInUse = true;
        }
		if (iParams.parameterExists(USETHREAD))
        {
            iUseThread = true;
        }
        if (iParams.parameterExists(dir))
        {
            // START -- Support for multiple header directories
            // Validate the ; separated header paths and store them
            list<pair<string, string> > dirs = BBCFileUtils::extractFilenames(iParams.getParameter(dir));
            list<pair<string, string> >::iterator dirbegin = dirs.begin();
            string tempval = "";
        
            for(; dirbegin != dirs.end(); dirbegin++)
            {
                if (dirbegin != dirs.begin())
                {
                    tempval += ";";
                }
                string header = BBCFileUtils::getFullPath(dirbegin->first);

               if (header.length() != ANALYSER_HEADER_MAX_LENGTH && header.at(header.length() - 1) == DIR_SEPARATOR)
                {
                    header.resize(header.length() - 1);
                }

                if (!BBCFileUtils::isValidDirectory(header))
                {
                    string::size_type pos = rightmostDirSeparatorIndex(header);
                    string tempvar;
                    if (pos != header.length() - 1)
                    {
                        tempvar = header.substr(pos + 1);
                        header.resize(pos);
                    }

                    if (header.size() == ANALYSER_HEADER_SIZE)
                    {
                        header += DIR_SEPARATOR;
                    }
    
                    if (!BBCFileUtils::isValidDirectory(header) || tempvar.find_first_of("*?") == string::npos)
                    {
                        string errormsg;
                        errormsg = "Non-existent ";
                        if (type == EBase)
                        {
                            errormsg += "base";
                        } else
                        {
                            errormsg += "current";
                        }
                        errormsg += " directory '" + header + DIR_SEPARATOR + tempvar + "'.\n";
                        throw HAException(errormsg);
                    }
                }
                if (header.at(header.length() - 1) == DIR_SEPARATOR)
                {
                    header.resize(header.length() - 1);
                }
                tempval += header;
            }
            iParams.storeParameter(dir, tempval);
            // END -- Support for multiple header directories
        }
        else
        {
            iParams.storeParameter(file, BBCFileUtils::getFullPath(iParams.getParameter(file)));
        }
        
        // Location of baseline's platform headers
        list<pair<string, string> > platformheaders = BBCFileUtils::extractFilenames(iParams.getParameter(platform));
        list<pair<string, string> >::iterator platformbegin = platformheaders.begin();
        string tempval = "";
        for(; platformbegin != platformheaders.end(); platformbegin++)
        {
            if (platformbegin != platformheaders.begin())
            {
                tempval += ";";
            }
            string header = BBCFileUtils::getFullPath(platformbegin->first);

            if (header.length() != ANALYSER_HEADER_MAX_LENGTH && header.at(header.length() - 1) == DIR_SEPARATOR)
            {
                header.resize(header.length() - 1);
            }
            
            tempval += header;
        }
        iParams.storeParameter(platform, tempval);

        // Location of forced headers file (containing full names of headers that 
        // will be included to preprocessing and processing phases, e.g. e32base.h)
        if (iParams.parameterExists(forcedheadersfile))
        {
            // START -- Support for multiple forced headers
            list<pair<string, string> > fheaders = BBCFileUtils::extractFilenames(iParams.getParameter(forcedheadersfile));
            list<pair<string, string> >::iterator fheadersbegin = fheaders.begin();
            string tempval = "";
            
            //for each forced header, get the full path before storing it
            for(; fheadersbegin != fheaders.end(); fheadersbegin++)
            {
                if (fheadersbegin != fheaders.begin())
                {
                    tempval += ";";
                }
                tempval += BBCFileUtils::getFullPath(fheadersbegin->first);
            }
            iParams.storeParameter(forcedheadersfile, tempval);
            forcedheaders = iParams.getParameter(forcedheadersfile);
            // END -- Support for multiple forced headers
        }
        
        if (!iParams.parameterExists(version))
        {
            iParams.storeParameter(version, versionstr);
        }
    } catch (HAException& e)
    {
        cout << "Error: "<<e.errorMessage()<<"\n";
        exit(2);
    }

    // Instantiate file utilities that generate the file lists based on 
    // commandline parameters. In this try/catch block, we're
    // handling the baseline files
    try
    {
        if (iParams.parameterExists(dir))
        {
            // baselinedir/currentdir commandline parameters given
            fileUtils = new BBCFileUtils(iParams.getParameter(dir));
            fileUtils->setTemp(iParams.getParameter(TEMPDIR));
            string wildcard;
            list<stringpair > sets;
            list<stringpair > discarddirs;
            list<stringpair > foundfiles;
            list<stringpair > completefilenames; // Filenames that are complete, i.e no wildcards used.
            vector<string> wildcardsinset;
            
            if (type == EBase)
            {                
                // We are reading the parameters of the baseline platform               
                
                if(iHeaderSetInUse)
                {
                    // the files to be analysed are defined using 'set' parameter.
                    sets = fileUtils->extractFilenames(iParams.getParameter(HEADERSET));   
                }
                else
                {
                    // 'set' parameter is absent. Use default file types in the files to be analysed.
                    sets = fileUtils->extractFilenames(WILDCARD_DEFAULT);
                }
                    
                sets = canonicalizeFilename(sets);
                                
                for(list<stringpair >::iterator s = sets.begin(); s != sets.end(); ++s )
                {
                    if( s->first.find_first_of("*?") != string::npos )
                    {
                        // Wildcard is used in filename.
                        std::string wc(s->first);
                        wildcardsinset.push_back(wc);
                        list<stringpair > tmpfiles(fileUtils->getFilesInDir(wc, ""));
                        files.insert(files.end(), tmpfiles.begin(), tmpfiles.end());
                    }                
                    else
                    {
                        completefilenames.push_back(*s);
                    }
                }
                
                files.sort(LessStringPair);// Sort files 
                files.unique(); // Remove duplicates

                // Remove trailing directory separator from the filenames, that were found using the wildcard,
                // to be able to build <code>foundfiles</code> list for later use.
                list<stringpair> foundwithwildcard(files);
                std::for_each(foundwithwildcard.begin(), foundwithwildcard.end(),RemoveTrailingDirSeparator<stringpair>());

                // Find files given with complete filename
                list<stringpair> tempcompletefiles(completefilenames);
                list<stringpair > tmplist(fileUtils->getFilesInDir(tempcompletefiles, "",foundfiles));

                // Add files found with wildcard to <code>foundfiles</code>
                foundfiles.sort(LessStringPair);                
                foundfiles.merge(foundwithwildcard, LessStringPair);
                foundfiles.unique(); // Remove duplicates

                // Merge all found files:
                tmplist.sort( LessStringPair );                
                files.merge(tmplist, LessStringPair);
                files.unique(); // Remove duplicates                
                if (iParams.parameterExists(DISCARDDIRS))
                {
                    discarddirs = BBCFileUtils::extractFilenames(iParams.getParameter(DISCARDDIRS));
                }
            } else if (type == ECurrent)
            {
                // We are reading the parameters of the current platform 
                // and the files to be analysed are defined using 'set' parameter.
                wildcard = WILDCARD_ALLFILES;
                files = fileUtils->getFilesInDir(wildcard, "");
                if (iParams.parameterExists(DISCARDDIRS))
                {
                    discarddirs = BBCFileUtils::extractFilenames(iParams.getParameter(DISCARDDIRS));
                }
            } else
            {
                // No 'set' parameter used
                wildcard = iParams.getParameter(BASELINE);
                files = fileUtils->getFilesInDir(wildcard, "");
                if (iParams.parameterExists(DISCARDDIRS))
                {
                    discarddirs = BBCFileUtils::extractFilenames(iParams.getParameter(DISCARDDIRS));
                }
            }
            if (iParams.parameterExists(RECURSIVE))
            {
                list<pair<string, string> > dirs = fileUtils->getDirsInDir("",discarddirs);
                while(!dirs.empty())
                {
                    string dir = dirs.front().first;
                    dirs.pop_front();
                    list<pair<string, string> > morefiles;
                    if (type == EBase)
                    {
                        // Read files which were given as complete names in the -set parameter:
                        morefiles = fileUtils->getFilesInDir(completefilenames, dir,foundfiles);

                        // Read files which were given as wildcards in the -set parameter:
                        for( vector<string>::iterator wc = wildcardsinset.begin(); wc != wildcardsinset.end(); ++wc)
                        {
                            list<pair<string, string> > tmpfiles = fileUtils->getFilesInDir(*wc, dir);
                            morefiles.insert(morefiles.end(), tmpfiles.begin(), tmpfiles.end());
                        }
                    } 
                    else
                    {
                        morefiles = fileUtils->getFilesInDir(wildcard, dir);
                    }
                    morefiles.sort(LessStringPair);
                    morefiles.unique();
                    list<pair<string, string> >::const_iterator file = morefiles.begin();
                    list<pair<string, string> >::const_iterator fileend = morefiles.end();
                    for(; file != fileend; file++)
                    {
                        files.push_back(*file);
                    }
                    list<pair<string, string> > moredirs = fileUtils->getDirsInDir(dir,discarddirs);
                    while(!moredirs.empty())
                    {
                        pair<string, string> direntry = moredirs.front();
                        moredirs.pop_front();
                        dirs.push_back(direntry);
                    }
                }
            }
            if (type == EBase)
            {
                list<pair<string, string> > notfound;
                diffs(files, sets, notfound);
                if (!notfound.empty())
                {
                    string errormessage = "Following files could not be found in baseline:\n";
                    list<pair<string, string> >::iterator file = notfound.begin();
                    list<pair<string, string> >::iterator fileend = notfound.end();
                    for(; file != fileend; file++)
                    {
                        errormessage += file->first;
                        errormessage += "\n";
                    }
					//this case has now been redefined as a input error that can be handled
					//the file is removed from the list to be analysed, and execution continues
                    //throw HAException(errormessage);
                }
            }
        }
        else
        {
            // baseline/current commandline parameters given
            string file_val = iParams.getParameter(file);
            string f = getFilenameWithoutDir(file_val);
            iParams.storeParameter(file, f);
            file_val.resize(file_val.length() - f.length() - 1);
            iParams.storeParameter(dir, file_val);
            fileUtils = new BBCFileUtils(iParams.getParameter(dir));
            fileUtils->setTemp(iParams.getParameter(TEMPDIR));
            pair<string, string> tempvar(f, toLowerCaseWin(f));
            files.push_back(tempvar);
        }
    } catch (HAException& e)
    {
        // something went wrong. Make a clean exit
        if (fileUtils != NULL)
        {
            delete fileUtils;
            fileUtils = NULL;
        }
        cout << "Error: " << e.errorMessage() << "\n";
        exit(2);
    }
    
    delete fileUtils;
    fileUtils = NULL;

}

// ----------------------------------------------------------------------------
// Analyser::processParameters
// processParameters
// ----------------------------------------------------------------------------
//
int Analyser::processParameters()
{
    string err = "";

    // Validate command-line parameters.
    // If they are not sound and complete, break off with an error message.
    try
    {
        err = iCmdLine->validateParameters();
    } catch (HAException& e)
    {
        cout << "ERROR: Bad parameters, quitting. Type ha -? for help.\n";
        cout << e.errorMessage();
        cout << "\n";
        return (2);
    }

    if (err.size() > 0)
    {
        cout << "ERROR: Parameter validation fail. Type ha -? for help.\n";
        cout << err << "\n";
        return (2);
    }
    
    map<string, string> params = iCmdLine->getParameters();
    map<string, string>::iterator begin = params.begin();
    map<string, string>::iterator end = params.end();
    while (begin != end)
    {
        iParams.storeParameter((*begin).first,(*begin).second, true);
        ++begin;
    }

    // readParameters should be called so that first is called baseline command
    // and after that current command, otherwise it doesn't work

    // Read base dependent parameters
    readParameters(EBase, iFiles, iForcedBaselineHeaders);
    // ..and current ones
    readParameters(ECurrent, iFiles2, iForcedCurrentHeaders);

#if defined(_DEBUG) || defined(DEBUG)
    if(iParams.parameterExists(COMMANDLINETEST))
    {
        map<string, string> params = iParams.getGivenParameters();
        map<string, string>::iterator begin = params.begin();
        map<string, string>::iterator end = params.end();
        while (begin != end)
        {
            cout << "Param: '" << (*begin).first << "' Value: '" << (*begin).second << "'\n";
            begin++;
        }
        exit(100);
    }
#endif

    return 0;
}

// ----------------------------------------------------------------------------
// Analyser::analyseTrees
// processParameters
// ----------------------------------------------------------------------------
//
int Analyser::analyseTrees(DOMNode* baseline, DOMNode* current, const list< pair<string,string> >& files, ReportGenerator& report)
{
    int ret = 0;
    //print progress information for files which have compiled
    list< pair<string,string> >::const_iterator begin = files.begin();
    list< pair<string,string> >::const_iterator end = files.end();
    
    while (begin != end)
    {
        _current_files++;
		cout << "\nAnalysing files (" << _current_files << "/" << _total_files << "): " << (*begin).first <<" => "<< (*begin).second << endl;
        begin++;
    }

    BBCAnalyser analyser(report);
    ret =  analyser.analyseTrees(baseline, current, files, iMacroFiles);

    return ret;
}

// ----------------------------------------------------------------------------
// Analyser::handleBundlesizeParam
// Get bundlesize value
// ----------------------------------------------------------------------------
//
int Analyser::handleBundlesizeParam()
{
    int bundlesize=1; 

    if (iParams.parameterExists(BUNDLESIZE))
    {
        string tempstr = iParams.getParameter(BUNDLESIZE);
        if (tempstr.length() > 0)
        {
            bundlesize = atoi(tempstr.c_str());
            if (bundlesize < 1)
            {
                bundlesize = 1;
            } 
            else if (bundlesize > MAX_BUNDLESIZE)
            {
                bundlesize = MAX_BUNDLESIZE;                
            }
        }
    }

    if (bundlesize >= BUNDLESIZE_WARNING)
    {
    cout << "Note: Processing in large bundles, this may have a negative "
         << "performance impact and/or produce unwanted artifacts.\n";
    }
    return bundlesize;
}

// ----------------------------------------------------------------------------
// Analyser::getReplaceParam
// Get Replace parameter value
// ----------------------------------------------------------------------------
//
string Analyser::getReplaceParam()
{
    string replace;
    // File renames
    if (iParams.parameterExists(FILEREPLACE))
    {
        replace = iParams.getParameter(FILEREPLACE);
    } else
    {
        replace = "";
    }

    return replace;
}



PlatformHeaders::iterator FindHeaderPair(const string& ID, PlatformHeaders& pfHeaders)
{
    for( PlatformHeaders::iterator i = pfHeaders.begin(); i != pfHeaders.end(); ++i )
    {
        if( i->first->ID() == ID )
        {
            return i;
        }
    }
    return pfHeaders.end();
}
// ----------------------------------------------------------------------------
// Analyzes one component at a time.
// 
// 
// ----------------------------------------------------------------------------
//
void Analyser::AnalyzePlatforms(PlatformHeaders& pfHeaders, PlatformHeaders& unsuccessfulHdrs, ReportGenerator& report, int& issues, bool createThread)
{
	string epocRoot("epoc32");
	epocRoot += DIR_SEPARATOR + string("include"); 
	// START -- Support for multiple header directories       
	list<pair<string, bool> > baseEpocRoot = BBCFileUtils::MergeDirs(iParams.getParameter(BASELINEDIR), epocRoot);
	list<pair<string, bool> > currEpocRoot = BBCFileUtils::MergeDirs(iParams.getParameter(CURRENTDIR), epocRoot);
	// END -- Support for multiple header directories
	for( PlatformHeaders::iterator pfHdr = pfHeaders.begin(); pfHdr != pfHeaders.end(); ++pfHdr )
	{        
		if( pfHdr->first->Status() == Header::HDR_STATUS_TO_BE_ANALYZED /*|| pfHdr->first->Status() == Header::HDR_STATUS_INVALID*/)
		{
			stringvector baseIncPaths;  // This contains include paths needed to compile baseline headers
			stringvector currIncPaths;  // This contains include paths needed to compile product headers

			baseIncPaths.clear();
			currIncPaths.clear();
			
			iBaseFilenames.clear();
			iCurrFilenames.clear();
			iBaseIncludes.clear();
			iCurrIncludes.clear();
			iInvalidFiles.clear();

			// All headers in the (baseline platform) component:
			FileList& baseCmpHeaders = pfHdr->first->GetComponent()->Headers();             
			iBaseFilenames.reserve(baseCmpHeaders.size());
			iCurrFilenames.reserve(baseCmpHeaders.size());

			// Make sure that the epoc32/include directory is always in include paths:
			// START -- Support for multiple header directories
			list<pair<string, bool> >::iterator iter1 = baseEpocRoot.begin();
			for(; iter1 != baseEpocRoot.end(); iter1++)
			{
				if( iter1->second )
				{
					baseIncPaths.push_back(iter1->first);
				}  
			}
			list<pair<string, bool> >::iterator iter2 = currEpocRoot.begin();
			for(; iter2 != currEpocRoot.end(); iter2++)
			{         
				if( iter2->second )
				{
					currIncPaths.push_back(iter2->first);
				}
			}
			// END -- Support for multiple header directories
			string forcedHeader;
			string baseForcedHeader;
			string curForcedHeader;
			char* base = new char[KMaxDirLength+1];
			getcwd(base, KMaxDirLength);

			vector< stringpair > tmpfiles;	
			vector< stringpair > invalid;
			// Loop all the headers that are in the same component:
			for( FileList::iterator bH = baseCmpHeaders.begin(); bH != baseCmpHeaders.end(); ++bH )
			{
				Header* baseHdr = dynamic_cast<Header*>(*bH);
							
				PlatformHeaders::iterator pairIter = FindHeaderPair(baseHdr->ID(), pfHeaders);
				if(pairIter != pfHeaders.end() && pairIter->second != 0)
				{
					// If analysing in bundle, get the headers to be anaysed to validate for include guard before addition to bundle.
					if( (pfHeaders.size() > 1) && baseHdr && (baseHdr->Status() == Header::HDR_STATUS_TO_BE_ANALYZED) )
					{
						stringpair tmp(baseHdr->ID(), pairIter->second->ID());
						tmpfiles.push_back(tmp);
					}
				}
			}
			
			if(tmpfiles.size())
			{
				// If analysing in bundle, validate for include guard before addition to bundle.
				validateHeaders(tmpfiles, invalid);
				// Exclude "iInvalidFiles" from bundle analysis. Analyse them only singly. 
				if( invalid.size() )
				{
					for( int i=0 ; i < (int)invalid.size() ; i++ )
					{
					
						PlatformHeaders::iterator pairIter = FindHeaderPair(invalid[i].first, pfHeaders);
						//No need to check if the invalid file exists in pfHeaders, as it already done above. 
						HeaderPair temp(pairIter->first, pairIter->second);
						if(find(iInvalidFiles.begin(), iInvalidFiles.end(), temp) == iInvalidFiles.end())
							iInvalidFiles.push_back(temp);
						pairIter->first->SetStatus(Header::HDR_STATUS_INVALID);	
					}
				}
			}

			for( FileList::iterator bH = baseCmpHeaders.begin(); bH != baseCmpHeaders.end(); ++bH )
			{
				Header* baseHdr = dynamic_cast<Header*>(*bH);
							
				PlatformHeaders::iterator pairIter = FindHeaderPair(baseHdr->ID(), pfHeaders);
				if(pairIter != pfHeaders.end() && pairIter->second != 0)
				{
					
					// If the status is "to be analyzed" , get this header to the bundle too
					if( baseHdr && 
						(baseHdr->Status() == Header::HDR_STATUS_TO_BE_ANALYZED ))
					{                       
						// Find all additional includes that are needed in compilation of this header:   
						const vector<string>& bIncs = iBasePlatformData->IncludesForHeader(baseHdr);                    
						forcedHeader.clear();
						forcedHeader = baseHdr->CachedForcedInclude();
						// If the component contains all SHAi headers, then no need to include the deafult forced header.
						if (forcedHeader == FORCED_SHAI_HDR)
							baseForcedHeader = forcedHeader;
						// Find all include paths that are needed in compilation of this header:
						const vector<string>& bPaths = iBasePlatformData->IncludePathsForHeader(baseHdr);                    

						// Add include paths for baseline platform headers:   
						// START -- Support for multiple header directories                                     
						for( vector<string>::const_iterator i = bPaths.begin(); i != bPaths.end(); ++i )
						{
							list<pair<string, bool> > fullIncPath = BBCFileUtils::MergeDirs(iParams.getParameter(BASELINEDIR), *i);
							list<pair<string, bool> >::iterator fulliterbegin = fullIncPath.begin();
							for(; fulliterbegin != fullIncPath.end(); fulliterbegin++)
							{
								if( find(baseIncPaths.begin(), baseIncPaths.end(), fulliterbegin->first) == baseIncPaths.end() )
								{
									baseIncPaths.push_back(fulliterbegin->first);
								}
							}
						}                    

						// Add additional include directives to header list:
						for( vector<string>::const_iterator i = bIncs.begin(); i != bIncs.end(); ++i )
						{                          
							// Make sure the header exists, because we don't want to generate new compilation errors...
							bool exists = false;
							// Test that header exists by merging the header name with include paths:
							for( stringvector::iterator ip = baseIncPaths.begin(); ip != baseIncPaths.end(); ++ip )
							{
								list<pair<string, bool> > fullIncPath = BBCFileUtils::MergeDirs( *ip, *i );
								list<pair<string, bool> >::iterator fulliterbegin = fullIncPath.begin();
								for(; fulliterbegin != fullIncPath.end(); fulliterbegin++)
								{                           
									if( find(iBaseIncludes.begin(), iBaseIncludes.end(), fulliterbegin->first) == iBaseIncludes.end() )
									{
										if( BBCFileUtils::FileExists(fulliterbegin->first) )
										{                                    
											iBaseIncludes.push_back(fulliterbegin->first);
											exists = true;
											break; 
										}                                
									}
								}
							}
							if( exists == false )
							{
								// Try to find the included header from the same directory than the header itself is:
								list<pair<string, bool> > fullIncPath = 
									BBCFileUtils::MergeDirs(iParams.getParameter(BASELINEDIR), baseHdr->Path() + DIR_SEPARATOR + *i);                            

								list<pair<string, bool> >::iterator fulliterbegin = fullIncPath.begin();
								for(; fulliterbegin != fullIncPath.end(); fulliterbegin++)
								{
									if( BBCFileUtils::FileExists(fulliterbegin->first) )
									{                         
										iBaseIncludes.push_back(fulliterbegin->first);
									} 
								}                           
							}
						}
						// END -- Support for multiple header directories

						// Add this header to the list of headers that are needed for compilation:                    
						if( find(iBaseIncludes.begin(), iBaseIncludes.end(), baseHdr->ID()) == iBaseIncludes.end())
						{
							iBaseIncludes.push_back(baseHdr->ID());
						}

						// Add headers to the list of headers that are to be analyzed:										
						iBaseFilenames.push_back(baseHdr->ID());
						iCurrFilenames.push_back(pairIter->second->ID());
						baseHdr->SetStatus(Header::HDR_STATUS_READY);
       
						forcedHeader = DIR_SEPARATOR + forcedHeader;
						forcedHeader = base + forcedHeader;
						if( BBCFileUtils::isValidFilename(forcedHeader) )
							if( find(iBaseIncludes.begin(), iBaseIncludes.end(), forcedHeader) == iBaseIncludes.end())
								iBaseIncludes.insert(iBaseIncludes.begin(),forcedHeader);
              
              
						// Then we need to find corresponding headers from the product (current) platform:                                        
					
						Header* currHeader = pairIter->second; //Current header

						// Find additional includes and include paths for the current platform's header:
						const vector<string>& cIncs = iProductPlatformData->IncludesForHeader(currHeader, baseHdr);                        
						forcedHeader.clear();
						forcedHeader =currHeader->CachedForcedInclude(); 
						// If the component contains all SHAi headers, then no need to include the deafult forced header.
						if (forcedHeader == FORCED_SHAI_HDR)
							curForcedHeader = forcedHeader;

						const vector<string>& cPaths =iProductPlatformData->IncludePathsForHeader(currHeader);                        

						// Add include paths to the list, if it does not exist there yet:
						for( vector<string>::const_iterator i = cPaths.begin(); i != cPaths.end(); ++i )
						{
							// SART -- Support for multiple header directories
							list<pair<string, bool> > fullIncPath = BBCFileUtils::MergeDirs(iParams.getParameter(CURRENTDIR), *i);
							list<pair<string, bool> >::iterator fulliterbegin = fullIncPath.begin();
							for(; fulliterbegin != fullIncPath.end(); fulliterbegin++)
							{
								if( find(currIncPaths.begin(), currIncPaths.end(), fulliterbegin->first) == currIncPaths.end() )
								{
									currIncPaths.push_back(fulliterbegin->first);
								}
							}
							// END -- Support for multiple header directories
						}

						// Add additional include directives to header list:
						for( vector<string>::const_iterator i = cIncs.begin(); i != cIncs.end(); ++i )
						{
							bool exists = false;
							// Make sure the header exists, because we don't want to generate new compilation errors...
							for( stringvector::iterator ip = currIncPaths.begin(); ip != currIncPaths.end(); ++ip )
							{
								// START -- Support for multiple header directories
								list<pair<string, bool> > fullIncPath = BBCFileUtils::MergeDirs( *ip, *i );
								list<pair<string, bool> >::iterator fulliterbegin = fullIncPath.begin();
								for(; fulliterbegin != fullIncPath.end(); fulliterbegin++)
								{
									if( find(iCurrIncludes.begin(), iCurrIncludes.end(), fulliterbegin->first) == iCurrIncludes.end() )
									{                                        
										if( BBCFileUtils::FileExists(fulliterbegin->first) )
										{
											iCurrIncludes.push_back(fulliterbegin->first);
											exists = true;
											break;
										}                                    
									}
								}
								// END -- Support for multiple header directories
							}
							if( exists == false )
							{
								// Try to find the included header from the same directory than the header itself is:
								// START -- Support for multiple header directories
								list<pair<string, bool> > fullIncPath = 
									BBCFileUtils::MergeDirs(iParams.getParameter(CURRENTDIR), currHeader->Path() + DIR_SEPARATOR + *i);                            
								list<pair<string, bool> >::iterator fulliterbegin = fullIncPath.begin();
								for(; fulliterbegin != fullIncPath.end(); fulliterbegin++)
								{
									if( BBCFileUtils::FileExists(fulliterbegin->first) )
									{                                
										iCurrIncludes.push_back(fulliterbegin->first);
									}
								}
								// END -- Support for multiple header directories
							}
						}
							// Add this header to the list:                        
						if( find(iCurrIncludes.begin(), iCurrIncludes.end(), currHeader->ID()) == iCurrIncludes.end())
						{
							iCurrIncludes.push_back(currHeader->ID());                            
						}
					
						forcedHeader = DIR_SEPARATOR + forcedHeader;
						forcedHeader = base + forcedHeader;
						if( BBCFileUtils::isValidFilename(forcedHeader) )
							if( find(iCurrIncludes.begin(), iCurrIncludes.end(), forcedHeader) == iCurrIncludes.end())
								iCurrIncludes.insert(iCurrIncludes.begin(),forcedHeader);
									
					}
				}
			}
			// Build include paths for parser objects:
			string bIP;
			for( stringvector::iterator i = baseIncPaths.begin(); i != baseIncPaths.end(); ++i )
			{
				if( i != baseIncPaths.begin() )
					bIP += ";";

				bIP += *i;
			}

			string cIP;
			for( stringvector::iterator i = currIncPaths.begin(); i != currIncPaths.end(); ++i )
			{
				if( i != currIncPaths.begin() )
					cIP += ";";

				cIP += *i;
			}

			// Construct parsers:
			auto_ptr<CPPParser> parser(new CPPParser(bIP));
			auto_ptr<CPPParser> parser2(new CPPParser(cIP));

			// Set temp directories for parsers
			parser->setTemp(iParams.getParameter(TEMPDIR));
			parser2->setTemp(iParams.getParameter(TEMPDIR));

			// If this bundle is for SHAi headers, then ignore iForcedHeaders 
			//to solve Kernel Macro related compilation issues.
			if(baseForcedHeader.size() == 0 )
			{
				parser->setForcedHeaders(iForcedBaselineHeaders);			
			}
			if(curForcedHeader.size() == 0 )
			{
				parser2->setForcedHeaders(iForcedCurrentHeaders);			
			}
			
			if (createThread)
			{		
				//if the number of threads in this group has reached pre-defined max count, destroy all the threads in this group before creating one.
				//boost::thread_group object does not destroy a thread when it goes to completion. if the threads are not destroyed lot of memory will be eaten up unneccessarily
				if(gHeaderThreads.size() >= MAX_THREAD_COUNT)
				{
				
					gHeaderThreads.join_all();
					int size = gHeaderThreads.size();
					for(int i=0;i<size;i++)
					{
						gHeaderThreads.remove_thread(gpComponentThreads[i]);
						gpComponentThreads[i]->~thread();	
					}
				}
						
				//create a copy of the Analyser object for the new thread
				Analyser* obj = new Analyser();
				*obj = *this;
				int size = gHeaderThreads.size();
				gpComponentThreads[size]=gHeaderThreads.create_thread(boost::bind(&Analyser::Wrapper,obj, boost::ref(report), boost::ref(issues), *(parser.get()), *(parser2.get()), boost::ref(pfHeaders), boost::ref(unsuccessfulHdrs)));				
			}
			else //do not create different thread for the second time when AnalyzePlatforms is called recurssively
			{
				Wrapper(report, issues, *(parser.get()), *(parser2.get()), pfHeaders, unsuccessfulHdrs);	
			}		
		}
	}
	
}

// ----------------------------------------------------------------------------
// Analyser::InitializePlatforms
// 
// 
// ----------------------------------------------------------------------------
//
void Analyser::InitializePlatforms(PlatformHeaders& pfHeaders, vector<pair<string, string> >& headers, 
								   vector<pair<string, string> >& excludeheaders, vector<pair<string, string> >& resourcevector)
{
	if( iBasePlatformData )
		delete iBasePlatformData;
	if( iProductPlatformData )
		delete iProductPlatformData;

	iBasePlatformData = new PlatformData(iParams.getParameter(BASELINEVERSION),
		iParams.getParameter(BASELINEDIR));
	iProductPlatformData = new PlatformData(iParams.getParameter(CURRENTVERSION),
		iParams.getParameter(CURRENTDIR));

	if( iUseBaselinePlatformData )
		iBasePlatformData->Initialize(iParams.getParameter(BASEPLATFORMDATA));
	if( iUseCurrentPlatformData )
		iProductPlatformData->Initialize(iParams.getParameter(CURRENTPLATFORMDATA));

	vector<pair<string, string> > updatedHdrs;
	updatedHdrs.reserve(headers.size());    

	// Mark the platform header objects with status 'HDR_STATUS_TO_BE_ANALYZED':
	vector<pair<string, string> >::const_iterator hdr = headers.begin();

	for( ;hdr != headers.end(); ++hdr )
	{
		pair<string,stringpair> headerInfo;
		bool is_Resource = false;
		int loc = -1;
		pair<string,string> resource;
		Header* baseHdrObj = 0;
		Header* currHdrObj = 0;        
		string hdrTest(hdr->first);
		toLower(hdrTest);

		// Check whether the header is a resource file. If, so add it to resource vector instead of pfheaders.
		if( (loc = int(hdrTest.find_last_of("."))) != string::npos &&
			hdrTest.substr(loc,string::npos) == RH_EXTENSION )
		{
			is_Resource = true;
			resource.first = hdrTest;
		}
		CFileMap::const_iterator bI = iBasePlatformData->HeadersById().find(hdrTest);
		if( bI != iBasePlatformData->HeadersById().end() )
		{
			baseHdrObj = dynamic_cast<Header*>((*bI).second);
		}

		hdrTest = hdr->second;
		toLower(hdrTest);
		if(is_Resource == true)
		{
			resource.second = hdrTest;
			resourcevector.push_back(resource);
		}

		CFileMap::const_iterator cI = iProductPlatformData->HeadersById().find(hdrTest);
		if( cI != iProductPlatformData->HeadersById().end() )
		{
			currHdrObj = dynamic_cast<Header*>((*cI).second);
		}

		if(baseHdrObj && baseHdrObj->Status()== Header::HDR_STATUS_IGNORE )
		{
			excludeheaders.push_back(*hdr);
		}
		else if( baseHdrObj && currHdrObj )
		{
			if( is_Resource == false)
			{
				pfHeaders.push_back(HeaderPair(baseHdrObj, currHdrObj));
				baseHdrObj->SetStatus(Header::HDR_STATUS_TO_BE_ANALYZED);
				currHdrObj->SetStatus(Header::HDR_STATUS_TO_BE_ANALYZED);
			}

			// get API info from current header
			if(currHdrObj->APIinfo().first.size() > 0)
			{
				headerInfo.first = currHdrObj->ID();
				headerInfo.second.first = currHdrObj->APIinfo().first; // API NAME
				headerInfo.second.second = currHdrObj->APIinfo().second; // API REL. CATEGORY
			}

		}
		else
		{
			// get API info from base header
			if(baseHdrObj && baseHdrObj->APIinfo().first.size() > 0)
			{
				headerInfo.first = baseHdrObj->ID();
				headerInfo.second.first = baseHdrObj->APIinfo().first; // API NAME
				headerInfo.second.second = baseHdrObj->APIinfo().second; // API REL. CATEGORY

			}
			// get API info from current header
			else if(currHdrObj && currHdrObj->APIinfo().first.size() > 0)
			{
				headerInfo.first = currHdrObj->ID();
				headerInfo.second.first = currHdrObj->APIinfo().first; // API NAME
				headerInfo.second.second = currHdrObj->APIinfo().second; // API REL. CATEGORY
			}
			// No info found from platform data, so use common include paths and 
			// other common compile-time parameters for this header:
			if( is_Resource == false)
			updatedHdrs.push_back(*hdr);
		}
		// Fill the headers having API Info in global vector, so that report generator can access it.
		if(headerInfo.first.size() > 0)
		{
			HeaderInfoList.push_back(headerInfo);
		}
	}
	headers = updatedHdrs;
}

// ----------------------------------------------------------------------------
// Analyser::analyse
// Do the actual analyse of headers
// Create analysis report
// ----------------------------------------------------------------------------
//
int Analyser::analyse()
{
	// Local variable instantiation
	int ret = 0;
	iHeaderSetInUse = false;
	iUseThread = false;
	string epocroot;
	int bundlesize = 1;
	unsigned int amount, amount2;
	iOnlySystemIncludeRequired = false;
	unsigned int excludedHeaderSize;

	if (processParameters() == 2) return 2;

	// Get the bundle size (as string) and convert it to an integer
	bundlesize = handleBundlesizeParam();

	// Get replace parameter for file renaming
	string replace = getReplaceParam();

	// Update the amount of found files
	amount = (unsigned int)iFiles.size();
	// Update the amount of found files
	amount2 = (unsigned int)iFiles2.size();

	// Vector that holds the merge results and if it can't find baseline
	// file from current file it will put empty string as current file
	vector<pair<string,string> > mergeVector;
	mergeVector.reserve(amount);

	// List holds files which were found in current but not in baseline.
	// Full path
	list<string> addedFiles;

	// List holds files which were in baseline file list but
	// weren't in current file list, ie they were removed.
	// Contains full path with filename
	list<string> removedFiles;
	try
	{
		// Merges baseline and current files into one vector
		MergeFiles(iFiles, iFiles2, replace, mergeVector);

		// Finds removed files
		fileDiffs(mergeVector, removedFiles);
	}
	catch (HAException e)
	{
		cout << "Error in processing file lists:\n" << e.errorMessage() << "\n";
		exit(4);
	}

	// Mergemap now contains pairs of following type:
	// baseline complex filename (w/ absolute path) -> current version complex filename (w/ absolute path)
	_total_files = (unsigned int)mergeVector.size();

	cout << "\nTotal baseline files: " << amount << "\nTotal current files: " << amount2 << "\nFile pairs found: "
		<< _total_files << "\n";

	cout << "\nComparing " << _total_files << " matching files between\n " << iParams.getParameter(BASELINEDIR)
		<< " (Version " << iParams.getParameter(BASELINEVERSION) << ")\nand\n " << iParams.getParameter(CURRENTDIR)
		<< " (Version " << iParams.getParameter(CURRENTVERSION) << ")\n\n\n\n";

	
	ReportGenerator report(iParams.getParameter(REPORTFILE));
	report.setCmdLineParms(iParams.getGivenParameters());
	report.setVersions(iParams.getParameter(BASELINEVERSION),iParams.getParameter(CURRENTVERSION));
	report.setXSL("BBCResults.xsl",false);
	

	report.startReport();
	// start the timer
	time_t starttime;
	time_t endtime;
	starttime = time(NULL);
	
	PlatformHeaders pfHeaders;
	pfHeaders.reserve(mergeVector.size());

	// Vector that holds the the headers those should be excluded from analysis.
	// These header files are mentioned in platform headers
	vector<pair<string,string> > excludeHeaders;
	excludeHeaders.reserve(mergeVector.size());


	// Headers that are found from platform data are inserted in pfHeaders.
	// Others are left to mergeVector.
	vector<pair<string, string> > resourceVector;
	resourceVector.reserve(mergeVector.size());

	if(mergeVector.size() > 0 )
		InitializePlatforms(pfHeaders, mergeVector,excludeHeaders,resourceVector);
	excludedHeaderSize = int(excludeHeaders.size());	

	endtime = time(NULL);
	time_t pfInitTime = endtime - starttime;
	time_t originalStartTime = starttime;
	starttime = time(NULL);

	//Now analyse Resource Header RH files using text parser
	if(resourceVector.size()>0)
		ParseAndCompareResourceFiles(resourceVector, report);

	// Process each removed filename from removedMap
	list<string>::iterator removedbegin = removedFiles.begin();
	list<string>::iterator removedend = removedFiles.end();
	for(; removedbegin != removedend; removedbegin++)
	{
		string filename = *removedbegin;
		report.addIssue(filename, "", EIssueIdentityFile, EIssueTypeRemoval, ESeverityBBCBreak, ESeveritySCBreak, "", 0,"", "","");
	}

	int issues = 0;
	PlatformHeaders unsuccessfulHeaders;
	vector<pair<string, string> > unsuccessfulHeaderNames;
	vector<pair<string, string> > platformUnsuccessfulHeaderNames;
	int compErrors = 0;

	//validate if the headers have include guards,
	//move ones without guards for individual compilation
	validateHeaders(mergeVector, unsuccessfulHeaderNames);

	boost::thread_group mainThreads;
	int mergeVectorCompErrs = 0;
	int unsuccessfulCompErrs = 0;
	int platformUnsuccessfulCompErrs = 0;

	// Analyse headers that were not found from platform data:	
	if( mergeVector.size() > 0 )
	{
		//create copy of Analyser object for the new thread
			Analyser* obj1=new Analyser();
			*obj1=*this;
			//analyse mergeVector in different thread
			mainThreads.create_thread(boost::bind(&Analyser::AnalyseHeaders,obj1,boost::ref(mergeVector),bundlesize,boost::ref(report),boost::ref(issues),boost::ref(mergeVectorCompErrs)));
	}
	
	// Compile unsuccessful headers one by one, because it is unlikely that they
	// will be compiled successfully here either:
	if( unsuccessfulHeaderNames.size() > 0 )
	{
		//create copy of Analyser object for the new thread
			Analyser* obj2 = new Analyser();
			*obj2=*this;
			//analyse unsuccessfulHeaderNames in different thread
			mainThreads.create_thread(boost::bind(&Analyser::AnalyseHeaders,obj2,boost::ref(unsuccessfulHeaderNames),1,boost::ref(report),boost::ref(issues),boost::ref(unsuccessfulCompErrs)));
	}
	
	if(pfHeaders.size() > 0)
	{
		AnalyzePlatforms(pfHeaders, unsuccessfulHeaders, report, issues, iUseThread);    
		if (iUseThread)
		{
			gHeaderThreads.join_all(); // wait for all threads in gHeaderThreads to complete
			gComponentThreads.join_all(); // wait for all threads in gComponentThreads to complete

			//destroy the thredas in gHeaderThreads
			int size = gHeaderThreads.size();
			for (int i=0;i<size;i++)
			{
				gHeaderThreads.remove_thread(gpComponentThreads[i]);
				gpComponentThreads[i]->~thread();
			}

			//destroy the thredas in gComponentThreads
			size=gComponentThreads.size();
			for (int i=0;i<size;i++)
			{
				gComponentThreads.remove_thread(gpHeaderThreads[i]);
				gpHeaderThreads[i]->~thread();
			}
		}
		
		for( PlatformHeaders::iterator i = unsuccessfulHeaders.begin(); i != unsuccessfulHeaders.end(); ++i )
		{  
			// Build list of headers that could not be compiled with platform data:
			platformUnsuccessfulHeaderNames.push_back(pair<string, string>(i->first->ID(), i->second->ID()));
		}
		
		if(platformUnsuccessfulHeaderNames.size() >0)
			AnalyseHeaders(platformUnsuccessfulHeaderNames, 1, report, issues, platformUnsuccessfulCompErrs); 
	}
	
	mainThreads.join_all(); // wait for all threads in mainThreads to complete
	compErrors += mergeVectorCompErrs + unsuccessfulCompErrs + platformUnsuccessfulCompErrs;
	report.finishReport();

	// List number of files which had compilation errors and could not be compiled	
	if ( _current_files + (int)excludedHeaderSize < _total_files )
		cout << "\n" << ( _total_files - (_current_files + excludedHeaderSize) ) <<"  files out of " << _total_files << " had some issues and could not be analysed.\n" << endl;

	// Wrap up the run and print statistics
	unsigned int count = _total_files * 2;

	endtime = time(NULL);
	time_t runningtime = endtime - starttime;
	double timedelta = 0.0;
	if (count > 0)
	{
		timedelta = (double)runningtime/(double)count;
	}
	cout << "\n";
	cout << "---------------------------------------------" << endl;
	cout << "Finished!" << endl;
	cout << "Files processed: " << count << endl;
	cout << "Total time: " << endtime - originalStartTime << " seconds." << endl;
	cout << "Platform data initialization time: " << pfInitTime << " seconds.\n";
	cout << "Compilation and analysis time: " << (long)runningtime << " seconds (Average: "<<timedelta<<" seconds per file).\n";
	cout << "Compilation errors: " << compErrors << endl;
	if(excludedHeaderSize > 0 )
	cout << "No of excluded headers: " << excludedHeaderSize << endl;
	cout << "---------------------------------------------" << endl;

	if (iNotRemovedFiles.size() != 0)
	{
		cout << iNotRemovedFiles.size() << "\n";
		list<string> tempvar;
		list<string>::iterator removefile = iNotRemovedFiles.begin();
		list<string>::iterator fileend = iNotRemovedFiles.end();
		for(; removefile != fileend; removefile++)
		{
			CPPParser::RemoveFile(*removefile, tempvar);
		}
		if (tempvar.size() != 0)
		{
			iNotRemovedFiles = tempvar;
		} else
		{
			iNotRemovedFiles.clear();
		}
	}

	if (ret == 0 && issues != 0)
	{
		ret = 1;
	}
	return ret;
}

void Analyser::AnalyseHeaders(const vector<pair<string, string> >& headerList, int bundlesize, ReportGenerator& report, int& issues, int& compErrors)
{    
	unsigned int processedcount = 1;    
	stringvector basefilenames;
	stringvector curfilenames;
	vector<pair<string, string> > unsuccessfulHeaders;
	
	vector<pair<string, string> >::const_iterator fnmapiter = headerList.begin();
	while (fnmapiter != headerList.end())
	{
		// Push the pair's members to their respective vectors
		// for bundle handling
		basefilenames.push_back(fnmapiter->first);
		curfilenames.push_back(fnmapiter->second);

		// If a bundle is full or the item is the last one to process,
		// we parse the current file lists to xml files
		if ((processedcount > 0 && (processedcount % bundlesize == 0)) || 
			processedcount == headerList.size())
		{
			if (!AnalyseBundle(basefilenames,curfilenames,report, issues))
			{
				//If there where parsing errors in a bundle, we try to compile each header
				// one by one
				stringvector::iterator basebegin = basefilenames.begin();
				stringvector::iterator baseend = basefilenames.end();
				stringvector::iterator currentbegin = curfilenames.begin();

				if( basefilenames.size() == 1 ||
					bundlesize == 1 )

				{
					if( basebegin != baseend )
					{
						//Add compilation error to the report
						string compilationError = iCompErrTxt;
						report.addIssue((*basebegin), "", EIssueIdentityFile, EIssueTypeCompilationError, ESeverityBBCBreak, ESeveritySCBreak, "", 0,"",
							(*currentbegin),compilationError);
						issues++;

						compErrors++;
					}
				}
				else
				{
					while(basebegin != baseend )
					{
						stringvector basefilename;
						stringvector curfilename;
						basefilename.push_back(*basebegin);
						curfilename.push_back(*currentbegin);
						if (!AnalyseBundle(basefilename,curfilename,report, issues))
						{
							//Add compilation error to the report						
							string compilationError = iCompErrTxt;
							report.addIssue((*basebegin), "", EIssueIdentityFile, EIssueTypeCompilationError, ESeverityBBCBreak, ESeveritySCBreak, "", 0,"",
								(*currentbegin),compilationError);
							issues++;								
							compErrors++;
						}
						basebegin++;
						currentbegin++;
					}
				}
			}
			basefilenames.clear();
			curfilenames.clear();
		}

		fnmapiter++;
		processedcount++;
	}
	
    if (iNotRemovedFiles.size() != 0)
	{            
		list<string> tempvar;
		list<string>::iterator removefile = iNotRemovedFiles.begin();
		list<string>::iterator fileend = iNotRemovedFiles.end();
		for(; removefile != fileend; removefile++)
		{
			CPPParser::RemoveFile(*removefile, tempvar);
		}
		if (tempvar.size() != 0)
		{
			iNotRemovedFiles = tempvar;
		} 
		else
		{
			iNotRemovedFiles.clear();
		}
	} 
	
}

// ----------------------------------------------------------------------------
// Analyser::AnalyseBundle
// ----------------------------------------------------------------------------
//
//bool Analyser::AnalyseBundle(const stringvector& basefilenames, const stringvector& curfilenames, ReportGenerator& report, int& issues)
bool Analyser::AnalyseBundle(const stringvector& basefilenames, 
                             const stringvector& curfilenames, 
                             ReportGenerator& report, 
                             int& issues,
                             CPPParser* baseParser,
                             CPPParser* currParser,
                             stringvector* basecompileset,
                             stringvector* currcompileset)
{
	auto_ptr<CPPParser> baseAutoPtr;
	auto_ptr<CPPParser> currAutoPtr;
	CPPParser* parser  = 0;
	CPPParser* parser2 = 0;

	if( baseParser )
	{
		// This function does not own the pointer, so no auto_ptr used here.
		parser = baseParser;
	}
	else
	{
		parser = new CPPParser(iParams.getParameter(BASELINEPLAT));
		// Set temp directory for parser
		parser->setTemp(iParams.getParameter(TEMPDIR));
		// Set forced headers
		parser->setForcedHeaders(iForcedBaselineHeaders);
		// Wrap allocated memory to an auto_ptr to get it deallocated properly.
		baseAutoPtr.reset(parser);                                  
	}
	if( currParser )
	{
		// This function does not own the pointer, so no auto_ptr used here.
		parser2 = currParser;        
	}
	else
	{
		parser2 = new CPPParser(iParams.getParameter(CURRENTPLAT));
		// Set temp directory for parser
		parser2->setTemp(iParams.getParameter(TEMPDIR));
		// Set forced headers
		parser2->setForcedHeaders(iForcedCurrentHeaders);
		// Wrap allocated memory to an auto_ptr to get it deallocated properly.
		currAutoPtr.reset(parser2);
	}

	try 
	{
		// Parse the filename vectors into XML and eventually into a DOM format
		DOMNode* root = 0;
		DOMNode* root2 = 0;
		if(basecompileset && basecompileset->size() != 0 )
		{
			root = parser->parse(*basecompileset, "base", iParams.getParameter(BASELINEDIR), iNotRemovedFiles);
		}
		else
		{
			root = parser->parse(basefilenames, "base", iParams.getParameter(BASELINEDIR), iNotRemovedFiles);
		}
		if(currcompileset && currcompileset->size() != 0 )
		{
			root2 = parser2->parse(*currcompileset, "current", iParams.getParameter(CURRENTDIR), iNotRemovedFiles);
		}
		else
		{
			root2 = parser2->parse(curfilenames, "current", iParams.getParameter(CURRENTDIR), iNotRemovedFiles);
		}

		MacroAnalyser macros(parser->getMacroFilename(), parser2->getMacroFilename(), basefilenames, curfilenames);

		macros.Analyse(iMacroFiles);

#if !defined(_DEBUG) && !defined(DEBUG)
		parser->RemoveFile(parser->getMacroFilename(), iNotRemovedFiles);
		parser2->RemoveFile(parser2->getMacroFilename(), iNotRemovedFiles);
		parser->RemoveFile(parser->getCompErrFile(), iNotRemovedFiles);
		parser2->RemoveFile(parser2->getCompErrFile(), iNotRemovedFiles);
#endif
		// Merged macros
		//
		list<pair<string,string> > mergedfiles;
		stringvector::const_iterator basebegin = basefilenames.begin();
		stringvector::const_iterator baseend = basefilenames.end();
		stringvector::const_iterator currentbegin = curfilenames.begin();
		while(basebegin != baseend)
		{
			mergedfiles.push_back(pair<string,string>(*basebegin,*currentbegin));
			basebegin++;
			currentbegin++;
		}
		if(mergedfiles.size() > 0)
		{
			issues += analyseTrees(root, root2,mergedfiles,report);
		}

		// Duplicated macros
		//
		// Base duplicates
		map<string, vector<pair<string,string> > >& duplicatedMacros = macros.getBaseDuplicates();
		map<string, vector<pair<string,string> > >::iterator duplicatedbegin = duplicatedMacros.begin();
		map<string, vector<pair<string,string> > >::iterator duplicatedend = duplicatedMacros.end();
		for(; duplicatedbegin != duplicatedend; duplicatedbegin++)
		{
			string filename = duplicatedbegin->first;
			// Process each duplicated macro from duplicatedMacros
			vector<pair<string,string> >::iterator duplicatedbegin2 = duplicatedbegin->second.begin();
			vector<pair<string,string> >::iterator duplicatedend2 = duplicatedbegin->second.end();
			for(; duplicatedbegin2 != duplicatedend2; duplicatedbegin2++)
			{
				string macroname = duplicatedbegin2->first;
				int lineNo = atoi(duplicatedbegin2->second.c_str());
				report.addIssue(filename, macroname, EIssueIdentityMacro, EIssueTypeNotAnalysed, ESeverityInformative, ESeveritySCInformative, "", lineNo, "","", "");
				issues++;
			}
		}

		// Current
		map<string, vector<pair<string,string> > >& currDuplicatedMacros = macros.getCurrentDuplicates();
		duplicatedbegin = currDuplicatedMacros.begin();
		duplicatedend = currDuplicatedMacros.end();
		for(; duplicatedbegin != duplicatedend; duplicatedbegin++)
		{
			string filename = duplicatedbegin->first;
			// Process each duplicated macro from duplicatedMacros
			vector<pair<string,string> >::iterator duplicatedbegin2 = duplicatedbegin->second.begin();
			vector<pair<string,string> >::iterator duplicatedend2 = duplicatedbegin->second.end();
			for(; duplicatedbegin2 != duplicatedend2; duplicatedbegin2++)
			{
				string macroname = duplicatedbegin2->first;
				int lineNo = atoi(duplicatedbegin2->second.c_str());
				report.addIssue("", macroname, EIssueIdentityMacro, EIssueTypeNotAnalysed, ESeverityInformative, ESeveritySCInformative, "", lineNo,"", filename, "");
				issues++;
			}
		}

		// Removed macros
		//
		map<string, TChange<list<pair<string,string> > > >& removedMacros = macros.getRemoved();
		map<string, TChange<list<pair<string,string> > > >::iterator removedbegin = removedMacros.begin();
		map<string, TChange<list<pair<string,string> > > >::iterator removedend = removedMacros.end();
		for(; removedbegin != removedend; removedbegin++)
		{
			string basefilename = removedbegin->second.GetBase();
			string currentfilename = removedbegin->second.GetCurrent();
			// Process each removed macro from removedMacros
			list<pair<string,string> >::iterator removedbegin2 = removedbegin->second.GetValue().begin();
			list<pair<string,string> >::iterator removedend2 = removedbegin->second.GetValue().end();
			for(; removedbegin2 != removedend2; removedbegin2++)
			{
				string macroname = removedbegin2->first;
				//int lineNo = atoi(removedbegin2->second.c_str());
				// No need to pass the line no in removed case.
				report.addIssue(basefilename, macroname, EIssueIdentityMacro, EIssueTypeRemoval, ESeverityPossibleBBCBreak, ESeveritySCBreak, "", 0,"", currentfilename, "");
				issues++;
			}
		}

		// Changed macros
		//
		map<string, TChange<map<string, pair<pair<string,string>,string> > > >& changedMacros = macros.getChanged();
		map<string, TChange<map<string, pair<pair<string,string>,string> > > >::iterator changedbegin = changedMacros.begin();
		map<string, TChange<map<string, pair<pair<string,string>,string> > > >::iterator changedend = changedMacros.end();
		for(; changedbegin != changedend; changedbegin++)
		{
			string basefilename = changedbegin->second.GetBase();
			string currentfilename = changedbegin->second.GetCurrent();
			// Process each changed macro from changedMacros
			map<string, pair<pair<string,string>,string> >::iterator changedbegin2 = changedbegin->second.GetValue().begin();
			map<string, pair<pair<string,string>,string> >::iterator changedend2 = changedbegin->second.GetValue().end();
			for(; changedbegin2 != changedend2; changedbegin2++)
			{
				string macroname = changedbegin2->first;
				string newcode = changedbegin2->second.first.second;
				int lineNo = atoi(changedbegin2->second.second.c_str());
				report.addIssue(basefilename, macroname, EIssueIdentityMacro, EIssueTypeChange, ESeverityPossibleBBCBreak, ESeveritySCNULL, newcode, lineNo, "",currentfilename, "");
				issues++;
			}
		}

		
		//clear the last set of files with macros
		iMacroFiles.clear();
	} catch (HAException e)
	{
#if !defined(_DEBUG) && !defined(DEBUG)
		parser->RemoveFile(parser->getMacroFilename(), iNotRemovedFiles);
		parser2->RemoveFile(parser2->getMacroFilename(), iNotRemovedFiles);
#endif

		//header has failed compilation with gccxml. get the compilation error text.
		if (parser2->getCompErrFile()!="")
		{
			iCompErrTxt = BBCFileUtils::getCompilationError(parser2->getCompErrFile());
			if (iCompErrTxt == "")
				iCompErrTxt = BBCFileUtils::getCompilationError(parser->getCompErrFile());
		}
		else 
		{
			if(parser->getCompErrFile()!="")
				iCompErrTxt = BBCFileUtils::getCompilationError(parser->getCompErrFile());
		}
#if !defined(_DEBUG) && !defined(DEBUG)
		parser->RemoveFile(parser->getCompErrFile(), iNotRemovedFiles);
		parser2->RemoveFile(parser2->getCompErrFile(), iNotRemovedFiles);
#endif

		
		//delete parser;
		//delete parser2;
		return false;
	}
	//delete parser;
	//delete parser2;
	return true;
}


// ----------------------------------------------------------------------------
// Analyser::processFileReplaces
// Process the file replaces
// ----------------------------------------------------------------------------
//
pair<string, string> Analyser::processFileReplaces(pair<string, string>& aFile, const stringmap& aReplaceMap, list<pair<string, string> >& aCurrentFiles)
{
    string searched(aFile.second);
    pair<string, string>  replacement(aFile);
    // If there are items on replace map, then apply the
    // replaces when necessary
    if (aReplaceMap.size() > 0)
    {
        StringMapIterC fileMapIter = aReplaceMap.find(searched);
        if (fileMapIter != aReplaceMap.end())
        {
            string file = fileMapIter->second;
            list<pair<string, string> >::const_iterator filereplace = FindFromList(toLowerCaseWin(file), aCurrentFiles, ERightValue, compareFiles);
            if (filereplace != aCurrentFiles.end())
            {
                replacement = *filereplace;
            }
        }
    }

    return replacement;
}


// ----------------------------------------------------------------------------
// Analyser::createReplaceMap
//
// ----------------------------------------------------------------------------
//
void Analyser::createReplaceMap(const string& aReplaceList, stringmap& aReplaceMap)
{
    string originalfilename("");
    string replacementfilename("");
    string* name = &originalfilename;
    bool original = true;
    bool isstr = false;
    for (size_t i = 0; i < aReplaceList.length(); i++)
    {
        char ch = aReplaceList.at(i);
        if (ch == ' ' && isstr == false)
        {
            if (original == true)
            {
                original = false;
                name = &replacementfilename;
            }
            else
            {
                // Pair separator found. 
                // Store the pair (original, replacement)
                stringpair mappair(toLowerCaseWin(originalfilename), toLowerCaseWin(replacementfilename));
                aReplaceMap.insert(mappair);
                replacementfilename.resize(0);
                originalfilename.resize(0);

                original = true;
                name = &originalfilename;
            }
        } else if (ch == '"')
        {
            if (isstr == true)
            {
                isstr = false;
            } else
            {
                isstr = true;
            }
        } else
        {
            *name += ch;
        }
    }
    if (original == true)
    {
        throw HAException("Syntax error: There has been given file name to replace but not file name for replace.");
    }
    if (originalfilename.length() > 0 && replacementfilename.length() > 0)
    {
        // Store the last pair in replacement list
        stringpair mappair(toLowerCaseWin(originalfilename), toLowerCaseWin(replacementfilename));
        aReplaceMap.insert(mappair);
    }
}

// ----------------------------------------------------------------------------
// Analyser::fileDiffs
// ----------------------------------------------------------------------------
//
void Analyser::fileDiffs(vector<pair<string, string> >& aFiles, list<string>& aMismatches)
{
    vector<pair<string, string> > ret;
    ret.reserve(aFiles.size());
    vector<pair<string, string> >::iterator file = aFiles.begin();
    vector<pair<string, string> >::iterator fileend = aFiles.end();
    
    for(;file != fileend; file++)
    {
        // START -- Support for multiple header directories
        list<pair<string, string> > basedirs = BBCFileUtils::extractFilenames(iParams.getParameter(BASELINEDIR));
        list<pair<string, string> >::iterator basedirbegin = basedirs.begin();
        string basedir;
        string basefile;
        for(; basedirbegin != basedirs.end(); basedirbegin++)
        {
            // Find the base dir from the list of base dirs
            basedir = basedirbegin->first;
            basefile = basedir + DIR_SEPARATOR + file->first;
            if (BBCFileUtils::FileExists(basefile))
                break;
        }  
    
        list<pair<string, string> > curdirs = BBCFileUtils::extractFilenames(iParams.getParameter(CURRENTDIR));
        list<pair<string, string> >::iterator curdirbegin = curdirs.begin();
        string curdir;
        string curfile;
        for(; curdirbegin != curdirs.end(); curdirbegin++)
        {
            // Find the current dir from the list of current dirs
            curdir = curdirbegin->first;
            curfile = curdir + DIR_SEPARATOR + file->second;
            if (BBCFileUtils::FileExists(curfile))
                break;
        } 
        // END -- Support for multiple header directories
         
        if (file->second == "")
        {
            // We hadn't find matching file from current list so we add it to removed list
            aMismatches.push_back(basefile);
        } else
        {
            pair<string, string> tempvar(basefile, curfile);
            ret.push_back(tempvar);
        }
    }
    aFiles = ret;
}

// ----------------------------------------------------------------------------
// Analyser::getFilenameWithoutDir
// Return the file part of the filename, eg. retuns the rightmost part of
// the given string, up to a "\" // or "/" separator.
// ----------------------------------------------------------------------------
//
string Analyser::getFilenameWithoutDir(const string& aFilename)
{
    string ret = aFilename;
    string::size_type idx = rightmostDirSeparatorIndex(aFilename);
    if (idx != string::npos)
    {
        ret = aFilename.substr(idx+1, aFilename.length() - idx);
    }
    return ret;
}

// ----------------------------------------------------------------------------
// Analyser::testFileAvailability
// ----------------------------------------------------------------------------
//
#if 0
void Analyser::testFileAvailability(stringmap map)
{
    stringmap::iterator begin = map.begin();
    stringmap::iterator end = map.end();

    for(; begin!= end; begin++)
    {
        string file = (*begin).first;

        int isValid = ACCESS(file.c_str(), 0);
        if (isValid == -1)
        {
            throw HAException("File: \"" + file + "\" not found");
        }
        
        file = (*begin).second;

        isValid = ACCESS(file.c_str(), 0);
        if (isValid == -1)
        {
            throw HAException("File: \"" + file + "\" not found");
        }
    }
}

#endif

// ----------------------------------------------------------------------------
// Analyser::MergeFiles
// ----------------------------------------------------------------------------
//
void Analyser::MergeFiles(const list<pair<string, string> >& aBasefiles, list<pair<string, string> >& aCurrentfiles,
                          const string& aReplaceList, vector<pair<string, string> >& aMatches)
{
    size_t asdf = aBasefiles.size();
    list<pair<string, string> >::const_iterator baseiter = aBasefiles.begin();
    list<pair<string, string> >::const_iterator baseend = aBasefiles.end();
    list<pair<string, string> > removedcurrentfiles;
    list<pair<string, string> > mismatches;
    if (!iParams.givenParameter(BASELINE))
    {
        stringmap replaceMap;
        if (aReplaceList.length() > 0)
        {            
            createReplaceMap(aReplaceList, replaceMap);         
            stringmap::iterator begin = replaceMap.begin();
            stringmap::iterator end = replaceMap.end();
        }                
        for(; baseiter != baseend; baseiter++)
        {            
            pair<string, string> file = *baseiter;
            file = processFileReplaces(file, replaceMap, aCurrentfiles);
            pair<string,string> tempvar;
			//compareWholeString will be set to true, 
			//only if the file name with whole path of current file need to compare with base file.
			//else by default will always be set to false.
            list<pair<string, string> >::iterator current = FindFromList(file.second, aCurrentfiles, ERightValue, compareFiles, false,true);
            if (current != aCurrentfiles.end())
            {
                tempvar.first = baseiter->first.substr(1);
                tempvar.second = current->first.substr(1);
                aMatches.push_back(tempvar);
                removedcurrentfiles.push_back(*current);
                aCurrentfiles.erase(current);
            } else
            {
                current = FindFromList(file.second, removedcurrentfiles, ERightValue, compareFiles, false);
                if (current != removedcurrentfiles.end())
                {
                    tempvar.first = baseiter->first.substr(1);
                    tempvar.second = current->first.substr(1);
                    aMatches.push_back(tempvar);
                } else
                {
                    mismatches.push_back(file);
                }
            }
        }        
        baseiter = mismatches.begin();
        baseend = mismatches.end();        
        for(; baseiter != baseend; baseiter++)
        {
            string filename = BBCFileUtils::StripPath(baseiter->second);
            pair<string, string> file(filename, filename); // We don't need to put filename to lowercase as it's already in lowercase
            file = processFileReplaces(file, replaceMap, aCurrentfiles);
            string empty("");
            pair<string,string> tempvar;
            tempvar.first = baseiter->first.substr(1);
            list<pair<string, string> >::iterator current = FindFromList(file.second, aCurrentfiles, ERightValue, compareFiles);
            if (current != aCurrentfiles.end())
            {
                tempvar.second = current->first.substr(1);
            } else
            {
                tempvar.second = empty;
            }
            aMatches.push_back(tempvar);
        }        
    } else
    {
        // START -- Support for multiple header directories
        list<pair<string, string> > basedirs = BBCFileUtils::extractFilenames(iParams.getParameter(BASELINEDIR));
        list<pair<string, string> >::iterator basedirbegin = basedirs.begin();
        bool  basefilefound = false;
        string basefile;
        for(; basedirbegin != basedirs.end(); basedirbegin++)
        {
            string basedir = basedirbegin->first;       
            basefile = basedir + DIR_SEPARATOR + aBasefiles.front().first;

            if (ACCESS(basefile.c_str(), 0) != -1)
            {
                basefilefound = true;
                break;
            }
      }
        list<pair<string, string> > curdirs = BBCFileUtils::extractFilenames(iParams.getParameter(CURRENTDIR));
        list<pair<string, string> >::iterator curdirbegin = curdirs.begin();
        bool  curfilefound = false;
        string curfile;
        
        for(; curdirbegin != curdirs.end(); curdirbegin++)
        {
            string curdir = curdirbegin->first;       
            curfile = curdir + DIR_SEPARATOR + aBasefiles.front().first;
            if (ACCESS(curfile.c_str(), 0) != -1)
            {
                curfilefound = true;
                break;
            }
        }
        if (!basefilefound )
        {
            throw HAException("File \"" + basefile + "\" not found");
        }
        if (!curfilefound)
        {
            throw HAException("File \"" + curfile + "\" not found");
        }
        pair<string,string> tempvar(aBasefiles.front().first, aCurrentfiles.front().first);
        aMatches.push_back(tempvar);
        // END -- Support for multiple header directories
    }
}

// ----------------------------------------------------------------------------
// AnalyserParams::diffs
//  	
// ----------------------------------------------------------------------------
//
void Analyser::diffs(   const list<pair<string, string> >& allfiles, 
                        const list<pair<string, string> >& sets, 
                        list<pair<string, string> >& result)
{
    result = sets;
    list<stringpair >::iterator setiter = result.begin();
    while(setiter != result.end())
    {
        if( setiter->first.find_first_of("*?") != string::npos )
            setiter = result.erase(setiter);
        else
            ++setiter;
    }
    
    list<pair<string, string> >::const_iterator file = allfiles.begin();
    list<pair<string, string> >::const_iterator fileend = allfiles.end();
    for(; file != fileend; file++)
    {    
        list<pair<string, string> >::iterator set = 
            FindFromList(file->second, result, ERightValue);
        if (set == result.end())
        {
            set = FindFromList(file->second, result, ERightValue, compareFiles);
        }
        
        if (set != result.end())
        {
            result.erase(set);
        }
    }
    
}

// ----------------------------------------------------------------------------
// AnalyserParams::canonicalizeFilename
// Get the actual name of a file. 
// ----------------------------------------------------------------------------
//
list<pair<string, string> > Analyser::canonicalizeFilename(list<pair<string, string> >& sets)
{
    list<pair<string, string> > ret;
    list<pair<string, string> >::iterator begin = sets.begin();
    list<pair<string, string> >::iterator end = sets.end();
    for(; begin != end; begin++)
    {
        if (begin->first.at(0) != DIR_SEPARATOR && begin->first.find(DIR_SEPARATOR) != string::npos)
        {
            string left = "";
            left += DIR_SEPARATOR;
            left += begin->first;
            string right = "";
            right += DIR_SEPARATOR;
            right += begin->second;
            ret.push_back(pair<string, string>(left, right));
        } else
        {
            ret.push_back(*begin);
        }
    }

    return ret;
}


// ----------------------------------------------------------------------------
// Analyser::Wrapper
// Wrapper function to analyse all files in a component in separate thread.
// 
// ----------------------------------------------------------------------------
//
void Analyser::Wrapper( ReportGenerator& report, 
                        int& issues, 
                        CPPParser baseParser, 
                        CPPParser currParser, 
                        PlatformHeaders& pfHeaders, 
                        PlatformHeaders& unsuccessfulHdrs
                       )
{
	stringvector tiBaseFilenames; // This contains also additional headers needed to compile baseline
	stringvector tiCurrFilenames; // This contains also additional headers needed to compile product  
	PlatformHeaders tiInvalidFiles;	// holds a list of files without include guards need to be compiled individually
	stringvector tiBaseIncludes; // This contains also additional headers needed to compile baseline
	stringvector tiCurrIncludes; // This contains also additional headers needed to compile product  

	stringvector baseSysIncludes; // This contains headers needed to compile baseline for 3rd time analyzation of a single header.
	stringvector curSysIncludes;  //  This contains headers needed to compile product for 3rd time analyzation of a single header.

	tiBaseFilenames.assign(iBaseFilenames.begin(),iBaseFilenames.end());
	tiCurrFilenames.assign(iCurrFilenames.begin(),iCurrFilenames.end());
	tiInvalidFiles.assign(iInvalidFiles.begin(),iInvalidFiles.end());
	tiBaseIncludes.assign(iBaseIncludes.begin(),iBaseIncludes.end());
	tiCurrIncludes.assign(iCurrIncludes.begin(),iCurrIncludes.end());
	
	if (iOnlySystemIncludeRequired == true)
	{
		//tiBaseIncludes and tiCurrIncludes are required for 3rd time analyzation.
		//This time parse each unsuccessful header with both system includes and paths.
		baseSysIncludes.assign(tiBaseIncludes.begin(),tiBaseIncludes.end());
		curSysIncludes.assign(tiCurrIncludes.begin(),tiCurrIncludes.end());

		// Clear these includes as for 2nd time parsing of each unsuccessful headres, 
		//as only system include paths arerequuired.
		tiBaseIncludes.clear();
		tiCurrIncludes.clear();
	}
	
	
	if( (tiBaseIncludes.size()>0 && tiCurrIncludes.size()>0)|| (tiBaseFilenames.size()>0 && tiCurrFilenames.size()>0) )
	{
		if( AnalyseBundle(tiBaseFilenames, tiCurrFilenames, report, issues, &baseParser, &currParser, &tiBaseIncludes, &tiCurrIncludes))
		{
			tiBaseFilenames.clear();
			tiCurrFilenames.clear();
		}
	}

	if (iNotRemovedFiles.size() != 0)
	{            
		list<string> tempvar;
		list<string>::iterator removefile = iNotRemovedFiles.begin();
		list<string>::iterator fileend = iNotRemovedFiles.end();
		for(; removefile != fileend; removefile++)
		{
			CPPParser::RemoveFile(*removefile, tempvar);
		}
		if (tempvar.size() != 0)
		{
			iNotRemovedFiles = tempvar;
		} 
		else
		{
			iNotRemovedFiles.clear();
		}
	}  
	
	if(tiInvalidFiles.size() > 0)
	{
		// also add to this list, the set of headers
		// without include guards
		PlatformHeaders::iterator add = tiInvalidFiles.begin();
		for(; add != tiInvalidFiles.end(); ++add )
		{
			tiBaseFilenames.push_back( add->first->ID() );
			tiCurrFilenames.push_back( add->second->ID() );
		}
	}		
	
	// if thread flag is set and there are gretaer number of files, create threads for analysing every PLATFORM_BUNDLESIZE number of files
	if( iUseThread && tiBaseFilenames.size() >= PLATFORM_BUNDLESIZE  )
	{
		stringvector tmp;
		int pcount = 0;
		stringvector::iterator i = tiBaseFilenames.begin();                
		for(; i != tiBaseFilenames.end(); ++i )
		{				
			pcount++;
			PlatformHeaders::iterator h = FindHeaderPair(*i, pfHeaders);
			if( h != pfHeaders.end() )
			{			
				tmp.push_back(*i);
			}			
			if ((pcount % PLATFORM_BUNDLESIZE == 0 || pcount == tiBaseFilenames.size()) && tmp.size()>0)		
			{
				while (lock.locked())
				{
					#ifdef __WIN__
					Sleep(4000);
					#else
					usleep(4000*1000);
					#endif
				}
				lock.lock();
				
				if(gComponentThreads.size() >= MAX_THREAD_COUNT2)
				{
					gComponentThreads.join_all();
					int size = gComponentThreads.size();
					for (int i=0;i<size;i++)
					{	
						gComponentThreads.remove_thread(gpHeaderThreads[i]);
						gpHeaderThreads[i]->~thread();	
					}				
				}
						
				//2nd time analyzation of each header in a different thread
				Analyser* obj = new Analyser();
				*obj = *this;
				int size = gComponentThreads.size();
				gpHeaderThreads[size]=gComponentThreads.create_thread(boost::bind(&Analyser::Wrapper2,obj,tmp, 
						boost::ref(pfHeaders), boost::ref(unsuccessfulHdrs), boost::ref(report), boost::ref(issues)));
				lock.unlock();	
				tmp.clear();
							
			}
		}
	}
	else // do not create different thread. analyse in the same thread.
	{						
		stringvector::iterator i = tiBaseFilenames.begin();                
		for(; i != tiBaseFilenames.end(); ++i )
		{                    
			PlatformHeaders::iterator h = FindHeaderPair(*i, pfHeaders);
			if( h != pfHeaders.end() )
			{
				if(( pfHeaders.size() > 1 ) )
				{
					PlatformHeaders tempHeaders;
					tempHeaders.push_back(*h);
					h->first->SetStatus(Header::HDR_STATUS_TO_BE_ANALYZED);
					iOnlySystemIncludeRequired = true;
					//2nd time analyzation of each header in same thread
					AnalyzePlatforms( tempHeaders, unsuccessfulHdrs, report, issues, false );
					iOnlySystemIncludeRequired = false;
				}
				else
				{
					//The 3rd time parsing is required to check again each unsuccessful headers 
					//with system includes and paths from platform data
					if(!AnalyseBundle(tiBaseFilenames, tiCurrFilenames, report, issues, &baseParser, &currParser, &baseSysIncludes, &curSysIncludes))
					{
						if( FindHeaderPair(h->first->ID(), unsuccessfulHdrs ) == unsuccessfulHdrs.end() )
						{
							unsuccessfulHdrs.push_back(*h); 
						}
					} 
					if (iNotRemovedFiles.size() != 0)
					{            
						list<string> tempvar;
						list<string>::iterator removefile = iNotRemovedFiles.begin();
						list<string>::iterator fileend = iNotRemovedFiles.end();
						for(; removefile != fileend; removefile++)
						{
							CPPParser::RemoveFile(*removefile, tempvar);
						}
						if (tempvar.size() != 0)
						{
							iNotRemovedFiles = tempvar;
						} 
						else
						{
							iNotRemovedFiles.clear();
						}
					}	
				}                        
			}
		}	
	}	
}  

// ----------------------------------------------------------------------------
// Analyser::Wrapper2
// Wrapper function to analyse group of files in a component individually in different thread.
// 
// ----------------------------------------------------------------------------
//
void Analyser::Wrapper2(stringvector filenames, PlatformHeaders& pfHeaders, PlatformHeaders& unsuccessfulHdrs, ReportGenerator& report, int& issues)
{
	PlatformHeaders tempHeaders;
	stringvector::iterator i = filenames.begin();                
	for(; i != filenames.end(); ++i )
	{	
		PlatformHeaders::iterator h = FindHeaderPair(*i, pfHeaders);
		if( h != pfHeaders.end() )
		{	
			tempHeaders.push_back(*h);
			h->first->SetStatus(Header::HDR_STATUS_TO_BE_ANALYZED);
			iOnlySystemIncludeRequired = true;	
			AnalyzePlatforms( tempHeaders, unsuccessfulHdrs, report, issues, false );
			iOnlySystemIncludeRequired = false;
		}
	}	

	if (iNotRemovedFiles.size() != 0)
					{            
						list<string> tempvar;
						list<string>::iterator removefile = iNotRemovedFiles.begin();
						list<string>::iterator fileend = iNotRemovedFiles.end();
						for(; removefile != fileend; removefile++)
						{
							CPPParser::RemoveFile(*removefile, tempvar);
						}
						if (tempvar.size() != 0)
						{
							iNotRemovedFiles = tempvar;
						} 
						else
						{
							iNotRemovedFiles.clear();
						}
					}
}



void Analyser::ParseAndCompareResourceFiles(vector<pair< string, string> >& resourcevector, ReportGenerator& report)
{
	ResourceContent baseResource;
	ResourceContent curResource;

	list<pair<string, string> > iBaseSystemheaders = BBCFileUtils::extractFilenames(iParams.getParameter(BASELINEPLAT));
	list<pair<string, string> > iCurSystemheaders = BBCFileUtils::extractFilenames(iParams.getParameter(CURRENTPLAT));

	for(int outer = 0; outer< (int)resourcevector.size(); outer++)
	{
		list<pair<string, string> > baseSystemheaders;
		list<pair<string, string> > curSystemheaders;

		baseSystemheaders = iBaseSystemheaders;
		curSystemheaders = iCurSystemheaders;
		pair <string, string> files = resourcevector.at(outer);
		vector <string> bIncludes;
		vector <string> cIncludes;


		baseResource.RHFileName = "";
		curResource.RHFileName = "";

		baseResource.RHFileName = BBCFileUtils::TrimAll(files.first);
		curResource.RHFileName = BBCFileUtils::TrimAll(files.second);

		pair <string, string> fileAnalyzed;
		fileAnalyzed.first = baseResource.RHFileName;
		fileAnalyzed.second = curResource.RHFileName;
		bool pairFound = false;
		// check if the file is already analyzed or not.
		for(int i = 0; i < (int)iRHFile_Analyzed.size(); i++ )
		{
			pair<string,string> filePair = iRHFile_Analyzed.at(i);
			if(fileAnalyzed.first == filePair.first )
			{
				pairFound = true;
				break;
			}
		}
		// File is not analyzed yet, so analyze it.
		if(pairFound == false )
		{
			iRHFile_Analyzed.push_back(fileAnalyzed);

			ifstream file(files.first.c_str());
			if(!file.is_open())
			{
				cerr << "ERROR: Cannot open " << files.first << " for reading!" << endl;
				exit(17);
			}

			// baseline resource file parsing
			getElementListFromRHFile(file,baseResource,bIncludes );
			file.close();

			// handle #include .RH headers, get proper path from system includes
			int basePos = (int)baseResource.RHFileName.find_last_of(DIR_SEPARATOR);
			string basePath = baseResource.RHFileName.substr(0,basePos);
			vector<pair<string,string> > includes;
			bool isPresent = false;
			pair<string,string> bPath;
			list<pair<string,string> >::iterator bHdr = baseSystemheaders.begin();
			for(;bHdr!= baseSystemheaders.end(); bHdr++)
			{
				bPath = *bHdr;
				if(bPath.first == basePath)
				{
					isPresent = true;
					break;
				}			
			}
			if(isPresent == false)
			{
				pair<string,string> bPair;
				bPair.first =basePath;
				bPair.second =basePath;
				baseSystemheaders.push_back(bPair);
			}

			bHdr= baseSystemheaders.begin();
			for(int i = 0; i < (int)bIncludes.size(); i++) 
			{
				for(;bHdr != baseSystemheaders.end(); bHdr++)
				{
					pair<string,string> baseHeader = *bHdr;
					pair<string,string>basePair;
					if(BBCFileUtils::FileExists(baseHeader.first + DIR_SEPARATOR + bIncludes.at(i)) )
					{
						basePair.first = baseHeader.first + DIR_SEPARATOR + bIncludes.at(i);
						includes.push_back(basePair);
						break;
					}
				}
			}

			ifstream file2(files.second.c_str());
			if(!file2.is_open())
			{
				cerr << "ERROR: Cannot open " << files.second << " for reading!" << endl;
				exit(17);
			}
			// current resource file parsing
			getElementListFromRHFile(file2,curResource, cIncludes );
			file2.close();
			
			_current_files++;
			cout << "\nAnalysing files (" << _current_files << "/" << _total_files << "): " << files.first <<" => "<< files.second << endl;

			// get current resource file's path and add to system include paths 
			// to get proper path for #include rh headers in current file
			int cPos = (int)curResource.RHFileName.find_last_of(DIR_SEPARATOR);
			string curPath = curResource.RHFileName.substr(0,cPos);
			isPresent = false;
			list<pair<string,string> >::iterator chdr= curSystemheaders.begin();
			pair<string,string> cPath;
			for(;chdr != curSystemheaders.end(); chdr++)
			{
				cPath = *chdr;
				if(cPath.first == curPath)
				{
					isPresent = true;
					break;
				}			
			}
			if(isPresent == false)
			{
				pair<string,string> cPair;
				cPair.first = curPath;
				cPair.second = curPath;
				curSystemheaders.push_back(cPair);
			}

			
			for(int out = 0; out < (int)includes.size(); out++)
			{
				int bLoc = (int)includes.at(out).first.find_last_of(DIR_SEPARATOR);
				string bString = includes.at(out).first.substr(bLoc+1,string::npos);
				bool includedHeaderPresent = false;

				for(int j = 0; j < (int)cIncludes.size(); j++) 
				{
					bool fileMatched = false;					
					if(bString == cIncludes.at(j))
					{
						includedHeaderPresent = true;
						chdr= curSystemheaders.begin();
						for(;chdr != curSystemheaders.end(); chdr++)
						{
							pair<string,string> curHeader = *chdr;						
							string curFile = curHeader.first + DIR_SEPARATOR + cIncludes.at(j);							
							if(BBCFileUtils::FileExists(curFile) ) 
							{
								fileMatched = true; // current file found in curr dir
								includes.at(out).second = curFile;
								break;
							}
						}
						if ( fileMatched == false )
						{
							// file does not exists in curdir
							report.addIssue(baseResource.RHFileName, includes.at(out).first, EIssueIdentityFile, 
								EIssueTypeRemoval,ESeverityBBCBreak,ESeveritySCNULL, "", 0, "",curResource.RHFileName,"");
						}
						break;
					}
				}
				if(includedHeaderPresent == false)
				{
					// add issue, as field is removed in current file.
					report.addIssue(baseResource.RHFileName, bString, EIssueIdentityField, 
						EIssueTypeRemoval,ESeverityNULL,ESeveritySCBreak, "", 0, "",curResource.RHFileName,"");
				}
			}

			for(int l = 0; l < (int)includes.size(); l++ )
			{
				pair<string,string> pair = includes.at(l);
				if(pair.first.size() > 0 && pair.second.size()>0)
				{				
					resourcevector.push_back(pair);
				}
			}

			compareResources( baseResource, curResource, report);
		}


		baseResource.structList.clear();
		baseResource.enumList.clear();
		baseResource.macroList.clear();

		curResource.structList.clear();
		curResource.enumList.clear();
		curResource.macroList.clear();


	}// end of one resource
	cout<<"\n\n"<<endl;
}


void Analyser::getElementListFromRHFile(std::ifstream& RHFile,ResourceContent& resource, vector< string >& includes )
{
	string line;
	EnumElement lEnum;
	string tempData;
	string elementVal;

	StructElement lStruct;
	string structName;

	bool structInuse = false;
	bool enumInuse = false;
	bool macroInuse = false;
	bool keyFound = false;
	bool elementfound = false;
	bool valueFound = false;

	bool comment = false;	
	bool ignoreLine = false;

	bool newLinecharFound = false; // for macros, newline character can be present

	long currentEnumVal = -1;

	char keywords [23][15] = {"short","long", "word", "len", "byte", "struct", "ltext","enum", "ltext8", "ltext16", "ltext32", "llink", "srlink","double",
		"buf<1>","buf<2>","buf<4>","buf<8>","buf<16>","buf<32>","buf<64>","buf<128>","buf<256>"};

	MacroElement macro;
	int lineNo = 0;

	while(getline(RHFile,line))
	{
		lineNo++;
		pair<string,int> enummember;
		StructMember elementMember;
		line = toLowerCase(trimWhiteSpace(line));

		// Ignore all comment lines. e.g /*xxxxxxxxxx*/ Struct ABCD , start reading characterwise from struct
		if(enumInuse == false && macroInuse == false && structInuse == false )
		{
			if(line.find("/*") != -1 )
			{
				if( line.find("*/") == -1)
				{
				comment = true;
				continue;
				}
				else
				{
					int com = (int)line.find_last_of("*");
					line= line.substr(com +2, string::npos);
				}
			}
			if(line.find("*/") != -1 )
			{
				comment = false;
				if(ignoreLine == true)
					ignoreLine = false;
				continue;
			}
			if(comment == true)
			{
				continue;
			}
			if(line.find("//") != -1 ) 
			{
				int com = (int)line.find_first_of("//");
				bool wordFound = false;
				line = line.substr(0,com);
				for (int i = 0; i< (int)line.size(); i++ )
				{
					// check  '//' commentline starts after some key value e.g struct ABCD // xyz
					if ( (int)line.at(i ) != 32 && (int)line.at(i) != 9 ) // 32 and 9 are for space and invalid character
					{
						wordFound = true;
						break;
					}
				}
				if(wordFound == false)
				continue;
			}

		}
 
		// Find any other header file is included in current file
		// Then add it to file and check whether this is already analyzed or not.
		// If not, then analyze it.
		if(line.find ("#") != -1 && line.find("include") != -1 )
		{
				int start = (int)line.find_first_of ("<");
			
			int end;
			if(start == -1)
			{
				start =(int) line.find_first_of("\"");
				end = (int)line.find_last_of("\"");
			}
			else
			{
				end = (int)line.find(">");
			}

			if (start > 0 && end > 0 )
			{
				line = line.substr(start + 1,(end - start) - 1);
				line = BBCFileUtils::TrimAll(line);
				int loc = (int)line.find(RH_EXTENSION);
				// Include only .rh files
				if(loc != -1)
					includes.push_back(line);
			}
		}

		// Now check lines for key structure (struct, enum, #inlude and start reading characterwise unless the key structure end.
		if (keyFound == false )
		{
			tempData.clear();
			int enumloc = (int)line.find(KEY_ENUM);
			// to get enum key word properly. After "enum" keyword, there might be no name present.
			// For this case, following checks are needed.
			if( enumloc!= -1)
			{
				enumInuse = true;
				string prestring = line.substr(0,enumloc);
				for(int i = 0; i< (int)prestring.size(); i++ )
				{
					if( (int)prestring.at(i)!= 32 && (int)prestring.at(i) != 9 )
					{
						enumInuse =false;
						break;
					}
				}
				if(enumInuse == true)
				{
					string postline = line.substr(enumloc+strlen(KEY_ENUM) ,string::npos);
					if( postline.size() > 0 && (int)postline.at(0)!= 32 && (int)postline.at(0) != 9 )
					{
							enumInuse =false;
							break;
					}
					else
					{
						line = postline;
						macroInuse = false;
						structInuse = false;
						lEnum.enumName = "";
						lEnum.enums.clear();
					}
				}
			}
			if(line.find(KEY_MACRO) != -1)
			{
				macroInuse = true;
				enumInuse = false;
				structInuse = false;
				macro.macroName = "";
				macro.macroVal = "";
				line = line.substr(strlen(KEY_MACRO),string::npos);
			}

			if(line.find(KEY_STRUCT) != -1)
			{
				structInuse = true;
				enumInuse = false;
				macroInuse = false;
				lStruct.structName = "";
				lStruct.members.clear();
				line = line.substr(strlen(KEY_STRUCT),string::npos);
			}	
		}

		// If any of the key found, then following lines will be checked character wise.
		if ( enumInuse == true || macroInuse == true || structInuse == true )
		{
			keyFound = true;

			EnumMember enummember;

			string elementName;
			string elementType;
			string structElementVal;

			bool lineend = false;
			int length = int(line.size());

			for (int j = 0; j < length ; j++)
			{
				int temp = line.at(j);
				//int templie = line.at(j);
				switch (temp)
				{
				case 32:  // For ' '
				case 9: //for Invalid space
					{
						if (structInuse == true && tempData.size() > 0)
						{
							if ( elementfound == true )
							{	
								for (int k = 0 ; k < 23 ; k++ )
								{
									// got the type, will check with all possible data types.Else it will be member name.
									int loc = int(line.find_first_of(keywords[k]));
									string key(keywords[k]);
									if (tempData == key )
									{											
										elementType.append(keywords[k]);
										tempData.clear();
										break;
									}										
								}
							}
						}
						if (macroInuse == true && macro.macroName.size() <=0 && tempData.size() > 0) // can be macro name
						{
							macro.macroName = tempData;
							macro.lineNo = lineNo;
							tempData.clear();
						}
					}
					break;
				case 59://For ';'
					{						
						if ( structInuse == true && elementfound == true && tempData.size() > 0)
						{
							elementName.append(tempData);
							elementMember.elementName = elementName;
							elementMember.elementType = elementType;
							elementMember.lineNo = lineNo;
							if (valueFound == true)
							{
								elementMember.elementValue= structElementVal; 
								valueFound = false;
							}
							lStruct.members.push_back (elementMember);
							tempData.clear();
						}

						if(macroInuse ==false)
							break;	

					}
					
				case 44://For ','
					{	
						if(macroInuse ==false)
						{
							if ( enumInuse == true && elementfound == true && tempData.size() > 0)
							{
								if (valueFound == true)
								{
									enummember.enumVal = elementVal.c_str();
									char *p;
									// convert enumVal to long , so that can be incremented if required.
									currentEnumVal = strtol(enummember.enumVal.c_str(),&p,0);
									valueFound = false;
								}
								else
								{
									currentEnumVal += 1;
									string p;
									// convert long to string
									enummember.enumVal = ltoa(currentEnumVal,p,0);
								}
								enummember.enumMemName.append(tempData);
								enummember.lineNo = lineNo;

								lEnum.enums.push_back(enummember);

								tempData.clear();
								elementVal.clear();
							}
							break;
						}
					}
					
				case 61: //For '='
					{
						if(macroInuse == false)
						{
							valueFound = true;
							break;
						}
					}
					//break;

				case 123:  //For '{'
					{
						if(macroInuse ==false)
						{
							if(tempData.size() > 0 )
							{
								if(structInuse == true)
								{
									lStruct.structName.assign(tempData);
									lStruct.lineNo = lineNo;
								}
								else
								{
									lEnum.enumName.assign(tempData);
									lEnum.lineNo = lineNo;
								}
							}
							tempData.clear();
							elementfound = true;

							break;
						}
					}
				case 125: //For '}'
					{
						if(macroInuse ==false)
						{
							if(structInuse == true)
							{
								structInuse = false;	
								if(tempData.size() > 0) // if some inline macro is present
								{
									elementMember.elementName = tempData ;
									elementMember.elementType = "";
									elementMember.lineNo = lineNo;
									lStruct.members.push_back(elementMember);
								}
								resource.structList.push_back(lStruct);
							}
							else if ( enumInuse == true )
							{
								if (elementfound == true && tempData.size() > 0)
								{
									if (valueFound == true)
									{
										enummember.enumVal = elementVal.c_str(); 
										char *p;
										// convert enumVal to long , so that can be incremented if required.
										currentEnumVal = strtol(enummember.enumVal.c_str(),&p,0);
										valueFound = false;
									}
									else
									{
										currentEnumVal += 1;
										string p;
										// convert long to string
										enummember.enumVal = ltoa(currentEnumVal,p,0);
									}

									enummember.lineNo = lineNo;

									enummember.enumMemName.append(tempData);

									lEnum.enums.push_back(enummember);							
								}
								currentEnumVal = -1;
								elementVal.clear();
								enumInuse = false;
								resource.enumList.push_back(lEnum);
							}
							keyFound = false;
							elementfound = false;
							tempData.clear();

							break;
						}
					}
				default:
					{
						// followings are to ignore any comment line in between.
						if( j+1 <length)
						{
							if (line.at(j) == '/' )
							{
								if(line.at(j+1) == '*')
									ignoreLine = true;

								else if ( line.at(j+1) == '/')
								{
									lineend = true;
									break;
								}
							}
							if(ignoreLine == true)
							{
								if (j+1 <length && line.at(j) == '*' && line.at(j+1) == '/')
								{
									ignoreLine = false;
									j = j+2;
									continue;

								}
							}
						} // comment line checks ended

						if(ignoreLine == false && j<length)
						{
							// newline character's int value is 92, for macros, newline char can be present mainly.
							if ((int) line.at(j)== 92 && macroInuse == true && tempData.size() > 0) // can be macro name
							{
								newLinecharFound = true; // new line character found
								if ( macro.macroName.size() <=0)
								{
									macro.macroName = tempData;	
									macro.lineNo = lineNo;
								}
								else
								{
									macro.macroVal.append(tempData);
								}
								tempData.clear();
								
							}
							// Check macro definition ended after newlines
							if( (int) line.at(j)!= 92 && j+1 >= length && macroInuse == true &&  newLinecharFound == true )
							{
								newLinecharFound =false;
								//macroInuse = false;
								//macro.macroVal.append(tempData);
								//tempData.clear();
								break;
							}
							if (enumInuse == true || macroInuse == true || structInuse == true)
							{
								if(valueFound == true)
								{
									if ( structInuse == true )
										structElementVal.push_back(line.at(j));
									else
										elementVal.push_back(line.at(j));									
								}
								else
								{
									if( (int)line.at(j) != 92)// ignore newline character
									tempData.push_back(line.at(j));
								}
							}
						}

						
					}
					break;
				}
				if (lineend == true)
					break;
			}// line end

			// Macro structure ended, fill the values.
			if( macroInuse == true && newLinecharFound == false && tempData.size() > 0 )
			{
				if(tempData.size()> 0 )
				{
					macro.macroVal.append(tempData);
					tempData.clear();
				}
				keyFound = false;
				macroInuse = false ;
				resource.macroList.push_back(macro);
			}
		}

	}// End of all lines in resource file

}

void Analyser::compareResources(ResourceContent &baseResource, ResourceContent &curResource, ReportGenerator& report)
{
	int base_struct_no = (int)baseResource.structList.size();
	int cur_struct_no = (int)curResource.structList.size();

	int base_enum_no = (int)baseResource.enumList.size();
	int cur_enum_no = (int)curResource.enumList.size();

	int base_macro_no = (int)baseResource.macroList.size();
	int cur_macro_no = (int)curResource.macroList.size();

	StructElement baseStruct;
	StructElement curStruct;

	EnumElement baseEnum;
	EnumElement curEnum;

	MacroElement baseMacro;
	MacroElement curMacro;

	for(int i = 0; i < base_struct_no; i++ )
	{
		baseStruct =  baseResource.structList.at(i);
		bool structFound = false;
		for(int j = 0; j < cur_struct_no; j++ )
		{
			curStruct = curResource.structList.at(j);
			if(baseStruct.structName == curStruct.structName )
			{
				int baseMemNo = (int)baseStruct.members.size();
				int curMemNo = (int)curStruct.members.size();

				structFound = true;

				for( int bInner = 0; bInner < baseMemNo; bInner++ )
				{
					bool memFound = false;
					for ( int cInner = 0; cInner < curMemNo; cInner++ )
					{
						if ( baseStruct.members.at(bInner).elementName == curStruct.members.at(cInner).elementName )
						{
							memFound = true;
							if(baseStruct.members.at(bInner).elementType == curStruct.members.at(cInner).elementType)
							{
								if(baseStruct.members.at(bInner).elementValue.size() > 0
									&& (baseStruct.members.at(bInner).elementValue != curStruct.members.at(cInner).elementValue) )
								{
									//add issue	member value mismatch		
									string bVal = baseStruct.structName + "::" + baseStruct.members.at(bInner).elementName;
									string cVal = curStruct.members.at(cInner).elementValue;
									int lineNo = curStruct.members.at(cInner).lineNo;
									report.addIssue(baseResource.RHFileName, bVal, EIssueIdentityStructMember, EIssueTypeChangeInInitialisation, 
										ESeverityNULL, ESeveritySCBreak, cVal, lineNo,"",curResource.RHFileName,"");
								} 
							}
							else
							{
								// add issue tyechange
								string bType = baseStruct.structName + "::" + baseStruct.members.at(bInner).elementName;
								string cType = curStruct.members.at(cInner).elementType;
								int lineNo = curStruct.members.at(cInner).lineNo;
								report.addIssue(baseResource.RHFileName, bType, EIssueIdentityStructMember, EIssueTypeChangeInType, 
									ESeverityNULL, ESeveritySCBreak, cType, lineNo,"",curResource.RHFileName,"");
							}

							break;

						}// memeber name matched
					}// loop thru all curr struct member

					if( memFound == false)
					{
						// Add Issue Member not found  // baseStruct.members.at(bInner)
						string bMember = baseStruct.structName + "::" + baseStruct.members.at(bInner).elementName;
						int lineNo = curStruct.lineNo;
						report.addIssue(baseResource.RHFileName, bMember, EIssueIdentityStructMember, EIssueTypeRemoval, 
							ESeverityNULL,ESeveritySCBreak, "", lineNo,"",curResource.RHFileName,"");
					}
				}// loop base struct member

			}// struct name match
		}// loop curr structs

		if( structFound == false )
		{ 
			//Add issue struct not found
			report.addIssue(baseResource.RHFileName, baseStruct.structName, EIssueIdentityStruct, EIssueTypeRemoval, 
				ESeverityNULL, ESeveritySCBreak, "", 0,"",curResource.RHFileName,"");
		}
	}//loop base structs

	// --------------Enum Comparison ------------
	vector<EnumMember>baseEnumNameEmptyMemberList;
	vector<EnumMember>curEnumNameEmptyMemberList;
	vector<EnumElement> bEnumList;
	vector<EnumElement> cEnumList;

    for( int b = 0; b < base_enum_no; b++)
	{
		baseEnum = baseResource.enumList.at(b);
		
		if(baseEnum.enumName.size()<=0)
		{
			for(int k = 0; k < (int)baseEnum.enums.size(); k++)
			{
				baseEnumNameEmptyMemberList.push_back(baseEnum.enums.at(k));
			}
		}
		else
		{
			bEnumList.push_back(baseEnum);
		}
	}

	for( int c = 0; c < cur_enum_no; c++)
	{
		curEnum = curResource.enumList.at(c);
		
		if(curEnum.enumName.size()<=0)
		{
			for(int k = 0; k < (int)curEnum.enums.size(); k++)
			{
				curEnumNameEmptyMemberList.push_back(curEnum.enums.at(k));
			}
		}
		else
		{
			cEnumList.push_back(curEnum);
		}
	}

	// Compare and report issue for enum list with name
	for( int l = 0; l < (int) bEnumList.size(); l++)
	{
		baseEnum = bEnumList.at(l);
		bool enumFound = false;

		for( int m = 0; m < (int)cEnumList.size(); m++ )
		{
			curEnum = cEnumList.at(m);
			if ( baseEnum.enumName == curEnum.enumName )
			{
				int bMemNo = (int)baseEnum.enums.size();
				int cMemNo = (int)curEnum.enums.size();

				enumFound = true;

				for ( int outer = 0; outer < bMemNo; outer++ )
				{
					bool enumMemFound = false;
					for( int inner = 0; inner < cMemNo; inner++ )
					{
						if(baseEnum.enums.at(outer).enumMemName == curEnum.enums.at(inner).enumMemName )
						{ 
							enumMemFound = true;
							// member name found
							if(baseEnum.enums.at(outer).enumVal.size() > 0 )
							{
								if (baseEnum.enums.at(outer).enumVal != curEnum.enums.at(inner).enumVal )
								{
									//add issue Member value changed
									string baseEnumVal = baseEnum.enumName +"::" + baseEnum.enums.at(outer).enumMemName;
									string curEnumVal = curEnum.enums.at(inner).enumVal;
									int lineNo = curEnum.enums.at(inner).lineNo;

									report.addIssue(baseResource.RHFileName, baseEnumVal, EIssueIdentityEnumerationValue, EIssueTypeChangeInInitialisation, 
										ESeverityNULL, ESeveritySCBreak, curEnumVal, lineNo,"",curResource.RHFileName,"");
								}
							}
							break;
						}
					} // loop cur mems

					if ( enumMemFound == false)
					{ 
						// Add Enum Member Missing
						string bMemName = baseEnum.enumName +"::" + baseEnum.enums.at(outer).enumMemName;
						int lineNo = curEnum.lineNo;
						report.addIssue(baseResource.RHFileName, bMemName, EIssueIdentityEnumerationValue, EIssueTypeRemoval, 
							ESeverityNULL, ESeveritySCBreak, "", lineNo,"",curResource.RHFileName,"");

					}
				}// loop base mems

				break;
			}// enum name matched
		}// loop cur enums

		if (enumFound == false )
		{
			// Enum List missing
			string bEnum = baseEnum.enumName;
			string cEnum = curEnum.enumName;
			report.addIssue(baseResource.RHFileName, bEnum, EIssueIdentityEnumerationValue, EIssueTypeRemoval, 
				ESeverityNULL, ESeveritySCBreak, cEnum, 0,"",curResource.RHFileName,"");
		}
	}//base enums

	// Now check for enum list with no enum name, in this case check member name and value
	if(baseEnumNameEmptyMemberList.size() > 0)
	{
		EnumMember bEnumMem;
		for(unsigned long i = 0; i < (unsigned long)baseEnumNameEmptyMemberList.size(); i++)
		{
			bEnumMem = baseEnumNameEmptyMemberList.at(i);
			EnumMember cEnumMem;
			bool enumMemFound = false;
			for(unsigned long j = 0; j <(unsigned long) curEnumNameEmptyMemberList.size(); j++ )
			{
				cEnumMem = curEnumNameEmptyMemberList.at(j);
				if(bEnumMem.enumMemName == cEnumMem.enumMemName)
				{
					enumMemFound = true;
					if(bEnumMem.enumVal != cEnumMem.enumVal )
					{
						//add issue enum value changed 
						string baseEnumVal = "::" + bEnumMem.enumMemName;
						string curEnumVal = cEnumMem.enumMemName;
						int lineNo = cEnumMem.lineNo;

						report.addIssue(baseResource.RHFileName, baseEnumVal, EIssueIdentityEnumerationValue, EIssueTypeChangeInInitialisation, 
							ESeverityNULL, ESeveritySCBreak, curEnumVal, lineNo,"",curResource.RHFileName,"");
					}
					break;
				}
			}
			if(enumMemFound == false)
			{
				// add issue enum mem mising
				string bMemName = "::" + bEnumMem.enumMemName;
				report.addIssue(baseResource.RHFileName, bMemName, EIssueIdentityEnumerationValue, EIssueTypeRemoval, 
					ESeverityNULL, ESeveritySCBreak, "", 0,"",curResource.RHFileName,"");
			}
		}
	}


	// --------------------- Macro Comparision --------------

	for (int p = 0; p < base_macro_no; p++ )
	{
		bool macroFound = false;
		baseMacro = baseResource.macroList.at(p);
		for (int q = 0; q < cur_macro_no; q++ )
		{
			curMacro = curResource.macroList.at(q);
			if(baseMacro.macroName == curMacro.macroName )
			{ // check Macro value
				macroFound = true;
				if(baseMacro.macroVal != curMacro.macroVal )
				{
					//add issue macro value mismatch
					report.addIssue(baseResource.RHFileName, baseMacro.macroName, EIssueIdentityMacro, EIssueTypeChange, 
						ESeverityNULL, ESeveritySCBreak, curMacro.macroVal, curMacro.lineNo,"",curResource.RHFileName,"");
				}
				break; // macro name matched
			}

		}

		if (macroFound == false )
		{
			// add issue macro not found
			report.addIssue(baseResource.RHFileName, baseMacro.macroName, EIssueIdentityMacro, EIssueTypeRemoval, 
				ESeverityNULL, ESeveritySCBreak, "", 0,"",curResource.RHFileName,"");
		}
	}



}

