/*
* Copyright (C) 2004 TES Electronic Solutions GmbH,
* All Rights Reserved.
* This source code and any compilation or derivative thereof is the
* proprietary information of TES Electronic Solutions GmbH
* and is confidential in nature.
* Under no circumstances is this software to be exposed to or placed
* under an Open Source License of any type without the expressed
* written permission of TES Electronic Solutions GmbH
*
*############################################################
*/

#include "StreamRuntimeBase.h"

#include "GfxEnv.h"
#include "GfxWrap.h"
#include "SndWrap.h"
#include "FntWrap.h"
#include "GUIInputMedia.h"
#include "GUIImageLoader.h"

#include "GUIResourceFileHandler.h"
#include "MyGUI_SR.h"

#include "GUITrace.h"
#include "GUIProfiler.h"
#include "GUIFileSysWrap.h"

#include "GUIInputCalibration.h"

#include "GUIMemLeakDetection.h"
#include "GUIMemLeakWatcher.h"

namespace NStreamRuntime
{
    CStreamRuntimeBase::CStreamRuntimeBase() :
        m_bUsagePrinted(false),
        m_kLicense(""),
        m_kLicenseFile(""),
        m_kConfigurationFile("StreamRuntimeConfig.xml"),
        m_iScreenWidth(-1),
        m_iScreenHeight(-1),
        m_kKeyboardDevice(""),
        m_kMouseDevice(""),
        m_kTouchDevice(""),
        m_kRemoteDevice(""),
        m_iTouchSizeX(800),
        m_iTouchSizeY(480),
        m_iTouchOffsetX(0),
        m_iTouchOffsetY(0),
        m_bInputDebugMode(false),
        m_bInputCalibration(false),
        m_pkLicense(NULL),
        m_pkConfigurator(NULL)
    {
        CommonInit();
    }

    CStreamRuntimeBase::~CStreamRuntimeBase()
    {
        delete m_pkLicense;
    }

    void CStreamRuntimeBase::CommonInit()
    {
        // Enable logging to a file
        GUI_REG_FILE_TRACE("StreamRuntime.log");
        // Enable logging to the Visual Studio Debugger
        GUI_REG_DEBUGGER_TRACE();
        // Enable logging to STDOUT
        GUI_REG_STDOUT_TRACE();
    }

