/***************************************************************************
 *   Copyright (C) 2005 by Thierry CHARLES   *
 *   thierry@les-charles.net   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "parsingthread.h"

#include <wx/datetime.h>

#include "lib/lib_string.h"
#include "lib/lib_logging.h"

#include "fileparser.h"
#include "fileinfo.h"
#include "parserres.h"

#include "xpe_components/mainwindow.h"

/** scanne un fichier (sans verifier si cela est nécessaire) */
bool ParsingThread::scanFile(FileInfo * fileInfo, FileParserRes * filesRes)
{
    FileParser * parser = fileInfo->getParser();
    bool bScanResult = false;

    try
    {
        long iParseTime = wxDateTime::GetTimeNow();
        bScanResult = parser->prepareParser( fileInfo );
        bScanResult = bScanResult && parser->startParsing();
        fileInfo = (bScanResult) ? parser->getParsedInfo() : NULL;
        bScanResult = bScanResult && fileInfo != NULL;

        if(bScanResult)
        {
            fileInfo->setLastParseTime( iParseTime );
            filesRes->updateFileInfo( fileInfo );
        }
    }
    catch( ... )
    {
        LOG_MESSAGE("Erreur inattendue.",logging::_ERROR_);
    }
    delete parser;
    return bScanResult;
}

/** vérifie si un fichier a besoin d'etre scanné */
bool ParsingThread::requireScan(FileInfo * fileInfo)
{
    return fileInfo->getLastParseTime() <= fileInfo->getLastModificationTime();
}

ParsingThread::ExitCode ParsingThread::Entry()
{
    while(!this->TestDestroy())
    {
        // on récupère l'éditeur courrant
        int iCurrentEditorId = this->filesRes->getCurrentEditorId();

        // on scanne le fichier en cours d'édition et ses dépendances
        FileInfo * info = this->filesRes->getFileInfoLock( iCurrentEditorId );
        if(info) // si aucune info n'est retournée, c'est qu'il ne faut pas scanner ce fichier
        {
            if(requireScan(info)) // scan du fichier
                scanFile(info,this->filesRes);

            // récup des dépendances directes
            FileContext context(libfile::dirname( info->getFileName() ));
            TStringSet parsedIncludes;
            TStringSet includesToParse = info->getDependancies( context );
            includesToParse.erase(info->getFileName());
            while(includesToParse.size() && (!this->TestDestroy()))
            {
                wxString sDep = *includesToParse.begin();
                parsedIncludes.insert(sDep);
                includesToParse.erase(sDep);

                FileInfo * incInfo = this->filesRes->getFileInfoLock( sDep );
                if(!incInfo)
                    continue;

                if(requireScan(incInfo)) // scan de l'include
                    scanFile(incInfo,this->filesRes);

                // récup des dépendances de l'include
                TStringSet includes = incInfo->getDependancies( context );
                TStringSet::iterator itInc = includes.begin();
                while(itInc != includes.end())
                {
                    if( ((*itInc) != info->getFileName()) && (parsedIncludes.find(*itInc) == parsedIncludes.end()) )
                        includesToParse.insert(*itInc);
                    itInc++;
                }

                this->filesRes->releaseLock( incInfo );
            }

            this->filesRes->releaseLock( info );
        }
        // on fait une pause de 30 secondes tant qu'on a pas changé d'éditeur
        int iSleeps = 0;
        while(iSleeps < 60 && (!this->TestDestroy()))
        {
            iSleeps++;
            int iNewEditorId = this->filesRes->getCurrentEditorId();
            if(iNewEditorId != iCurrentEditorId)
                break;
            this->Sleep(500);
        }
    }

    return 0;
}
