<commit_before>/*
 *  ProjectGenerator: Tool to generate module/project files
 *  Copyright (C) 2002 - 2011.  Dinand Vanvelzen
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

/*-------------------------------------------------------------------------//
//                                                                         //
//      INCLUDES                                                           //
//                                                                         //
//-------------------------------------------------------------------------*/

#include <stdio.h>

#ifndef GUCEF_CORE_LOGGING_H
#include "gucefCORE_Logging.h"
#define GUCEF_CORE_LOGGING_H
#endif /* GUCEF_CORE_LOGGING_H ? */

#ifndef GUCEF_CORE_DVCPPOSWRAP_H
#include "DVCPPOSWRAP.h"
#define GUCEF_CORE_DVCPPOSWRAP_H
#endif /* GUCEF_CORE_DVCPPOSWRAP_H ? */

#ifndef GUCEF_CORE_CFILEACCESS_H
#include "CFileAccess.h"
#define GUCEF_CORE_CFILEACCESS_H
#endif /* GUCEF_CORE_CFILEACCESS_H ? */

#ifndef GUCEF_CORE_CONFIGSTORE_H
#include "CConfigStore.h"
#define GUCEF_CORE_CONFIGSTORE_H
#endif /* GUCEF_CORE_CONFIGSTORE_H ? */

#ifndef GUCEF_PROJECTGEN_DATATYPES_H
#include "gucefProjectGen_DataTypes.h"
#define GUCEF_PROJECTGEN_DATATYPES_H
#endif /* GUCEF_PROJECTGEN_DATATYPES_H ? */

#ifndef GUCEF_PROJECTGEN_CIPROJECTGENERATOR_H
#include "gucefProjectGen_CIProjectGenerator.h"
#define GUCEF_PROJECTGEN_CIPROJECTGENERATOR_H
#endif /* GUCEF_PROJECTGEN_CIPROJECTGENERATOR_H ? */

#ifndef GUCEF_PROJECTGEN_CIPROJECTINFOGATHERER_H
#include "gucefProjectGen_CIProjectInfoGatherer.h"
#define GUCEF_PROJECTGEN_CIPROJECTINFOGATHERER_H
#endif /* GUCEF_PROJECTGEN_CIPROJECTINFOGATHERER_H ? */

#ifndef GUCEF_PROJECTGEN_CDIRCRAWLINGPROJECTINFOGATHERER_H
#include "gucefProjectGen_CDirCrawlingProjectInfoGatherer.h"
#define GUCEF_PROJECTGEN_CDIRCRAWLINGPROJECTINFOGATHERER_H
#endif /* GUCEF_PROJECTGEN_CDIRCRAWLINGPROJECTINFOGATHERER_H ? */

#ifndef GUCEF_PROJECTGEN_CXMLPROJECTGENERATOR_H
#include "gucefProjectGen_CXmlProjectGenerator.h"
#define GUCEF_PROJECTGEN_CXMLPROJECTGENERATOR_H
#endif /* GUCEF_PROJECTGEN_CXMLPROJECTGENERATOR_H ? */

#ifndef GUCEF_PROJECTGEN_CCMAKEPROJECTGENERATOR_H
#include "gucefProjectGen_CCMakeProjectGenerator.h"
#define GUCEF_PROJECTGEN_CCMAKEPROJECTGENERATOR_H
#endif /* GUCEF_PROJECTGEN_CCMAKEPROJECTGENERATOR_H ? */

#ifndef GUCEF_PROJECTGEN_CANDROIDMAKEFILEGENERATOR_H
#include "gucefProjectGen_CAndroidMakefileGenerator.h"
#define GUCEF_PROJECTGEN_CANDROIDMAKEFILEGENERATOR_H
#endif /* GUCEF_PROJECTGEN_CANDROIDMAKEFILEGENERATOR_H ? */

#ifndef GUCEF_PROJECTGEN_CPREMAKE4PROJECTGENERATOR_H
#include "gucefProjectGen_CPremake4ProjectGenerator.h"
#define GUCEF_PROJECTGEN_CPREMAKE4PROJECTGENERATOR_H
#endif /* GUCEF_PROJECTGEN_CPREMAKE4PROJECTGENERATOR_H ? */

#ifndef GUCEF_PROJECTGEN_CPROJECTGENGLOBAL_H
#include "gucefProjectGen_CProjectGenGlobal.h"
#define GUCEF_PROJECTGEN_CPROJECTGENGLOBAL_H
#endif /* GUCEF_PROJECTGEN_CPROJECTGENGLOBAL_H ? */

#ifndef GUCEF_PROJECTGEN_CPROJECTPREPROCESSORMANAGER_H
#include "gucefProjectGen_CProjectPreprocessorManager.h"
#define GUCEF_PROJECTGEN_CPROJECTPREPROCESSORMANAGER_H
#endif /* GUCEF_PROJECTGEN_CPROJECTPREPROCESSORMANAGER_H ? */

/*-------------------------------------------------------------------------//
//                                                                         //
//      NAMESPACE                                                          //
//                                                                         //
//-------------------------------------------------------------------------*/

using namespace GUCEF;
using namespace GUCEF::PROJECTGEN;

/*-------------------------------------------------------------------------//
//                                                                         //
//      UTILITIES                                                          //
//                                                                         //
//-------------------------------------------------------------------------*/

bool
LoadConfig( CORE::CValueList& keyValueList )
{GUCEF_TRACE;

    #ifdef GUCEF_DEBUG_MODE
    const CORE::CString configFile = "ProjectGenerator_d.ini";
    #else
    const CORE::CString configFile = "ProjectGenerator.ini";
    #endif

    CORE::CString configFilePath = CORE::CombinePath( "$CURWORKDIR$", configFile );
    configFilePath = CORE::RelativePath( configFilePath );

    if ( !CORE::FileExists( configFilePath ) )
    {
        configFilePath = CORE::CombinePath( "$MODULEDIR$", configFile );
        configFilePath = CORE::RelativePath( configFilePath );

        if ( !FileExists( configFilePath ) )
        {
            return false;
        }
    }
    GUCEF_LOG( CORE::LOGLEVEL_NORMAL, "Located config file @ " + configFilePath );

    keyValueList.SetConfigNamespace( "Main/AppArgs" );
    keyValueList.SetUseGlobalConfig( true );
    keyValueList.SetAllowDuplicates( false );
    keyValueList.SetAllowMultipleValues( true );

    CORE::CConfigStore& configStore = CORE::CCoreGlobal::Instance()->GetConfigStore();
    configStore.SetConfigFile( configFilePath );
    return configStore.LoadConfig();
}

/*-------------------------------------------------------------------------*/

void
ParseParams( const int argc                 ,
             char* argv[]                   ,
             CORE::CValueList& keyValueList )
{GUCEF_TRACE;

    GUCEF::CORE::CString argString;
    if ( argc > 0 )
    {
        argString = *argv;

        // Combine the argument strings back into a single string because we don't want to use
        // a space as the seperator
        for ( int i=1; i<argc; ++i )
        {
            argString += ' ' + CORE::CString( argv[ i ] );
        }

        // Parse the param list based on the ' symbol
        GUCEF_LOG( CORE::LOGLEVEL_NORMAL, "Application parameters: " + argString );
        keyValueList.SetMultiple( argString, '*' );
    }
}

/*---------------------------------------------------------------------------*/

/*
 *      Application entry point
 */
