/***************************************************************************
 *   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 "fileparser.h"

#include <stdexcept>
#include "lib/lib_logging.h"

/**
 * prépare le parser pour scanner un fichier dont on passe les infos actuelles en paramètre
 * @param info informations actuellement connues sur le fichier (surtout le nom, l'id et le type)
 * @return true si le parser peut gérer le fichier demandé et que le parser n'est pas actuellement en fonction,
 *          false dans le cas contraire
 * @see FileParser::prepareParserImpl()
 */
bool FileParser::prepareParser(const FileInfo * info)
{
    bool bRetVal = false;
    wxCriticalSectionLocker lock(this->csState);
    try
    {
        if(this->state == Prepared || this->state == Finished || this->state == Unknown)
            bRetVal = this->prepareParserImpl(info);
    }
    catch( std::exception &e )
    {
        LOG_MESSAGE(e.what(),logging::_ERROR_);
        bRetVal = false;
    }
    catch( ... )
    {
        LOG_MESSAGE("Exception occured while preparing parser",logging::_ERROR_);
        bRetVal = false;
    }
    this->state = (bRetVal) ? Prepared : Unknown;
    return bRetVal;
}

/**
 * démarre le parsing si le parser est en état Prepared. Rend la main lorsque le parsing est terminé.
 * @return false si le parser échoue ou si il n'était pas en état Prepared
 * @see FileParser::parse()
 */
bool FileParser::startParsing()
{
    wxCriticalSectionLocker lock(this->csState);
    try
    {
        if(this->state != Prepared)
            return false;

        this->state = Running;
        wxCriticalSectionLocker parsingLock(this->csParsing); // on indique que le parsing est en cours
        this->csState.Leave();
        bool bRetVal = this->parse(); // on effectue le parsing proprement dit
        this->csState.Enter();
        if(!this->checkStopRequested()) // on détermine le nouvel état en fonction du type d'arret
        {
            state = bRetVal ? Finished : Unknown;
        }
        else
            state = Unknown;
        return bRetVal;
    }
    catch( std::exception &e )
    {
        LOG_MESSAGE(e.what(),logging::_ERROR_);
        return false;
    }
    catch( ... )
    {
        LOG_MESSAGE("Exception occured while parsing",logging::_ERROR_);
        return false;
    }
}

/**
 * demande au parser de s'arreter. Rend la main lorsque le parser s'est arreté
 * @see FileParser::checkStopRequested()
 */
void FileParser::stopParsing()
{
    try
    {
        wxCriticalSectionLocker lock(this->csState);

        if(this->state != Running)
            return; // le parser n'est pas en route : on quitte direct

        this->bStopRequested = true; // on installe la demande d'arret
        this->csState.Leave();

        wxCriticalSectionLocker parsingLock(this->csParsing); // on attend la fin du parsing
    }
    catch( std::exception &e )
    {
        LOG_MESSAGE(e.what(),logging::_ERROR_);
    }
    catch( ... )
    {
        LOG_MESSAGE("Exception occured while stoping parser",logging::_ERROR_);
    }
}

/** renvoie l'état actuel du parser */
FileParser::ParserState FileParser::getState()
{
    try
    {
        wxCriticalSectionLocker lock(this->csState);
        return this->state;
    }
    catch( std::exception &e )
    {
        LOG_MESSAGE(e.what(),logging::_ERROR_);
        return Unknown;
    }
    catch( ... )
    {
        LOG_MESSAGE("Exception occured while getting parser state",logging::_ERROR_);
        return Unknown;
    }
}

/**
 * récupère les infos collectées lors du dernier parsing (uniquement en état Finished)
 * @return NULL si il n'y a pas eu de parsing depuis la création de l'instance ou la dernière préparation
 * @see FileParser::getParsedInfoImpl()
 */
FileInfo * FileParser::getParsedInfo()
{
    try
    {
        wxCriticalSectionLocker lock(this->csState);
        if(this->state != Finished)
            return NULL;
        return this->getParsedInfoImpl();
    }
    catch( std::exception &e )
    {
        LOG_MESSAGE(e.what(),logging::_ERROR_);
        return NULL;
    }
    catch( ... )
    {
        LOG_MESSAGE("Exception occured while getting parsed infos",logging::_ERROR_);
        return NULL;
    }
}

/**
 * vérifie si un arret définitif du parsing a été demandé.
 * A utiliser régulièrement dans l'implémentation de la méthode parse()
 * @return true si un arret a été demandé
 */
bool FileParser::checkStopRequested()
{
    if((!wxThread::IsMain()) && wxThread::This()->TestDestroy())
    {
        this->bStopRequested = true;
    }
    return this->bStopRequested;
}

/**
 * vérifie si une pause est demandée.
 * Si c'est le cas, immobilise le thread jusqu'au prochain appel à continueParsing.
 * A utiliser régulièrement dans l'implémentation de la méthode parse()
 * @return true si une pause a été faite
 */
bool FileParser::checkPauseRequested()
{
    if((!wxThread::IsMain()) && wxThread::This()->TestDestroy())
    {
        this->bStopRequested = true;
    }
    return false;
}