    void CStreamRuntimeBase::ProcessCommandLine(eC_UInt uiCommandCount, eC_String* pkCommandLine)
    {
#ifdef STREAMRUNTIME_USE_CLI
        if ((uiCommandCount > 1) && (NULL != pkCommandLine))
        {
            for (eC_UInt uiCurrentParameter = 1; uiCurrentParameter < uiCommandCount; ++uiCurrentParameter)
            {
                eC_String kCurrentParam = pkCommandLine[uiCurrentParameter];
                if (kCurrentParam == "--help")
                {
                    PrintUsage();
                }
                else if (kCurrentParam == "--config")
                {
                    if (uiCurrentParameter + 1 < uiCommandCount)
                    {
                        m_kConfigurationFile = pkCommandLine[++uiCurrentParameter];
                        GUILOGMESSAGE("using config-file: " + m_kConfigurationFile + "\n");
                    }
                }
                else if (kCurrentParam == "--screenwidth")
                {
                    if (uiCurrentParameter + 1 < uiCommandCount)
                    {
                        pkCommandLine[++uiCurrentParameter].ToInt(m_iScreenWidth);
                        GUILOGMESSAGE("using horizontal size: " + eC_String(m_iScreenWidth) + "\n");
                    }
                }
                else if (kCurrentParam == "--screenheight")
                {
                    if (uiCurrentParameter + 1 < uiCommandCount)
                    {
                        pkCommandLine[++uiCurrentParameter].ToInt(m_iScreenHeight);
                        GUILOGMESSAGE("using vertical size: " + eC_String(m_iScreenHeight) + "\n");
                    }
                }
                else if (kCurrentParam == "--keyboard")
                {
                    if (uiCurrentParameter + 1 < uiCommandCount)
                    {
                        m_kKeyboardDevice = pkCommandLine[++uiCurrentParameter];
                        GUILOGMESSAGE("using keyboard-device: " + m_kKeyboardDevice + "\n");
                    }
                }
                else if (kCurrentParam == "--mouse")
                {
                    if (uiCurrentParameter + 1 < uiCommandCount)
                    {
                        m_kMouseDevice = pkCommandLine[++uiCurrentParameter];
                        GUILOGMESSAGE("using MOUSE-device: " + m_kMouseDevice + "\n");
                    }
                }
                else if (kCurrentParam == "--touch")
                {
                    if (uiCurrentParameter + 1 < uiCommandCount)
                    {
                        m_kTouchDevice = pkCommandLine[++uiCurrentParameter];
                        GUILOGMESSAGE("using TOUCH-device: " + m_kTouchDevice + "\n");
                    }
                }
                else if (kCurrentParam == "--remote")
                {
                    if (uiCurrentParameter + 1 < uiCommandCount)
                    {
                        m_kRemoteDevice = pkCommandLine[++uiCurrentParameter];
                        GUILOGMESSAGE("using mouse-device: " + m_kRemoteDevice + "\n");
                    }
                }
                else if (kCurrentParam == "--touchsizex")
                {
                    if (uiCurrentParameter + 1 < uiCommandCount)
                    {
                        pkCommandLine[++uiCurrentParameter].ToInt(m_iTouchSizeX);
                        GUILOGMESSAGE("using horizontal size for touch: " + eC_String(m_iTouchSizeX) + "\n");
                    }
                }
                else if (kCurrentParam == "--touchsizey")
                {
                    if (uiCurrentParameter + 1 < uiCommandCount)
                    {
                        pkCommandLine[++uiCurrentParameter].ToInt(m_iTouchSizeY);
                        GUILOGMESSAGE("using vertical size for touch: " + eC_String(m_iTouchSizeY) + "\n");
                    }
                }
                else if (kCurrentParam == "--touchoffsetx")
                {
                    if (uiCurrentParameter + 1 < uiCommandCount)
                    {
                        pkCommandLine[++uiCurrentParameter].ToInt(m_iTouchOffsetX);
                        GUILOGMESSAGE("using horizontal offset for touch: " + eC_String(m_iTouchOffsetX) + "\n");
                    }
                }
                else if (kCurrentParam == "--touchoffsety")
                {
                    if (uiCurrentParameter + 1 < uiCommandCount)
                    {
                        pkCommandLine[++uiCurrentParameter].ToInt(m_iTouchOffsetY);
                        GUILOGMESSAGE("using vertical offset for touch: " + eC_String(m_iTouchOffsetY) + "\n");
                    }
                }
                else if (kCurrentParam == "--resourcefile")
                {
                    if (uiCurrentParameter + 1 < uiCommandCount)
                    {
                        eC_String kResourceFile = pkCommandLine[++uiCurrentParameter];
                        GUILOGMESSAGE("using resource-file: " + kResourceFile + "\n");

                        GETRESHANDLER.SetResourceFile(kResourceFile);
                        GETRESHANDLER.SetFileOpenOrder(CGUIResourceFileHandler::RESOURCE_FILE_FIRST);
                    }
                }
                else if (kCurrentParam == "--resourcepath")
                {
                    if (uiCurrentParameter + 1 < uiCommandCount)
                    {
                        eC_String kResourcePath = pkCommandLine[++uiCurrentParameter];
                        GUILOGMESSAGE("using resource-path: " + kResourcePath + "\n");

                        GETRESHANDLER.SetResourcePathPrefix(kResourcePath);
                    }
                }
                else if (kCurrentParam == "--license")
                {
                    if (uiCurrentParameter + 1 < uiCommandCount)
                    {
                        m_kLicense = pkCommandLine[++uiCurrentParameter];
                        GUILOGMESSAGE("using license: " + m_kLicense + "\n");

                        m_pkLicense = m_kLicense.ToASCII_Alloc();
                        CGUI::SetGuilianiLicenseKey(m_pkLicense);
                    }
                }
                else if (kCurrentParam == "--licensefile")
                {
                    if (uiCurrentParameter + 1 < uiCommandCount)
                    {
                        m_kLicenseFile = pkCommandLine[++uiCurrentParameter];
                        GUILOGMESSAGE("using license-file: " + m_kLicenseFile + "\n");

                        CGUI::LoadGuilianiLicenseKey(m_kLicenseFile);
                    }
                }
                else if (kCurrentParam == "--enableinputdebug")
                {
                    m_bInputDebugMode = true;
                    GUILOGMESSAGE("enabling debug-mode for input\n");
                }
                else if (kCurrentParam == "--inputcalibration")
                {
                    m_bInputCalibration = true;
                    GUILOGMESSAGE("enabling input-calibration\n");
                }
                else
                {
                    PrintUsage();

                    GUILOG(GUI_TRACE_WARNING, "ignoring unknown option: " + kCurrentParam + "\n");
                }
            }
        }
#endif
    }