GUCEF_OSMAIN_BEGIN
{GUCEF_TRACE;

    GUCEF_LOG( CORE::LOGLEVEL_NORMAL, "This tool was compiled on: " __DATE__ " @ " __TIME__ );

    CORE::CCoreGlobal::Instance();
    PROJECTGEN::CProjectGenGlobal::Instance();

    // Load settings from a config file (if any) and then override with params (if any)
    CORE::CValueList keyValueList;
    LoadConfig( keyValueList );
    ParseParams( argc, argv, keyValueList );

    CORE::Int32 minLogLevel = CORE::LOGLEVEL_BELOW_NORMAL;
    CORE::CString valueStr = keyValueList.GetValueAlways( "MinimalLogLevel" );
    if ( !valueStr.IsNULLOrEmpty() )
    {
        minLogLevel = CORE::StringToInt32( valueStr );
        CORE::CCoreGlobal::Instance()->GetLogManager().SetMinLogLevel( minLogLevel );
    }

    // Support overriding environment variables from a file.
    // This can be important for build environments which rely on such variables
    CORE::CString envOverrideFile = keyValueList.GetValueAlways( "envOverridesFile" );
    if ( !envOverrideFile.IsNULLOrEmpty() )
    {
        CORE::CString fileContent;
        if ( CORE::LoadTextFileAsString( envOverrideFile, fileContent, true, "\n" ) )
        {
            CORE::SetEnvOverrides( fileContent );
        }
    }

    CORE::CString outputDir = CORE::RelativePath( keyValueList.GetValueAlways( "outputDir" ) );
    if ( outputDir.IsNULLOrEmpty() )
    {
        outputDir = CORE::RelativePath( "$CURWORKDIR$" );
    }
    CORE::CreateDirs( outputDir );

    CORE::CString logFilename = CORE::CombinePath( outputDir, "ProjectGenerator_Log.txt" );

    keyValueList.Set( "logfile", logFilename );

    CORE::CFileAccess logFileAccess( logFilename, "w" );
    CORE::CStdLogger logger( logFileAccess );
    CORE::CCoreGlobal::Instance()->GetLogManager().AddLogger( &logger );

    CORE::CPlatformNativeConsoleLogger console;
    CORE::CCoreGlobal::Instance()->GetLogManager().AddLogger( console.GetLogger() );

    CORE::CCoreGlobal::Instance()->GetLogManager().FlushBootstrapLogEntriesToLogs();
    GUCEF_LOG( CORE::LOGLEVEL_NORMAL, "Flushed to log @ " + logFilename );

    TStringVector rootDirs;
    try
    {
        rootDirs = keyValueList.GetValueVector( "rootDir" );
        GUCEF_LOG( CORE::LOGLEVEL_NORMAL, "Number of rootDir arguments passed from command line: " + CORE::UInt32ToString( rootDirs.size() ) );
    }
    catch ( CORE::CValueList::EUnknownKey& )
    {
        rootDirs.push_back( CORE::RelativePath( "$CURWORKDIR$" ) );
        GUCEF_LOG( CORE::LOGLEVEL_NORMAL, "Using current working directory since no rootDir arguments where passed from the command line" );
    }

    bool addToolCompileTimeToOutput = CORE::StringToBool( keyValueList.GetValueAlways( "addToolCompileTimeToOutput" ) );

    // Get the generators to use
    TStringVector generatorList = keyValueList.GetValueAlways( "generators" ).ParseElements( ';', false );
    if ( generatorList.size() == 0  )
    {
        // No specific generators where specified, defaulting...
        generatorList.push_back( "xml" );
    }

    // Set any global dir excludes that where passed as cmd parameters
    TProjectInfo projectInfo;
    projectInfo.globalDirExcludeList = keyValueList.GetValueAlways( "dirsToIgnore" ).ParseElements( ';', false );
    GUCEF_LOG( CORE::LOGLEVEL_NORMAL, "There are " + CORE::UInt32ToString( projectInfo.globalDirExcludeList.size() ) + " dirs in the global dir ignore list" );

    projectInfo.projectName = keyValueList.GetValueAlways( "projectName" );

    bool useProjectInfoCache = CORE::StringToBool( keyValueList.GetValueAlways( "useProjectInfoCache" ) );
    bool projectInfoLoadedFromCache = false;
    if ( useProjectInfoCache )
    {
        CORE::CString cachedInfoPath = CORE::CombinePath( CORE::RelativePath( outputDir ), "Project.xml" );
        projectInfoLoadedFromCache = DeserializeProjectInfo( projectInfo, cachedInfoPath );
    }

    if ( !projectInfoLoadedFromCache )
    {
        // Use an info gatherer to get all the project information for us
        CDirCrawlingProjectInfoGatherer infoGatherer;
        infoGatherer.GatherInfo( rootDirs    ,
                                 projectInfo );
    }

    // Before we hand the data we collected and generated to the generator(s) for the desired output we will check
    // for preprocessors which can be executed before any output generator. These apply changes to the project data
    // that will apply to all output generators
    const CProjectPreprocessorManager::TProjectPreprocessorsList& projectPreProcessors = CProjectGenGlobal::Instance()->GetProjectPreprocessorManager().GetProjectPreprocessors();
    CProjectPreprocessorManager::TProjectPreprocessorsList::const_iterator n = projectPreProcessors.begin();
    while ( n != projectPreProcessors.end() )
    {
        GUCEF_LOG( CORE::LOGLEVEL_NORMAL, "Invoking project preprocessor" );
        (*n)->ProccessProjects( projectInfo  ,
                                outputDir    ,
                                keyValueList );
        ++n;
    }

    // Now we output the project info using all generators specified
    TStringVector::iterator i = generatorList.begin();
    while ( i != generatorList.end() )
    {
        if ( (*i).Lowercase() == "xml" )
        {
            CXmlProjectGenerator xmlGenerator;
            xmlGenerator.GenerateProject( projectInfo                ,
                                          outputDir                  ,
                                          addToolCompileTimeToOutput ,
                                          keyValueList               );
        }
        else
        if ( (*i).Lowercase() == "androidmake" )
        {
            CAndroidMakefileGenerator androidMakefileGenerator;
            androidMakefileGenerator.GenerateProject( projectInfo                ,
                                                      outputDir                  ,
                                                      addToolCompileTimeToOutput ,
                                                      keyValueList               );
        }
        else
        if ( (*i).Lowercase() == "cmake" )
        {
            CCMakeProjectGenerator cmakeGenerator;
            cmakeGenerator.GenerateProject( projectInfo                ,
                                            outputDir                  ,
                                            addToolCompileTimeToOutput ,
                                            keyValueList               );
        }
        else
        if ( (*i).Lowercase() == "premake4" )
        {
            CPremake4ProjectGenerator premake4Generator;
            premake4Generator.GenerateProject( projectInfo                ,
                                               outputDir                  ,
                                               addToolCompileTimeToOutput ,
                                               keyValueList               );
        }
        ++i;
    }

    GUCEF_LOG( CORE::LOGLEVEL_NORMAL, "Wrote log file to: " + logFilename );

    CORE::CCoreGlobal::Instance()->GetLogManager().ClearLoggers();

    return 0;
}
GUCEF_OSMAIN_END

/*-------------------------------------------------------------------------//
//                                                                         //
//      Info & Changes                                                     //
//                                                                         //
//-------------------------------------------------------------------------//

- 27-11-2004 :
        - Dinand: Initial implementation

---------------------------------------------------------------------------*/
<commit_msg>adding some logging around locating the ProjectGenerator config so we know from the log where is was looking for the config<commit_after>/*
 *  ProjectGenerator: Tool to generate module/project files
 *  Copyright (C) 2002 - 2011.  Dinand Vanvelzen
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

/*-------------------------------------------------------------------------//
//                                                                         //
//      INCLUDES                                                           //
//                                                                         //
//-------------------------------------------------------------------------*/

#include <stdio.h>

#ifndef GUCEF_CORE_LOGGING_H
#include "gucefCORE_Logging.h"
#define GUCEF_CORE_LOGGING_H
#endif /* GUCEF_CORE_LOGGING_H ? */

#ifndef GUCEF_CORE_DVCPPOSWRAP_H
#include "DVCPPOSWRAP.h"
#define GUCEF_CORE_DVCPPOSWRAP_H
#endif /* GUCEF_CORE_DVCPPOSWRAP_H ? */

#ifndef GUCEF_CORE_CFILEACCESS_H
#include "CFileAccess.h"
#define GUCEF_CORE_CFILEACCESS_H
#endif /* GUCEF_CORE_CFILEACCESS_H ? */

#ifndef GUCEF_CORE_CONFIGSTORE_H
#include "CConfigStore.h"
#define GUCEF_CORE_CONFIGSTORE_H
#endif /* GUCEF_CORE_CONFIGSTORE_H ? */

#ifndef GUCEF_PROJECTGEN_DATATYPES_H
#include "gucefProjectGen_DataTypes.h"
#define GUCEF_PROJECTGEN_DATATYPES_H
#endif /* GUCEF_PROJECTGEN_DATATYPES_H ? */

#ifndef GUCEF_PROJECTGEN_CIPROJECTGENERATOR_H
#include "gucefProjectGen_CIProjectGenerator.h"
#define GUCEF_PROJECTGEN_CIPROJECTGENERATOR_H
#endif /* GUCEF_PROJECTGEN_CIPROJECTGENERATOR_H ? */

#ifndef GUCEF_PROJECTGEN_CIPROJECTINFOGATHERER_H
#include "gucefProjectGen_CIProjectInfoGatherer.h"
#define GUCEF_PROJECTGEN_CIPROJECTINFOGATHERER_H
#endif /* GUCEF_PROJECTGEN_CIPROJECTINFOGATHERER_H ? */

#ifndef GUCEF_PROJECTGEN_CDIRCRAWLINGPROJECTINFOGATHERER_H
#include "gucefProjectGen_CDirCrawlingProjectInfoGatherer.h"
#define GUCEF_PROJECTGEN_CDIRCRAWLINGPROJECTINFOGATHERER_H
#endif /* GUCEF_PROJECTGEN_CDIRCRAWLINGPROJECTINFOGATHERER_H ? */

#ifndef GUCEF_PROJECTGEN_CXMLPROJECTGENERATOR_H
#include "gucefProjectGen_CXmlProjectGenerator.h"
#define GUCEF_PROJECTGEN_CXMLPROJECTGENERATOR_H
#endif /* GUCEF_PROJECTGEN_CXMLPROJECTGENERATOR_H ? */

#ifndef GUCEF_PROJECTGEN_CCMAKEPROJECTGENERATOR_H
#include "gucefProjectGen_CCMakeProjectGenerator.h"
#define GUCEF_PROJECTGEN_CCMAKEPROJECTGENERATOR_H
#endif /* GUCEF_PROJECTGEN_CCMAKEPROJECTGENERATOR_H ? */

#ifndef GUCEF_PROJECTGEN_CANDROIDMAKEFILEGENERATOR_H
#include "gucefProjectGen_CAndroidMakefileGenerator.h"
#define GUCEF_PROJECTGEN_CANDROIDMAKEFILEGENERATOR_H
#endif /* GUCEF_PROJECTGEN_CANDROIDMAKEFILEGENERATOR_H ? */

#ifndef GUCEF_PROJECTGEN_CPREMAKE4PROJECTGENERATOR_H
#include "gucefProjectGen_CPremake4ProjectGenerator.h"
#define GUCEF_PROJECTGEN_CPREMAKE4PROJECTGENERATOR_H
#endif /* GUCEF_PROJECTGEN_CPREMAKE4PROJECTGENERATOR_H ? */

