/*
* Copyright 2009 Funambol, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

#include "daemon/DaemonEngine.h"
#include "common/Buffer.h"
#include "DataStorage/IDataStorage.h"
#include "base/util/StringBuffer.h"
#include "daemon/Configuration.h"
#include "daemon/Profile.h"

#include "Logger/LoggerMacroses.h"
#include "ClientAdapter/ClientAdapterStub.h"

#include "Errors.h"

#include "daemon/config_def.h"

#include <memory>

using namespace NS_DM_Client;
using namespace NS_DM_Client::NS_Daemon;

static const char c_LoggerInstanceName[] = "DaemonEngine";

IDaemonEngine*  IDaemonEngine::GetInstance()
{
    static IDaemonEngine* engine = new(std::nothrow) DaemonEngine();
    return engine;
}


IDaemonEngine::IDaemonEngine()
{

}


DaemonEngine::DaemonEngine()
:
m_Started(false),
m_logger(NS_Logging::GetLogger(c_LoggerInstanceName)),
m_ConfStorage(0),
m_conf(m_logger),
m_clientAdapterStub(0)
{
LINFO("Enter");
LINFO("Exit");
}


DaemonEngine::~DaemonEngine()
{
LINFO("Enter");

    if (isRunning())
    {
        LWARN("Still running while being destructed. ");
        Stop();
    }

    if (m_ConfStorage)
    {
        m_ConfStorage->Release();
        m_ConfStorage = NULL;
    }

    if (m_clientAdapterStub)
    {
        delete m_clientAdapterStub;
        m_clientAdapterStub = NULL;
    }

LINFO("Exit");
}

bool DaemonEngine::Start()
{
LINFO("Enter");

    if (isRunning())
    {
        LWARN("Already running. ");
        return true;
    }

    NS_DM_Client::NS_DataStorage::IConfigurationStorage* pCS = getConfigurationStorage();
    if (!pCS)
    {
        LERROR("Failed to create ConfigurationStorage instance. ");
        return false;
    }
    Buffer buf;
    if (!pCS->LoadConfiguration(buf))
    {
        LERROR("Failed to load configuration. ");
        return false;
    }

    const size_t configSize = buf.Size();
    if (buf.GetPointer() == NULL || configSize == 0)
    {
        LERROR("Configuration is empty. ");
        return false;
    }

    LDEBUG("Configuration size: '%d'. ", configSize);
    String config(static_cast<const char*>(buf.GetPointer()), configSize);
    StringBuffer configData(config.c_str());
    if (!m_conf.Read(configData))
    {
        LERROR("Failed to read configuration. ");
        return false;
    }

    if (!m_clientAdapterStub)
    {
        do
        {
            std::auto_ptr<ClientAdapterStub> cas(new(std::nothrow) ClientAdapterStub(m_conf));
            if (cas.get() != NULL)
            {
                LDEBUG("ClientAdapaterStub=%p", cas.get());

                StringMap settings;
                String loggerInstance;
                readConfigurationForClientAdapter(configData, settings, loggerInstance);
                const bool initResult = cas->Init(settings);
                LDEBUG("ClientAdapaterStub init result=%d", initResult);
                if (!initResult)
                {
                    break;
                }

                const bool startResult = cas->Start();
                LDEBUG("ClientAdapaterStub started=%d", startResult);
                if (!startResult)
                {
                    break;
                }

                m_clientAdapterStub = cas.get();
                cas.release();
            }
            else
            {
                LERROR("Failed to create ClientAdapaterStub");
            }

        }while(false);
    }

    m_Started = true;
LINFO("Exit");
    return isRunning();
}

bool DaemonEngine::Stop()
{
LINFO("Enter");

    if (!isRunning())
    {
        LWARN("Asked to stop while not running. ");
        return true;
    }

    if (m_clientAdapterStub)
    {
        LDEBUG("Try to stop ClientAdapaterStub");
        const bool stopResult = m_clientAdapterStub->Stop();
        LDEBUG("ClientAdapaterStub stopped=%d", stopResult);
    }

    for(int i = 0; i < m_conf.GetProfilesCount(); ++i)
    {
        Profile* p = m_conf.GetProfile(i);
        if (p->IsEnabled())
        {
            LDEBUG("Try to stop profile '%s'", p->GetName().c_str());
            bool res = p->Enable(false);
            LINFO("Profile %s Enable=false status bRes=%d. ", p->GetName().c_str(), res);
        }
    }
    m_Started = false;
LINFO("Exit");

    return true;
}

void DaemonEngine::Release()
{
LINFO("Enter");
    delete this;
LINFO("Exit");
}

StatusCode DaemonEngine::HandleClientRequest(const UIMessageType& type, const Buffer& input, StatusCode& response_res, Buffer& output)
{
LINFO("Enter: type=%d",type);

    StatusCode res = e_Failed;
    response_res = e_Failed;
    switch(type)
    {
        case e_GetTreeValue:
        {
            res = execute_RequestGetValueFromTreeCommand(input, response_res, output);
            break;
        }
        case e_RequestUserInitiatedFirmwareUpdate:
        {
            res = execute_RequestFirmwareUpdate(true, input);
            break;
        }
        case e_RequestDeviceInitiatedFirmwareUpdate:
        {
            res = execute_RequestFirmwareUpdate(false, input);
            break;
        }
        case e_GetProfiles:
        {
            res = execute_RequestGetProfiles(input, response_res, output);
            break;
        }
        case e_SetProfileState:
        {
            res = execute_RequestSetProfileState(input, response_res, output);
            break;
        }
        default:
        {
            LERROR("no supported client request type");
            response_res = e_ForbiddenCommand;
            res = e_ForbiddenCommand;
        }
    };
    response_res = res;
LINFO("Exit Res:%d", res);
    return res;
}

bool DaemonEngine::isRunning() const
{
LINFO("Enter");
LINFO("Exit");
    return m_Started;
}

NS_DM_Client::NS_DataStorage::IConfigurationStorage*   DaemonEngine::getConfigurationStorage()
{
LINFO("Enter");

    if (!m_ConfStorage)
    {
        m_ConfStorage = NS_DM_Client::NS_DataStorage::CreateConfigurationStorage();
    }
LINFO("Exit");
    return m_ConfStorage;
}

void DaemonEngine::readConfigurationForClientAdapter(NS_Daemon::StringBuffer& configData, StringMap& settings, String& loggerInstance)
{
LINFO("Enter");

    NS_Daemon::StringBuffer ClientAdapterTag;
    if (m_conf.S_getTagInfo(configData, NS_Configuration::c_ClientAdapterTag, ClientAdapterTag))
    {
        if (!m_conf.S_readSettings(ClientAdapterTag, settings))
        {
            LWARN("failed to read settings for ClientAdapter from configuration");
        }
        NS_Daemon::StringBuffer loggerInstanceStringBuffer;
        if (!m_conf.S_getAttribute(ClientAdapterTag, NS_Configuration::c_LoggerInstanceTag, loggerInstanceStringBuffer))
        {
            LWARN("failed to read logger instance name for ClientAdapter from configuration");
        }
    }

LINFO("Exit");
}