    void CStreamRuntimeBase::PrintUsage()
    {
#ifdef STREAMRUNTIME_USE_CLI
        if (false == m_bUsagePrinted)
        {
            GUILOGMESSAGE("Usage:  StreamRuntime [options]\n");
            GUILOGMESSAGE("Options:\n");
            GUILOGMESSAGE("     --help: print this message\n");
            GUILOGMESSAGE("     --config <filename>: specify configuration-file to use\n");
            GUILOGMESSAGE("     --screenwidth <width>: specify width of screen\n");
            GUILOGMESSAGE("     --screenheight <height>: specify height of screen\n");
            GUILOGMESSAGE("     --keyboard <keyboard-device>: specify keyboard-device to use\n");
            GUILOGMESSAGE("     --mouse <mouse-device>: specify mouse-device to use\n");
            GUILOGMESSAGE("     --touch <touch-device>: specify touch-device to use\n");
            GUILOGMESSAGE("     --remote <remote-device>: specify remote-device to use\n");
            GUILOGMESSAGE("     --touchsizex <size>: specify horizontal size of touch-device (negative value inverts axis)\n");
            GUILOGMESSAGE("     --touchsizey <size>: specify vertical size of touch-device (negative value inverts axis)\n");
            GUILOGMESSAGE("     --touchoffsetx <offset>: specify horizontal offset of touch\n");
            GUILOGMESSAGE("     --touchoffsety <offset>: specify vertical offset of touch\n");
            GUILOGMESSAGE("     --resourcefile <resource-file>: specify resource-file to use\n");
            GUILOGMESSAGE("     --resourcepath <resource-path>: specify path for resources\n");
            GUILOGMESSAGE("     --license <license>: specify license-key as a string\n");
            GUILOGMESSAGE("     --licensefile <license-file>: specify license-file containing key\n");
            GUILOGMESSAGE("     --enableinputdebug: enable debug-mode for input\n");
            GUILOGMESSAGE("     --inputcalibration: calibrate input\n");
            m_bUsagePrinted = true;
        }
#endif
    }

    eC_Bool CStreamRuntimeBase::LoadConfiguration()
    {
        if (m_bUsagePrinted)
            return false;
        else
        {
            m_pkConfigurator = new Configurator();
            return GETRUNTIMECONFIG.LoadConfiguration(GetConfigurationFile());
        }
    }

    eC_Bool CStreamRuntimeBase::LoadLicenseFile()
    {
#ifdef STREAMRUNTIME_USE_CLI
        // no license active
        if (!CGUI::IsLicenseActive())
        {
            // try binary-folder first
            eC_String kLicenseFile;
            GETFILESYS.MakeNormalizedPlatformPath(GETFILESYS.GetExecutablePath() + "GuilianiLicense.key", kLicenseFile);
            if (GETFILESYS.CheckIfFileExists(kLicenseFile))
            {
                CGUI::LoadGuilianiLicenseKey(kLicenseFile);
                return true;
            }

            GETFILESYS.MakeNormalizedPlatformPath(GETFILESYS.GetExecutablePath() + "../GuilianiLicense.key", kLicenseFile);
            if (GETFILESYS.CheckIfFileExists(kLicenseFile))
            {
                CGUI::LoadGuilianiLicenseKey(kLicenseFile);
                return true;
            }
        }
#endif
        return false;
    }

    void CStreamRuntimeBase::CreateGUI()
    {
        if (GETRUNTIMECONFIG.IsProfilingActive())
        {
            GETPROFILER.SetActive(true);
            GETPROFILER.SetDisplayActive(true);
            GETPROFILER.SetMemoryAvailable(GETRUNTIMECONFIG.GetMemoryAvailable());
            GETPROFILER.SetMemoryThresholds(GETRUNTIMECONFIG.GetMemoryUsageWarning(), GETRUNTIMECONFIG.GetMemoryUsageAlert());
        }

        // set the configurator
        CStreamRuntimeGUI::SetConfigurator(m_pkConfigurator);

#ifdef STREAMRUNTIME_USE_CLI
        if (m_bInputCalibration)
        {
            eC_UInt uiWidth = GETGFX.GetPhysicalScreenWidth();
            eC_UInt uiHeight = GETGFX.GetPhysicalScreenHeight();

            CGUIInputCalibration* pkCalibration = new CGUIInputCalibration(uiWidth, uiHeight);
            pkCalibration->Run();

            eC_Int iSizeX = 0;
            eC_Int iSizeY = 0;
            eC_Int iOffsetX = 0;
            eC_Int iOffsetY = 0;

            pkCalibration->GetSize(iSizeX, iSizeY);
            pkCalibration->GetOffset(iOffsetX, iOffsetY);

            GETINPUTMEDIA.SetSize(iSizeX, iSizeY);
            GETINPUTMEDIA.SetOffset(iOffsetX, iOffsetY);

            delete pkCalibration;
        }
#endif

#ifdef STREAMRUNTIME_USE_CLI
        // set debug-mode for original input-device
        if (m_bInputDebugMode)
            GETINPUTMEDIA.SetDebugMode(true);
#endif

        // Create the root GUI object derived from CGUI
        CMyGUI kMyGui(
            eC_FromInt(0),
            eC_FromInt(0),
            eC_FromInt(GetScreenWidth()),
            eC_FromInt(GetScreenHeight()),
            NO_HANDLE);

        UpdateWindowTitle();

#ifdef STREAMRUNTIME_USE_CLI
        // activate cursor for mouse
        if (!GetMouseDevice().IsEmpty())
            kMyGui.EnableMouseCursor();
#endif

        // Now start the GUI. This will return when the application quits.
        kMyGui.Run();
    }