#ifndef GUCEF_PROJECTGEN_CPROJECTGENGLOBAL_H
#include "gucefProjectGen_CProjectGenGlobal.h"
#define GUCEF_PROJECTGEN_CPROJECTGENGLOBAL_H
#endif /* GUCEF_PROJECTGEN_CPROJECTGENGLOBAL_H ? */

#ifndef GUCEF_PROJECTGEN_CPROJECTPREPROCESSORMANAGER_H
#include "gucefProjectGen_CProjectPreprocessorManager.h"
#define GUCEF_PROJECTGEN_CPROJECTPREPROCESSORMANAGER_H
#endif /* GUCEF_PROJECTGEN_CPROJECTPREPROCESSORMANAGER_H ? */

/*-------------------------------------------------------------------------//
//                                                                         //
//      NAMESPACE                                                          //
//                                                                         //
//-------------------------------------------------------------------------*/

using namespace GUCEF;
using namespace GUCEF::PROJECTGEN;

/*-------------------------------------------------------------------------//
//                                                                         //
//      UTILITIES                                                          //
//                                                                         //
//-------------------------------------------------------------------------*/

bool
LoadConfig( CORE::CValueList& keyValueList )
{GUCEF_TRACE;

    #ifdef GUCEF_DEBUG_MODE
    const CORE::CString configFile = "ProjectGenerator_d.ini";
    #else
    const CORE::CString configFile = "ProjectGenerator.ini";
    #endif

    CORE::CString configFilePath = CORE::CombinePath( "$CURWORKDIR$", configFile );
    configFilePath = CORE::RelativePath( configFilePath );

    GUCEF_LOG( CORE::LOGLEVEL_BELOW_NORMAL, "Checking for config file @ " + configFilePath );
    if ( !CORE::FileExists( configFilePath ) )
    {
        configFilePath = CORE::CombinePath( "$MODULEDIR$", configFile );
        configFilePath = CORE::RelativePath( configFilePath );

        GUCEF_LOG( CORE::LOGLEVEL_BELOW_NORMAL, "Checking for config file @ " + configFilePath );
        if ( !FileExists( configFilePath ) )
        {
            GUCEF_WARNING_LOG( CORE::LOGLEVEL_NORMAL, "Unable to locate any config file, will rely on params" );
            return false;
        }
    }
    GUCEF_LOG( CORE::LOGLEVEL_NORMAL, "Located config file @ " + configFilePath );

    keyValueList.SetConfigNamespace( "Main/AppArgs" );
    keyValueList.SetUseGlobalConfig( true );
    keyValueList.SetAllowDuplicates( false );
    keyValueList.SetAllowMultipleValues( true );

    CORE::CConfigStore& configStore = CORE::CCoreGlobal::Instance()->GetConfigStore();
    configStore.SetConfigFile( configFilePath );
    return configStore.LoadConfig();
}

/*-------------------------------------------------------------------------*/

void
ParseParams( const int argc                 ,
             char* argv[]                   ,
             CORE::CValueList& keyValueList )
{GUCEF_TRACE;

    GUCEF::CORE::CString argString;
    if ( argc > 0 )
    {
        argString = *argv;

        // Combine the argument strings back into a single string because we don't want to use
        // a space as the seperator
        for ( int i=1; i<argc; ++i )
        {
            argString += ' ' + CORE::CString( argv[ i ] );
        }

        // Parse the param list based on the ' symbol
        GUCEF_LOG( CORE::LOGLEVEL_NORMAL, "Application parameters: " + argString );
        keyValueList.SetMultiple( argString, '*' );
    }
}

/*---------------------------------------------------------------------------*/

/*
 *      Application entry point
 */
GUCEF_OSMAIN_BEGIN
{GUCEF_TRACE;

    GUCEF_LOG( CORE::LOGLEVEL_NORMAL, "This tool was compiled on: " __DATE__ " @ " __TIME__ );

    CORE::CCoreGlobal::Instance();
    PROJECTGEN::CProjectGenGlobal::Instance();

    // Load settings from a config file (if any) and then override with params (if any)
    CORE::CValueList keyValueList;
    LoadConfig( keyValueList );
    ParseParams( argc, argv, keyValueList );

    CORE::Int32 minLogLevel = CORE::LOGLEVEL_BELOW_NORMAL;
    CORE::CString valueStr = keyValueList.GetValueAlways( "MinimalLogLevel" );
    if ( !valueStr.IsNULLOrEmpty() )
    {
        minLogLevel = CORE::StringToInt32( valueStr );
        CORE::CCoreGlobal::Instance()->GetLogManager().SetMinLogLevel( minLogLevel );
    }

    // Support overriding environment variables from a file.
    // This can be important for build environments which rely on such variables
    CORE::CString envOverrideFile = keyValueList.GetValueAlways( "envOverridesFile" );
    if ( !envOverrideFile.IsNULLOrEmpty() )
    {
        CORE::CString fileContent;
        if ( CORE::LoadTextFileAsString( envOverrideFile, fileContent, true, "\n" ) )
        {
            CORE::SetEnvOverrides( fileContent );
        }
    }

    CORE::CString outputDir = CORE::RelativePath( keyValueList.GetValueAlways( "outputDir" ) );
    if ( outputDir.IsNULLOrEmpty() )
    {
        outputDir = CORE::RelativePath( "$CURWORKDIR$" );
    }
    CORE::CreateDirs( outputDir );

    CORE::CString logFilename = CORE::CombinePath( outputDir, "ProjectGenerator_Log.txt" );

    keyValueList.Set( "logfile", logFilename );

    CORE::CFileAccess logFileAccess( logFilename, "w" );
    CORE::CStdLogger logger( logFileAccess );
    CORE::CCoreGlobal::Instance()->GetLogManager().AddLogger( &logger );

    CORE::CPlatformNativeConsoleLogger console;
    CORE::CCoreGlobal::Instance()->GetLogManager().AddLogger( console.GetLogger() );

    CORE::CCoreGlobal::Instance()->GetLogManager().FlushBootstrapLogEntriesToLogs();
    GUCEF_LOG( CORE::LOGLEVEL_NORMAL, "Flushed to log @ " + logFilename );

    TStringVector rootDirs;
    try
    {
        rootDirs = keyValueList.GetValueVector( "rootDir" );
        GUCEF_LOG( CORE::LOGLEVEL_NORMAL, "Number of rootDir arguments passed from command line: " + CORE::UInt32ToString( rootDirs.size() ) );
    }
    catch ( CORE::CValueList::EUnknownKey& )
    {
        rootDirs.push_back( CORE::RelativePath( "$CURWORKDIR$" ) );
        GUCEF_LOG( CORE::LOGLEVEL_NORMAL, "Using current working directory since no rootDir arguments where passed from the command line" );
    }

    bool addToolCompileTimeToOutput = CORE::StringToBool( keyValueList.GetValueAlways( "addToolCompileTimeToOutput" ) );

    // Get the generators to use
    TStringVector generatorList = keyValueList.GetValueAlways( "generators" ).ParseElements( ';', false );
    if ( generatorList.size() == 0  )
    {
        // No specific generators where specified, defaulting...
        generatorList.push_back( "xml" );
    }

    // Set any global dir excludes that where passed as cmd parameters
    TProjectInfo projectInfo;
    projectInfo.globalDirExcludeList = keyValueList.GetValueAlways( "dirsToIgnore" ).ParseElements( ';', false );
    GUCEF_LOG( CORE::LOGLEVEL_NORMAL, "There are " + CORE::UInt32ToString( projectInfo.globalDirExcludeList.size() ) + " dirs in the global dir ignore list" );

    projectInfo.projectName = keyValueList.GetValueAlways( "projectName" );

    bool useProjectInfoCache = CORE::StringToBool( keyValueList.GetValueAlways( "useProjectInfoCache" ) );
    bool projectInfoLoadedFromCache = false;
    if ( useProjectInfoCache )
    {
        CORE::CString cachedInfoPath = CORE::CombinePath( CORE::RelativePath( outputDir ), "Project.xml" );
        projectInfoLoadedFromCache = DeserializeProjectInfo( projectInfo, cachedInfoPath );
    }

    if ( !projectInfoLoadedFromCache )
    {
        // Use an info gatherer to get all the project information for us
        CDirCrawlingProjectInfoGatherer infoGatherer;
        infoGatherer.GatherInfo( rootDirs    ,
                                 projectInfo );
    }

    // Before we hand the data we collected and generated to the generator(s) for the desired output we will check
    // for preprocessors which can be executed before any output generator. These apply changes to the project data
    // that will apply to all output generators
    const CProjectPreprocessorManager::TProjectPreprocessorsList& projectPreProcessors = CProjectGenGlobal::Instance()->GetProjectPreprocessorManager().GetProjectPreprocessors();
    CProjectPreprocessorManager::TProjectPreprocessorsList::const_iterator n = projectPreProcessors.begin();
    while ( n != projectPreProcessors.end() )
    {
        GUCEF_LOG( CORE::LOGLEVEL_NORMAL, "Invoking project preprocessor" );
        (*n)->ProccessProjects( projectInfo  ,
                                outputDir    ,
                                keyValueList );
        ++n;
    }

    // Now we output the project info using all generators specified
    TStringVector::iterator i = generatorList.begin();
    while ( i != generatorList.end() )
    {
        if ( (*i).Lowercase() == "xml" )
        {
            CXmlProjectGenerator xmlGenerator;
            xmlGenerator.GenerateProject( projectInfo                ,
                                          outputDir                  ,
                                          addToolCompileTimeToOutput ,
                                          keyValueList               );
        }
        else
        if ( (*i).Lowercase() == "androidmake" )
        {
            CAndroidMakefileGenerator androidMakefileGenerator;
            androidMakefileGenerator.GenerateProject( projectInfo                ,
                                                      outputDir                  ,
                                                      addToolCompileTimeToOutput ,
                                                      keyValueList               );
        }
        else
        if ( (*i).Lowercase() == "cmake" )
        {
            CCMakeProjectGenerator cmakeGenerator;
            cmakeGenerator.GenerateProject( projectInfo                ,
                                            outputDir                  ,
                                            addToolCompileTimeToOutput ,
                                            keyValueList               );
        }
        else
        if ( (*i).Lowercase() == "premake4" )
        {
            CPremake4ProjectGenerator premake4Generator;
            premake4Generator.GenerateProject( projectInfo                ,
                                               outputDir                  ,
                                               addToolCompileTimeToOutput ,
                                               keyValueList               );
        }
        ++i;
    }

    GUCEF_LOG( CORE::LOGLEVEL_NORMAL, "Wrote log file to: " + logFilename );

    CORE::CCoreGlobal::Instance()->GetLogManager().ClearLoggers();

    return 0;
}
GUCEF_OSMAIN_END

/*-------------------------------------------------------------------------//
//                                                                         //
//      Info & Changes                                                     //
//                                                                         //
//-------------------------------------------------------------------------//

- 27-11-2004 :
        - Dinand: Initial implementation

---------------------------------------------------------------------------*/
<|endoftext|>


<commit_before>/*------------------------------------------------------------------------
* (The MIT License)
*
* Copyright (c) 2008-2011 Rhomobile, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* http://rhomobile.com
*------------------------------------------------------------------------*/

#include "SSLImpl.h"

#include "logging/RhoLog.h"
#undef DEFAULT_LOGCATEGORY
#define DEFAULT_LOGCATEGORY "SSL"

namespace rho
{
	namespace net
	{

Platform::String^ A2PS(char* str)
{
	std::string s_str = std::string(str);
	std::wstring wid_str = std::wstring(s_str.begin(), s_str.end());
	const wchar_t* w_char = wid_str.c_str();
	return ref new Platform::String(w_char);
}

		void * SSLImpl::createStorage()
		{
			return new ssl_data_t();
		}

		void SSLImpl::freeStorage(void *ptr)
		{
			if(ptr)
			{
				delete ptr;
				ptr = null;
			}
		}

		CURLcode SSLImpl::connect(int sockfd, int nonblocking, int *done, int ssl_verify_peer, void *storage)
		{
			struct sockaddr_in adr_inet= {0};
			int len_inet = sizeof(adr_inet);
			int res;
			char buffer [33];
			CURLcode retCode = CURLE_SSL_CONNECT_ERROR;

			ssl_data_t* Storage = (ssl_data_t*)storage;
			if(Storage == null)
				return CURLE_SSL_CONNECT_ERROR;

			res = getpeername(sockfd, (struct sockaddr *)&adr_inet, &len_inet);
			if(res == -1)
				return CURLE_SSL_CONNECT_ERROR;

			Platform::String^ host = A2PS(inet_ntoa(adr_inet.sin_addr));
			Platform::String^ port = A2PS(itoa(adr_inet.sin_port, buffer, 10));

			task<void>(Storage->m_sslSocket->ConnectAsync(ref new HostName(host), port, Sockets::SocketProtectionLevel::Ssl)).then([this, Storage, &retCode] (task<void> previousTask) {
				try
				{
					previousTask.get();
					retCode = CURLE_OK;
				}
				catch (Platform::Exception^ exception)
				{
					delete Storage->m_sslSocket;
					Storage->m_sslSocket = nullptr;
					RAWLOG_ERROR("SSL connection error");
					retCode = CURLE_SSL_CONNECT_ERROR;
				}

			}).wait();

			return retCode;
		}

		void SSLImpl::shutdown(void *storage)
		{
			ssl_data_t* Storage = (ssl_data_t*)storage;
			if (Storage == nullptr)
				return;

			delete Storage->m_sslSocket;
			Storage->m_sslSocket = nullptr;
		}

		ssize_t SSLImpl::send(const void *mem, size_t len, void *storage)
		{
			int retCode = -1;

			ssl_data_t* Storage = (ssl_data_t*)storage;

			if(Storage == null)
				return -1;

			IOutputStream^ os = Storage->m_sslSocket->OutputStream;

			auto writer = ref new DataWriter(os);

			auto data = ref new Platform::Array<uint8>(len);

			memcpy(data->Data, mem, len);

			writer->WriteBytes(data);

			task<unsigned int>(writer->StoreAsync()).then([this, &retCode] (task<unsigned int> bytesStored) {
				try
				{
					retCode = bytesStored.get();
				}
				catch (Platform::Exception^ exception)
				{
					RAWLOG_ERROR("SSL send failed");
					retCode = -1;
				}

			}).wait();

			if(retCode == -1)
				return -1;

			task<bool>(writer->FlushAsync()).then([this, &retCode] (task<bool> isFlushed) {
				try
				{
					if(!isFlushed.get())
						retCode = -1;
				}
				catch (Platform::Exception^ exception)
				{
					RAWLOG_ERROR("SSL send failed");
					retCode = CURLE_SSL_CONNECT_ERROR;
				}

			}).wait();

			return retCode;
		}

		ssize_t SSLImpl::recv(char *buf, size_t size, int *wouldblock, void *storage)
		{
			int retCode = -1;

			ssl_data_t* Storage = (ssl_data_t*)storage;

			if(Storage == null)
				return -1;

			IInputStream^ is = Storage->m_sslSocket->InputStream;

			auto reader = ref new DataReader(is);

			auto data = ref new Platform::Array<uint8>(size);

			task<unsigned int>(reader->LoadAsync(size)).then([this, reader, &retCode, data] (task<unsigned int> bytesLoaded) {
				try
				{
					retCode = bytesLoaded.get();
			        reader->ReadBytes(data);
				}
				catch (Platform::Exception^ exception)
				{
					RAWLOG_ERROR("SSL read failed");
					retCode = -1;
				}

			}).wait();

			*wouldblock = (retCode > 0) ? 0 : 1;

			return retCode;
		}

	} // namespace net
} // namespace rho
<commit_msg>ssl crashes on WP8 fixed. SAS does work now correctly<commit_after>/*------------------------------------------------------------------------
* (The MIT License)
*
* Copyright (c) 2008-2011 Rhomobile, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* http://rhomobile.com
*------------------------------------------------------------------------*/

#include "SSLImpl.h"

#include "logging/RhoLog.h"
#undef DEFAULT_LOGCATEGORY
#define DEFAULT_LOGCATEGORY "SSL"

namespace rho
{
	namespace net
	{

Platform::String^ A2PS(char* str)
{
	std::string s_str = std::string(str);
	std::wstring wid_str = std::wstring(s_str.begin(), s_str.end());
	const wchar_t* w_char = wid_str.c_str();
	return ref new Platform::String(w_char);
}

		void * SSLImpl::createStorage()
		{
			return new ssl_data_t();
		}

		void SSLImpl::freeStorage(void *ptr)
		{
			if(ptr)
			{
				delete ptr;
				ptr = null;
			}
		}

		CURLcode SSLImpl::connect(int sockfd, int nonblocking, int *done, int ssl_verify_peer, void *storage)
		{
			struct sockaddr_in adr_inet= {0};
			int len_inet = sizeof(adr_inet);
			int res;
			char buffer [33];
			CURLcode retCode = CURLE_SSL_CONNECT_ERROR;

			ssl_data_t* Storage = (ssl_data_t*)storage;
			if(Storage == null)
				return CURLE_SSL_CONNECT_ERROR;

			res = getpeername(sockfd, (struct sockaddr *)&adr_inet, &len_inet);
			if(res == -1)
				return CURLE_SSL_CONNECT_ERROR;

			struct hostent *remoteHost;
			remoteHost = gethostbyaddr((char *)&(adr_inet.sin_addr), 4, AF_INET);
			Platform::String^ host = A2PS(remoteHost->h_name);
			Platform::String^ port = A2PS("https");

			task<void>(Storage->m_sslSocket->ConnectAsync(ref new HostName(host), port, Sockets::SocketProtectionLevel::Ssl)).then([this, Storage, &retCode] (task<void> previousTask) {
				try
				{
					previousTask.get();
					retCode = CURLE_OK;
				}
				catch (Platform::Exception^ exception)
				{
					delete Storage->m_sslSocket;
					Storage->m_sslSocket = nullptr;
					RAWLOG_ERROR("SSL connection error");
					retCode = CURLE_SSL_CONNECT_ERROR;
				}

			}).wait();

			*done = 1;
			return retCode;
		}

		void SSLImpl::shutdown(void *storage)
		{
			ssl_data_t* Storage = (ssl_data_t*)storage;
			if (Storage == nullptr)
				return;

			delete Storage->m_sslSocket;
			Storage->m_sslSocket = nullptr;
		}