    void CStreamRuntimeBase::DeInit()
    {
#ifdef GUILIANI_LEAK_DETECTION
        LEAK_DETECTION.ShowResults();
        // Comment in to write leak detection output to a file
        //LEAK_DETECTION.WriteResultsToFile("StreamRuntime_MemoryLeaks.log");
#endif
    }

    void CStreamRuntimeBase::DestructWrapperClasses()
    {
        CGUIInputMedia::DeleteInstance();
        CSndWrap::DeleteInstance();
        CFntWrap::DeleteInstance();
        CGfxWrap::DeleteInstance();
        CGfxEnv::DeleteInstance();
        CGUIImageLoader::DeleteInstance();
    }

    void CStreamRuntimeBase::UpdateWindowTitle()
    {
        // display version and license-type in window-titlebar
        eC_String kText = "Guiliani " + CGUI::GetVersionString() + " (" + CGUI::GetPlatformString() + "/" + GETGFX.GetWrapperName() + ") -" + CGUI::GetLicenseString();
        GETGFX.SetWindowCaption(kText);
    }

    Configurator& CStreamRuntimeBase::GetRuntimeConfig() const
    {
        if (NULL != m_pkConfigurator)
            return *m_pkConfigurator;
        else
            GUI_THROW(0);
    }

    eC_String CStreamRuntimeBase::GetConfigurationFile() const
    {
        return m_kConfigurationFile;
    }

    eC_Int CStreamRuntimeBase::GetScreenWidth() const
    {
#ifdef GUILIANI_STREAM_GUI
        if (m_iScreenWidth == -1)
            return GETRUNTIMECONFIG.GetScreenWidth();
        else
#endif
            return m_iScreenWidth;
    }

    eC_Int CStreamRuntimeBase::GetScreenHeight() const
    {
#ifdef GUILIANI_STREAM_GUI
        if (m_iScreenHeight == -1)
            return GETRUNTIMECONFIG.GetScreenHeight();
        else
#endif
            return m_iScreenHeight;
    }

    eC_Bool CStreamRuntimeBase::IsWindowResizable() const
    {
#ifdef GUILIANI_STREAM_GUI
        return GETRUNTIMECONFIG.IsWindowResizable();
#else
        return false;
#endif
    }

    eC_String CStreamRuntimeBase::GetKeyboardDevice() const
    {
        return m_kKeyboardDevice;
    }

    eC_String CStreamRuntimeBase::GetRemoteDevice() const
    {
        return m_kRemoteDevice;
    }

    eC_String CStreamRuntimeBase::GetMouseDevice() const
    {
        return m_kMouseDevice;
    }

    eC_String CStreamRuntimeBase::GetTouchDevice() const
    {
        return m_kTouchDevice;
    }

    eC_Int CStreamRuntimeBase::GetTouchSizeX() const
    {
        return m_iTouchSizeX;
    }

    eC_Int CStreamRuntimeBase::GetTouchSizeY() const
    {
        return m_iTouchSizeY;
    }

    eC_Int CStreamRuntimeBase::GetTouchOffsetX() const
    {
        return m_iTouchOffsetX;
    }

    eC_Int CStreamRuntimeBase::GetTouchOffsetY() const
    {
        return m_iTouchOffsetY;
    }

    eC_Bool CStreamRuntimeBase::IsInputDebugModeEnabled() const
    {
        return m_bInputDebugMode;
    }
}