		ssize_t SSLImpl::send(const void *mem, size_t len, void *storage)
		{
			int retCode = -1;

			ssl_data_t* Storage = (ssl_data_t*)storage;

			if(Storage == null)
				return -1;

			IOutputStream^ os = Storage->m_sslSocket->OutputStream;

			auto writer = ref new DataWriter(os);

			auto data = ref new Platform::Array<uint8>(len);

			memcpy(data->Data, mem, len);

			writer->WriteBytes(data);

			task<unsigned int>(writer->StoreAsync()).then([this, &retCode] (task<unsigned int> bytesStored) {
				try
				{
					retCode = bytesStored.get();
				}
				catch (Platform::Exception^ exception)
				{
					RAWLOG_ERROR("SSL send failed");
					retCode = -1;
				}

			}).wait();

			if(retCode == -1)
				return -1;

			task<bool>(writer->FlushAsync()).then([this, &retCode] (task<bool> isFlushed) {
				try
				{
					if(!isFlushed.get())
						retCode = -1;
				}
				catch (Platform::Exception^ exception)
				{
					RAWLOG_ERROR("SSL send failed");
					retCode = CURLE_SSL_CONNECT_ERROR;
				}

			}).wait();

			return retCode;
		}

		ssize_t SSLImpl::recv(char *buf, size_t size, int *wouldblock, void *storage)
		{
			int retCode = -1;

			ssl_data_t* Storage = (ssl_data_t*)storage;

			if(Storage == null)
				return -1;

			IInputStream^ is = Storage->m_sslSocket->InputStream;

			auto reader = ref new DataReader(is);

			reader->InputStreamOptions = InputStreamOptions::Partial;

			task<unsigned int>(reader->LoadAsync(size)).then([this, reader, &retCode, buf] (task<unsigned int> bytesLoaded) {
				try
				{
					retCode = bytesLoaded.get();
					auto data = ref new Platform::Array<uint8>(retCode);
			        reader->ReadBytes(data);
					memcpy(buf, data->Data, retCode);
				}
				catch (Platform::Exception^ exception)
				{
					RAWLOG_ERROR("SSL read failed");
					retCode = -1;
				}

			}).wait();

			*wouldblock = (retCode > 0) ? 0 : 1;

			return retCode;
		}

	} // namespace net
} // namespace rho
<|endoftext|>


<commit_before>std::vector<float> arithMean(std::vector<float> x) {
	std::vector<float> a(x.size());
	for (int i = 0; i < x.length; i++) {
		float s = 0.0;
		for(int j = 0; j < i + 1; j++)
			s = s + x[j];

		a.push_back(s / (i+1));
	}

	return a;
}<commit_msg>Updated Lecture 3 (Small flaw in 'arithmetic mean' of c++ variant)<commit_after>std::vector<float> arithMean(std::vector<float> x) {
	std::vector<float> a(x.size());
	for (int i = 0; i < x.size(); i++) {
		float s = 0.0;
		for(int j = 0; j < i + 1; j++)
			s = s + x[j];

		a.push_back(s / (i+1));
	}

	return a;
}<|endoftext|>


<commit_before>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile: mitkPropertyManager.cpp,v $
Language:  C++
Date:      $Date$
Version:   $Revision: 1.12 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkSceneReaderV1.h"
#include "mitkSerializerMacros.h"
#include "mitkDataTreeNodeFactory.h"

MITK_REGISTER_SERIALIZER(SceneReaderV1)

bool mitk::SceneReaderV1::LoadScene( TiXmlDocument& document, const std::string& workingDirectory, DataStorage* storage )
{
  assert(storage);
  bool error(false);

  LOG_INFO << "Reading objects for MITK scene from '" << workingDirectory << "'";

  // iterate all nodes
  // first level nodes should be <node> elements. for each
  for( TiXmlElement* element = document.FirstChildElement("node"); element != NULL; element = element->NextSiblingElement("node") )
  {
    //   1. if there is a <data type="..." file="..."> element,
    //        - construct a name for the appropriate deserializer
    //        - try to instantiate this deserializer via itk object factory
    //        - if deserializer could be created, use it to read the file into a BaseData object
    //        - if successful, call the new node's SetData(..)
    DataTreeNode::Pointer node;
    TiXmlElement* dataElement = element->FirstChildElement("data");
    if (dataElement)
    {
      const char* filename( element->Attribute("file") );
      if ( filename )
      {
        DataTreeNodeFactory::Pointer factory = DataTreeNodeFactory::New();
        factory->SetFileName( filename );

        try
        {
          factory->Update();
          node = factory->GetOutput();
        }
        catch (std::exception& e)
        {
          LOG_ERROR << "Error during attempt to read '" << filename << "'. Exception says: " << e.what();
          error = true;
        }

        if (node.IsNull())
        {
          LOG_ERROR << "Error during attempt to read '" << filename << "'. Factory returned NULL object.";
          error = true;
        }
      }
    }

    // in case there was no <data> element we create a new node for our propertylist
    if (node.IsNull())
    {
      node = DataTreeNode::New();
    }

    //   2. check child nodes
    const char* uida = element->Attribute("UID");
    std::string uid("");

    if (uida)
    {
      uid = uida;
      m_NodeForID[uid] = node.GetPointer();
      m_IDForNode[ node.GetPointer() ] = uid;
    }
    else
    {
      LOG_ERROR << "No UID found for current node. Node will have no parents.";
      error = true;
    }

    // remember node for later adding to DataStorage
    m_Nodes.insert( std::make_pair( node, std::list<std::string>() ) );

    //   3. if there are <source> elements, remember parent objects
    for( TiXmlElement* source = element->FirstChildElement("source"); source != NULL; source = source->NextSiblingElement("source") )
    {
      const char* sourceUID = source->Attribute("UID");
      if (sourceUID)
      {
        m_Nodes[node].push_back( std::string(sourceUID) );
      }
    }

  // TODO
  //   5. if there are <properties> nodes,
  //        - instantiate the appropriate PropertyListDeSerializer
  //        - use them to construct PropertyList objects
  //        - add these properties to the node (if necessary, use renderwindow name)

  } // end for all <node>

  // remove all unknown parent UIDs
  for (NodesAndParentsMapType::iterator nodesIter = m_Nodes.begin();
       nodesIter != m_Nodes.end();
       ++nodesIter)
  {
    for (std::list<std::string>::iterator parentsIter = nodesIter->second.begin();
         parentsIter != nodesIter->second.end();)
    {
      if (m_NodeForID.find( *parentsIter ) == m_NodeForID.end())
      {
        parentsIter = nodesIter->second.erase( parentsIter );
        LOG_WARN << "Found a DataTreeNode with unknown parents. Will add it to DataStorage without any parent objects.";
        error = true;
      }
      else
      {
        ++parentsIter;
      }
    }
  }

  // repeat
  //   for all created nodes
  unsigned int lastMapSize(0);
  while ( lastMapSize != m_Nodes.size()) // this is to prevent infinite loops; each iteration must at least add one node to DataStorage
  {
    lastMapSize = m_Nodes.size();

    for (NodesAndParentsMapType::iterator nodesIter = m_Nodes.begin();
         nodesIter != m_Nodes.end();
         ++nodesIter)
    {
      bool addNow(true);
      // if any parent node is not yet in DataStorage, skip node for now and check later
      for (std::list<std::string>::iterator parentsIter = nodesIter->second.begin();
           parentsIter != nodesIter->second.end();
           ++parentsIter)
      {
        if ( !storage->Exists( m_NodeForID[ *parentsIter ] ) )
        {
          addNow = false;
          break;
        }
      }

      if (addNow)
      {
        DataStorage::SetOfObjects::Pointer parents = DataStorage::SetOfObjects::New();
        for (std::list<std::string>::iterator parentsIter = nodesIter->second.begin();
             parentsIter != nodesIter->second.end();
             ++parentsIter)
        {
          parents->push_back( m_NodeForID[ *parentsIter ] );
        }

        // if all parents are found in datastorage (or are unknown), add node to DataStorage
        storage->Add( nodesIter->first, parents );

        // remove this node from m_Nodes
        m_Nodes.erase( nodesIter );

        // break this for loop because iterators are probably invalid
        break;
      }
    }
  }

  // All nodes that are still in m_Nodes at this point are not part of a proper directed graph structure. We'll add such nodes without any parent information.
  for (NodesAndParentsMapType::iterator nodesIter = m_Nodes.begin();
       nodesIter != m_Nodes.end();
       ++nodesIter)
  {
    storage->Add( nodesIter->first );
    LOG_WARN << "Encountered node that is not part of a directed graph structure. Will be added to DataStorage without parents.";
    error = true;
  }

  // TODO prepare to detect errors (such as cycles) from wrongly written or edited xml files

  return !error;
}

<commit_msg>FIX (#2183): correctly parse <data> tag; correctly construct filename for BaseData files<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile: mitkPropertyManager.cpp,v $
Language:  C++
Date:      $Date$
Version:   $Revision: 1.12 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkSceneReaderV1.h"
#include "mitkSerializerMacros.h"
#include "mitkDataTreeNodeFactory.h"

MITK_REGISTER_SERIALIZER(SceneReaderV1)

bool mitk::SceneReaderV1::LoadScene( TiXmlDocument& document, const std::string& workingDirectory, DataStorage* storage )
{
  assert(storage);
  bool error(false);

  LOG_INFO << "Reading objects for MITK scene from '" << workingDirectory << "'";

  // iterate all nodes
  // first level nodes should be <node> elements. for each
  for( TiXmlElement* element = document.FirstChildElement("node"); element != NULL; element = element->NextSiblingElement("node") )
  {
    //   1. if there is a <data type="..." file="..."> element,
    //        - construct a name for the appropriate deserializer
    //        - try to instantiate this deserializer via itk object factory
    //        - if deserializer could be created, use it to read the file into a BaseData object
    //        - if successful, call the new node's SetData(..)
    DataTreeNode::Pointer node;
    TiXmlElement* dataElement = element->FirstChildElement("data");
    if (dataElement)
    {
      const char* filename( dataElement->Attribute("file") );
      if ( filename )
      {
        DataTreeNodeFactory::Pointer factory = DataTreeNodeFactory::New();
        factory->SetFileName( workingDirectory + "/" + filename );

        try
        {
          factory->Update();
          node = factory->GetOutput();
        }
        catch (std::exception& e)
        {
          LOG_ERROR << "Error during attempt to read '" << filename << "'. Exception says: " << e.what();
          error = true;
        }

        if (node.IsNull())
        {
          LOG_ERROR << "Error during attempt to read '" << filename << "'. Factory returned NULL object.";
          error = true;
        }
      }
    }

    // in case there was no <data> element we create a new node for our propertylist
    if (node.IsNull())
    {
      node = DataTreeNode::New();
    }

    //   2. check child nodes
    const char* uida = element->Attribute("UID");
    std::string uid("");

    if (uida)
    {
      uid = uida;
      m_NodeForID[uid] = node.GetPointer();
      m_IDForNode[ node.GetPointer() ] = uid;
    }
    else
    {
      LOG_ERROR << "No UID found for current node. Node will have no parents.";
      error = true;
    }

    // remember node for later adding to DataStorage
    m_Nodes.insert( std::make_pair( node, std::list<std::string>() ) );

    //   3. if there are <source> elements, remember parent objects
    for( TiXmlElement* source = element->FirstChildElement("source"); source != NULL; source = source->NextSiblingElement("source") )
    {
      const char* sourceUID = source->Attribute("UID");
      if (sourceUID)
      {
        m_Nodes[node].push_back( std::string(sourceUID) );
      }
    }

  // TODO
  //   5. if there are <properties> nodes,
  //        - instantiate the appropriate PropertyListDeSerializer
  //        - use them to construct PropertyList objects
  //        - add these properties to the node (if necessary, use renderwindow name)

  } // end for all <node>

  // remove all unknown parent UIDs
  for (NodesAndParentsMapType::iterator nodesIter = m_Nodes.begin();
       nodesIter != m_Nodes.end();
       ++nodesIter)
  {
    for (std::list<std::string>::iterator parentsIter = nodesIter->second.begin();
         parentsIter != nodesIter->second.end();)
    {
      if (m_NodeForID.find( *parentsIter ) == m_NodeForID.end())
      {
        parentsIter = nodesIter->second.erase( parentsIter );
        LOG_WARN << "Found a DataTreeNode with unknown parents. Will add it to DataStorage without any parent objects.";
        error = true;
      }
      else
      {
        ++parentsIter;
      }
    }
  }

  // repeat
  //   for all created nodes
  unsigned int lastMapSize(0);
  while ( lastMapSize != m_Nodes.size()) // this is to prevent infinite loops; each iteration must at least add one node to DataStorage
  {
    lastMapSize = m_Nodes.size();

    for (NodesAndParentsMapType::iterator nodesIter = m_Nodes.begin();
         nodesIter != m_Nodes.end();
         ++nodesIter)
    {
      bool addNow(true);
      // if any parent node is not yet in DataStorage, skip node for now and check later
      for (std::list<std::string>::iterator parentsIter = nodesIter->second.begin();
           parentsIter != nodesIter->second.end();
           ++parentsIter)
      {
        if ( !storage->Exists( m_NodeForID[ *parentsIter ] ) )
        {
          addNow = false;
          break;
        }
      }

      if (addNow)
      {
        DataStorage::SetOfObjects::Pointer parents = DataStorage::SetOfObjects::New();
        for (std::list<std::string>::iterator parentsIter = nodesIter->second.begin();
             parentsIter != nodesIter->second.end();
             ++parentsIter)
        {
          parents->push_back( m_NodeForID[ *parentsIter ] );
        }

        // if all parents are found in datastorage (or are unknown), add node to DataStorage
        storage->Add( nodesIter->first, parents );

        // remove this node from m_Nodes
        m_Nodes.erase( nodesIter );

        // break this for loop because iterators are probably invalid
        break;
      }
    }
  }

  // All nodes that are still in m_Nodes at this point are not part of a proper directed graph structure. We'll add such nodes without any parent information.
  for (NodesAndParentsMapType::iterator nodesIter = m_Nodes.begin();
       nodesIter != m_Nodes.end();
       ++nodesIter)
  {
    storage->Add( nodesIter->first );
    LOG_WARN << "Encountered node that is not part of a directed graph structure. Will be added to DataStorage without parents.";
    error = true;
  }

  // TODO prepare to detect errors (such as cycles) from wrongly written or edited xml files

  return !error;
}

<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////
// Copyright (c) 2012 Polytech Montpellier
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the copyright holder nor the names of its
//       contributors may be used to endorse or promote products derived from
//       this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
// BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
////////////////////////////////////////////////////////////

#include "Badger.hpp"

#include "ConsoleViewBadger.hpp"
#include "Database.hpp"

#include <cstdlib>
#include <iostream>
#include <sstream>
#include <iomanip>

namespace badger
{

    namespace
    {
        void sendCommand(plt::Console &c, const std::string &command)
        {
            for(auto it = command.begin(); it!=command.end(); ++it)
                c.sendChar(*it);

            c.sendChar('\n');
        }
    }

    // Important: don't remove the last space of each line! They are for SQL request!
    const std::string Badger::m_request =
"UPDATE vbMifare.Registrations "
"INNER JOIN Polytech.Users ON Polytech.Users.Username = vbMifare.Registrations.Id_user "
"INNER JOIN vbMifare.Lectures ON (vbMifare.Registrations.Id_lecture = vbMifare.Lectures.Id_lecture AND vbMifare.Registrations.Id_package = " "vbMifare.Lectures.Id_package AND (vbMifare.Lectures.Date < CURDATE() OR (vbMifare.Lectures.Date = CURDATE() AND EndTime < CURTIME()))) "
"LEFT JOIN vbMifare.BadgingInformations ON (vbMifare.Lectures.Date = vbMifare.BadgingInformations.Date AND Polytech.Users.Mifare = " "vbMifare.BadgingInformations.Mifare AND vbMifare.Lectures.StartTime <= vbMifare.BadgingInformations.Time AND vbMifare.Lectures.EndTime >= " "vbMifare.BadgingInformations.Time) "
"SET vbMifare.Registrations.Status = CASE "
"WHEN vbMifare.BadgingInformations.Date IS NULL THEN \"Absent\" "
"ELSE \"Present\" "
"END;";

    Badger::Badger
    (
    ) :
    m_continuer(true)
    {
        // Important, a console need a view, otherwise seg fault :)
        m_console.setView( std::make_shared<ConsoleViewBadger>() );

        m_console.enable(true);

        std::function<void(const std::string&)> openFunction = std::bind(&Badger::open, this, std::placeholders::_1);
        addCommand("open", openFunction, false);

        std::function<void()> closeFunction = std::bind(&Badger::close, this);
        addCommand("close", closeFunction, true);

        std::function<std::string()> nextFunction = std::bind(&Badger::next, this);
        addCommand("next", nextFunction, true);

        std::function<std::string()> rollbackFunction = std::bind(&Badger::rollback, this);
        addCommand("rollback", rollbackFunction, true);

        std::function<std::string()> eraseFunction = std::bind(&Badger::erase, this);
        addCommand("erase", eraseFunction, true);

        std::function<std::string()> countFunction = std::bind(&Badger::count, this);
        addCommand("count", countFunction, true);

        std::function<std::string()> getDateTimeFunction = std::bind(&Badger::getDateTime, this);
        addCommand("getDateTime", getDateTimeFunction, true);

        std::function<std::string(const Date&, const Time&)> setDateTimeFunction = std::bind(&Badger::setDateTime, this, std::placeholders::_1, std::placeholders::_2);
        addCommand("setDateTime", setDateTimeFunction, true);

        std::function<std::string(const Date&, const Time&, const Time&)> displayFunction = std::bind(&Badger::display, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
        addCommand("display", displayFunction, true);

        std::function<std::string(const std::string&, const Date&, const Time&, const Time&)> sendFunction = std::bind(&Badger::send, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4);
        addCommand("send", sendFunction, true);

        std::function<void()> quitFunction = std::bind(&Badger::quit, this);
        addCommand("quit", quitFunction, false);
        addCommand("exit", quitFunction, false);

        std::cout << "==================================" << std::endl;
        std::cout << "    Welcome to badger program    " << std::endl;
        std::cout << std::endl;
        std::cout << "To get available options, type '?'" << std::endl;
        std::cout << "==================================" << std::endl;
    }

    Badger::~Badger
    (
    )
    {
        close();
    }

    void Badger::open
    (
        const std::string &port
    )
    {
        m_serial.open(port);
        m_serial.setBaudRate(serial::BaudRate::Baud_38400);
    }

    void Badger::close
    (
    )
    {
        if(m_serial.isOpen())
            m_serial.close();
    }

    std::string Badger::next
    (
    )
    {
        std::vector<serial::byte> command;
        command.push_back('G');

        sendCommandOnSerial(command);
        std::string result = getReturnCommand();

        std::string begin(result, 0, 1);

        return (begin != "A") ? "Database is empty (E) or finish (F), result: " + begin : result.erase(0,1);
    }

    std::string Badger::rollback
    (
    )
    {
        std::vector<serial::byte> command;
        command.push_back('R');

        sendCommandOnSerial(command);
        std::string result = getReturnCommand();

        return (result == "A") ? "" : "Rollback impossible";
    }

    std::string Badger::erase
    (
    )
    {
        std::string answer;
        std::string result;

        std::cout << "Do you really want to erase all database (yes)? ";
        std::getline(std::cin, answer);

        if(answer == "yes")
        {
            std::cout << "Wait..." << std::endl;

            std::vector<serial::byte> command;
            command.push_back('E');

            sendCommandOnSerial(command);

            result = getReturnCommand();
        }

        return (result == "A") ? "" : "Erase impossible";

    }

    std::string Badger::count
    (
    )
    {
        std::vector<serial::byte> command;
        command.push_back('N');

        sendCommandOnSerial(command);
        std::string result = getReturnCommand();
        result.erase(result.begin());

        return result;
    }

    std::string Badger::getDateTime
    (
    )
    {
        std::vector<serial::byte> command;
        command.push_back('T');

        sendCommandOnSerial(command);
        std::string result = getReturnCommand();
        result.erase(result.begin());

        Date date;
        Time time;

        std::istringstream iss( std::string(result, 0, 2) + '-' + std::string(result, 2, 2) + '-' + std::string(result, 4, 4) );
        iss >> date;

        iss.clear();
        iss.str( std::string(result, 8, 2) + ':' + std::string(result, 10, 2) + ':' + std::string(result, 12, 2) );
        iss >> time;

        std::ostringstream oss;
        oss << "Date: " << date << ",\tTime:" << time;
        return oss.str();
    }

    std::string Badger::setDateTime
    (
        const Date &date,
        const Time &time
    )
    {
        std::ostringstream oss;
        oss << std::setfill('0');
        oss << std::setw(2) << date.getDay();
        oss << std::setw(2) << date.getMonth();
        oss << std::setw(4) << date.getYear();

        oss << std::setw(2) << time.getHour();
        oss << std::setw(2) << time.getMinute();
        oss << std::setw(2) << time.getSecond();
        oss << 0; // Event

        std::vector<serial::byte> command;
        command.push_back('S');

        auto datetime = oss.str();
        for(auto c : datetime)
            command.push_back(c);

        sendCommandOnSerial(command);
        std::string result = getReturnCommand();
        result.erase(result.begin());

        oss.clear();
        oss.str("");
        oss << "Date: " << date << ",\tTime:" << time;
        return oss.str();
    }

    std::string Badger::display
    (
        const Date &date,
        const Time &begin,
        const Time &end
    )
    {
        auto records = get(date, begin, end);

        for(unsigned int i(0); i<records.size(); ++i)
            std::cout << records[i].date << ' ' << records[i].time << ' ' << records[i].data << std::endl;

        return "";
    }

    std::string Badger::send
    (
        const std::string &passwd,
        const Date &date,
        const Time &begin,
        const Time &end
    )
    {
        auto records = get(date, begin, end);

        std::cout << "Send in database..." << std::endl;

        badger::Database db("localhost", "vbMifare", passwd, "vbMifare", 0);
        db.prepare("Insert INTO BadgingInformations (Mifare, Date, Time) VALUES(?, ?, ?)");

        for(unsigned int i(0); i<records.size(); ++i)
        {
            std::string dateString;
            std::string timeString;

            // Extract date
            std::ostringstream oss;
            oss << std::setfill('0');
            oss << std::setw(4) << records[i].date.getYear()
                << std::setw(2) << records[i].date.getMonth()
                << std::setw(2) << records[i].date.getDay();
            dateString = oss.str();

            // Extract time
            oss.clear();
            oss.str("");
            oss << records[i].time;
            timeString = oss.str();

            db.addParameterString( &records[i].data );
            db.addParameterString( &dateString );
            db.addParameterString( &timeString );

            db.execute();
        }

        std::cout << "Sending finish." << std::endl;
        std::cout << "Updating registrations status." << std::endl;
            db.deletePreparedRequest();
            db.prepare(Badger::m_request);
            db.execute();
        std::cout << "Updating finish." << std::endl;
        std::cout << "You can now erase the records." << std::endl;

        return "";
    }

    void Badger::quit
    (
    )
    {
        m_continuer = false;
    }

    void Badger::tryToSendCommand
    (
        const std::string &command
    )
    {
        std::string nameFunction;
        std::istringstream iss(command);

        iss >> nameFunction;

        bool canBeSend = true;

        auto it = m_access.find(nameFunction);

        if(it != m_access.end())
        {
            if(m_access[nameFunction] && !m_serial.isOpen())
            {
                std::cout << "Serial port isn't open" << std::endl;
                canBeSend = false;
            }
        }

        if(canBeSend)
            sendCommand(m_console, command);
    }

    std::string Badger::getReturnCommand
    (
    )
    {
        std::vector<serial::byte> result;

        // After readUntil, flush the stream to avoid some read problems
        m_serial.readUntil(result, '\r').flush();

        if(result.front() != serial::byte(2) || result.back() != serial::byte(13))
            throw std::runtime_error("The return command don't begin by STX or don't end by CR");

        result.erase( result.begin() );
        result.erase( --result.end() );
        result.push_back('\0');

        return std::string(&result[0]);
    }

    void Badger::sendCommandOnSerial
    (
        const std::vector<serial::byte> &command
    )
    {
        std::vector<serial::byte> tmp = command;

        // Add STX to begin
        tmp.insert(tmp.begin(), 2);

        // Add CR to end
        tmp.push_back(13);

        m_serial.write(&tmp[0], tmp.size());
    }

    Badger::Record Badger::parseRecord
    (
        const std::string &str
    ) const
    {
        std::string day(str, 0, 2);
        std::string month(str, 2, 2);
        std::string year(str, 4, 4);

        std::string hour(str, 8, 2);
        std::string minute(str, 10, 2);
        std::string seconde(str, 12, 2);

        Record rcd;

        rcd.date = Date(std::atoi(&day[0]), std::atoi(&month[0]), std::atoi(&year[0]));
        rcd.time = Time(std::atoi(&hour[0]), std::atoi(&minute[0]), std::atoi(&seconde[0]));
        rcd.data = std::string(str, 18);

        return rcd;
    }

    std::vector<Badger::Record> Badger::get
    (
        const Date &date,
        const Time &begin,
        const Time &end
    )
    {
        unsigned int numberOfRecords;

        std::string countStr = count();
        std::istringstream iss(countStr);

        if(!(iss >> numberOfRecords))
            throw std::runtime_error("Unable to parse number of records");

        rollback();

        std::vector<Record> records;

        for(unsigned int i(0); i<numberOfRecords; ++i)
        {
            Record rcd = parseRecord(next());

            if(rcd.date == date && rcd.time >= begin && rcd.time <= end)
                records.push_back( rcd);
        }

        return records;
    }

    void Badger::run
    (
    )
    {
        while(m_continuer)
        {
            std::string command;

            std::cout << "> ";
            std::getline(std::cin, command);

            tryToSendCommand(command);
        }
    }

} // namespace badger

<commit_msg>Ajout du copyright<commit_after>////////////////////////////////////////////////////////////
// Copyright (c) 2012 Polytech Montpellier
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the copyright holder nor the names of its
//       contributors may be used to endorse or promote products derived from
//       this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
// BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
////////////////////////////////////////////////////////////

#include "Badger.hpp"

#include "ConsoleViewBadger.hpp"
#include "Database.hpp"

#include <cstdlib>
#include <iostream>
#include <sstream>
#include <iomanip>

namespace badger
{

    namespace
    {
        void sendCommand(plt::Console &c, const std::string &command)
        {
            for(auto it = command.begin(); it!=command.end(); ++it)
                c.sendChar(*it);

            c.sendChar('\n');
        }
    }

    // Important: don't remove the last space of each line! They are for SQL request!
    const std::string Badger::m_request =
"UPDATE vbMifare.Registrations "
"INNER JOIN Polytech.Users ON Polytech.Users.Username = vbMifare.Registrations.Id_user "
"INNER JOIN vbMifare.Lectures ON (vbMifare.Registrations.Id_lecture = vbMifare.Lectures.Id_lecture AND vbMifare.Registrations.Id_package = " "vbMifare.Lectures.Id_package AND (vbMifare.Lectures.Date < CURDATE() OR (vbMifare.Lectures.Date = CURDATE() AND EndTime < CURTIME()))) "
"LEFT JOIN vbMifare.BadgingInformations ON (vbMifare.Lectures.Date = vbMifare.BadgingInformations.Date AND Polytech.Users.Mifare = " "vbMifare.BadgingInformations.Mifare AND vbMifare.Lectures.StartTime <= vbMifare.BadgingInformations.Time AND vbMifare.Lectures.EndTime >= " "vbMifare.BadgingInformations.Time) "
"SET vbMifare.Registrations.Status = CASE "
"WHEN vbMifare.BadgingInformations.Date IS NULL THEN \"Absent\" "
"ELSE \"Present\" "
"END;";

    Badger::Badger
    (
    ) :
    m_continuer(true)
    {
        // Important, a console need a view, otherwise seg fault :)
        m_console.setView( std::make_shared<ConsoleViewBadger>() );

        m_console.enable(true);

        std::function<void(const std::string&)> openFunction = std::bind(&Badger::open, this, std::placeholders::_1);
        addCommand("open", openFunction, false);

        std::function<void()> closeFunction = std::bind(&Badger::close, this);
        addCommand("close", closeFunction, true);

        std::function<std::string()> nextFunction = std::bind(&Badger::next, this);
        addCommand("next", nextFunction, true);

        std::function<std::string()> rollbackFunction = std::bind(&Badger::rollback, this);
        addCommand("rollback", rollbackFunction, true);

        std::function<std::string()> eraseFunction = std::bind(&Badger::erase, this);
        addCommand("erase", eraseFunction, true);

        std::function<std::string()> countFunction = std::bind(&Badger::count, this);
        addCommand("count", countFunction, true);

        std::function<std::string()> getDateTimeFunction = std::bind(&Badger::getDateTime, this);
        addCommand("getDateTime", getDateTimeFunction, true);

        std::function<std::string(const Date&, const Time&)> setDateTimeFunction = std::bind(&Badger::setDateTime, this, std::placeholders::_1, std::placeholders::_2);
        addCommand("setDateTime", setDateTimeFunction, true);

        std::function<std::string(const Date&, const Time&, const Time&)> displayFunction = std::bind(&Badger::display, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
        addCommand("display", displayFunction, true);

        std::function<std::string(const std::string&, const Date&, const Time&, const Time&)> sendFunction = std::bind(&Badger::send, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4);
        addCommand("send", sendFunction, true);

        std::function<void()> quitFunction = std::bind(&Badger::quit, this);
        addCommand("quit", quitFunction, false);
        addCommand("exit", quitFunction, false);

        std::cout << "==================================" << std::endl;
        std::cout << "    Welcome to badger program    " << std::endl;
        std::cout << std::endl;
        std::cout << "To get available options, type '?'" << std::endl;
        std::cout << "By Badger Team" << std::endl;
        std::cout << "==================================" << std::endl;
    }

    Badger::~Badger
    (
    )
    {
        close();
    }

    void Badger::open
    (
        const std::string &port
    )
    {
        m_serial.open(port);
        m_serial.setBaudRate(serial::BaudRate::Baud_38400);
    }

    void Badger::close
    (
    )
    {
        if(m_serial.isOpen())
            m_serial.close();
    }

    std::string Badger::next
    (
    )
    {
        std::vector<serial::byte> command;
        command.push_back('G');

        sendCommandOnSerial(command);
        std::string result = getReturnCommand();

        std::string begin(result, 0, 1);

        return (begin != "A") ? "Database is empty (E) or finish (F), result: " + begin : result.erase(0,1);
    }

    std::string Badger::rollback
    (
    )
    {
        std::vector<serial::byte> command;
        command.push_back('R');

        sendCommandOnSerial(command);
        std::string result = getReturnCommand();

        return (result == "A") ? "" : "Rollback impossible";
    }

    std::string Badger::erase
    (
    )
    {
        std::string answer;
        std::string result;

        std::cout << "Do you really want to erase all database (yes)? ";
        std::getline(std::cin, answer);

        if(answer == "yes")
        {
            std::cout << "Wait..." << std::endl;

            std::vector<serial::byte> command;
            command.push_back('E');

            sendCommandOnSerial(command);

            result = getReturnCommand();
        }

        return (result == "A") ? "" : "Erase impossible";

    }

    std::string Badger::count
    (
    )
    {
        std::vector<serial::byte> command;
        command.push_back('N');

        sendCommandOnSerial(command);
        std::string result = getReturnCommand();
        result.erase(result.begin());

        return result;
    }

    std::string Badger::getDateTime
    (
    )
    {
        std::vector<serial::byte> command;
        command.push_back('T');

        sendCommandOnSerial(command);
        std::string result = getReturnCommand();
        result.erase(result.begin());

        Date date;
        Time time;

        std::istringstream iss( std::string(result, 0, 2) + '-' + std::string(result, 2, 2) + '-' + std::string(result, 4, 4) );
        iss >> date;

        iss.clear();
        iss.str( std::string(result, 8, 2) + ':' + std::string(result, 10, 2) + ':' + std::string(result, 12, 2) );
        iss >> time;

        std::ostringstream oss;
        oss << "Date: " << date << ",\tTime:" << time;
        return oss.str();
    }

    std::string Badger::setDateTime
    (
        const Date &date,
        const Time &time
    )
    {
        std::ostringstream oss;
        oss << std::setfill('0');
        oss << std::setw(2) << date.getDay();
        oss << std::setw(2) << date.getMonth();
        oss << std::setw(4) << date.getYear();

        oss << std::setw(2) << time.getHour();
        oss << std::setw(2) << time.getMinute();
        oss << std::setw(2) << time.getSecond();
        oss << 0; // Event

        std::vector<serial::byte> command;
        command.push_back('S');

        auto datetime = oss.str();
        for(auto c : datetime)
            command.push_back(c);

        sendCommandOnSerial(command);
        std::string result = getReturnCommand();
        result.erase(result.begin());

        oss.clear();
        oss.str("");
        oss << "Date: " << date << ",\tTime:" << time;
        return oss.str();
    }

    std::string Badger::display
    (
        const Date &date,
        const Time &begin,
        const Time &end
    )
    {
        auto records = get(date, begin, end);

        for(unsigned int i(0); i<records.size(); ++i)
            std::cout << records[i].date << ' ' << records[i].time << ' ' << records[i].data << std::endl;

        return "";
    }

    std::string Badger::send
    (
        const std::string &passwd,
        const Date &date,
        const Time &begin,
        const Time &end
    )
    {
        auto records = get(date, begin, end);

        std::cout << "Send in database..." << std::endl;

        badger::Database db("localhost", "vbMifare", passwd, "vbMifare", 0);
        db.prepare("Insert INTO BadgingInformations (Mifare, Date, Time) VALUES(?, ?, ?)");

        for(unsigned int i(0); i<records.size(); ++i)
        {
            std::string dateString;
            std::string timeString;

            // Extract date
            std::ostringstream oss;
            oss << std::setfill('0');
            oss << std::setw(4) << records[i].date.getYear()
                << std::setw(2) << records[i].date.getMonth()
                << std::setw(2) << records[i].date.getDay();
            dateString = oss.str();

            // Extract time
            oss.clear();
            oss.str("");
            oss << records[i].time;
            timeString = oss.str();

            db.addParameterString( &records[i].data );
            db.addParameterString( &dateString );
            db.addParameterString( &timeString );

            db.execute();
        }

        std::cout << "Sending finish." << std::endl;
        std::cout << "Updating registrations status." << std::endl;
            db.deletePreparedRequest();
            db.prepare(Badger::m_request);
            db.execute();
        std::cout << "Updating finish." << std::endl;
        std::cout << "You can now erase the records." << std::endl;

        return "";
    }

    void Badger::quit
    (
    )
    {
        m_continuer = false;
    }

    void Badger::tryToSendCommand
    (
        const std::string &command
    )
    {
        std::string nameFunction;
        std::istringstream iss(command);

        iss >> nameFunction;

        bool canBeSend = true;

        auto it = m_access.find(nameFunction);

        if(it != m_access.end())
        {
            if(m_access[nameFunction] && !m_serial.isOpen())
            {
                std::cout << "Serial port isn't open" << std::endl;
                canBeSend = false;
            }
        }

        if(canBeSend)
            sendCommand(m_console, command);
    }

    std::string Badger::getReturnCommand
    (
    )
    {
        std::vector<serial::byte> result;

        // After readUntil, flush the stream to avoid some read problems
        m_serial.readUntil(result, '\r').flush();

        if(result.front() != serial::byte(2) || result.back() != serial::byte(13))
            throw std::runtime_error("The return command don't begin by STX or don't end by CR");

        result.erase( result.begin() );
        result.erase( --result.end() );
        result.push_back('\0');

        return std::string(&result[0]);
    }

    void Badger::sendCommandOnSerial
    (
        const std::vector<serial::byte> &command
    )
    {
        std::vector<serial::byte> tmp = command;

        // Add STX to begin
        tmp.insert(tmp.begin(), 2);

        // Add CR to end
        tmp.push_back(13);

        m_serial.write(&tmp[0], tmp.size());
    }

    Badger::Record Badger::parseRecord
    (
        const std::string &str
    ) const
    {
        std::string day(str, 0, 2);
        std::string month(str, 2, 2);
        std::string year(str, 4, 4);

        std::string hour(str, 8, 2);
        std::string minute(str, 10, 2);
        std::string seconde(str, 12, 2);

        Record rcd;

        rcd.date = Date(std::atoi(&day[0]), std::atoi(&month[0]), std::atoi(&year[0]));
        rcd.time = Time(std::atoi(&hour[0]), std::atoi(&minute[0]), std::atoi(&seconde[0]));
        rcd.data = std::string(str, 18);

        return rcd;
    }

    std::vector<Badger::Record> Badger::get
    (
        const Date &date,
        const Time &begin,
        const Time &end
    )
    {
        unsigned int numberOfRecords;

        std::string countStr = count();
        std::istringstream iss(countStr);

        if(!(iss >> numberOfRecords))
            throw std::runtime_error("Unable to parse number of records");

        rollback();

        std::vector<Record> records;

        for(unsigned int i(0); i<numberOfRecords; ++i)
        {
            Record rcd = parseRecord(next());

            if(rcd.date == date && rcd.time >= begin && rcd.time <= end)
                records.push_back( rcd);
        }

        return records;
    }

    void Badger::run
    (
    )
    {
        while(m_continuer)
        {
            std::string command;

            std::cout << "> ";
            std::getline(std::cin, command);

            tryToSendCommand(command);
        }
    }

} // namespace badger

<|endoftext|>