/*
 * 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 <syncml/core/TagNames.h>
#include <Utils.h>
#include "treemanager/TreeLocations.h"
#include "serverexchange/wrappers/SCommandFactory.h"
#include "serverexchange/wrappers/SCommandAdapter.h"
#include "serverexchange/wrappers/SAlertCommand.h"
#include "serverexchange/wrappers/SReplaceCommand.h"
#include "serverexchange/wrappers/SResultsCommand.h"
#include "serverexchange/wrappers/SStatusCommand.h"
#include <Logger/LoggerMacroses.h>

const char* const c_LogName = "SCommandFactory";

using namespace NS_DM_Client;
using namespace NS_DM_Client::NS_SyncMLCommand;


static void addItem(Funambol::ArrayList & items, const char * uri, const char * value)
{
    Funambol::ComplexData complexData(value);

    Funambol::Meta meta;
    meta.setFormat("chr");
    meta.setType(TEXT_PLAIN_ENCODING);

    Funambol::Source source(uri);
    Funambol::Item item(NULL, &source, &meta, &complexData, false);

    items.add(item);
}


SAlertCommandPtr SCommandFactory::CreateAlert(const AlertCode alertCode)
{
    return SAlertCommandPtr(new(std::nothrow) SAlertCommand(alertCode));
}


SAlertCommandPtr SCommandFactory::CreateAlertOnFWDownload(int result, ExecPtr &exec, const char *alertType)
{
    SAlertCommand *pAlert = new(std::nothrow) SAlertCommand(AC_GENERIC_ALERT);
    if(pAlert == (SAlertCommand*)NULL)
    {
        GDLWARN("new SAlertCommand");
    }

    pAlert->Prepare();
    if (exec.get())
    {
        Funambol::Alert *pa = pAlert->GetAlert();
        if (pa)
        {
            pa->setCorrelator(exec->getCorrelator());

            char buffer[16];
            memset(buffer, '0', 16);
            Funambol::Item       item;
            Funambol::ArrayList *items = exec->getItems();
            if (items && items->size())
            {
                Funambol::Item* pFirstItem = (Funambol::Item*)items->get(0);
                const char *srcuri = NULL;
                if (pFirstItem && pFirstItem->getTarget() )
                    srcuri = pFirstItem->getTarget()->getLocURI();

                if (srcuri)
                {
                    Funambol::Source source(srcuri);
                    item.setSource(&source);
                }
                __sprintf(buffer, "%d", result);
            }
            else
            {
                __sprintf(buffer, "%d", e_Failed);
            }

            Funambol::Meta meta;
            meta.setType(alertType);
            item.setMeta(&meta);

            Funambol::ComplexData data(buffer);
            item.setData(&data);
            pAlert->AddItem(item);
        }
    }
    else
    {
        GDLWARN("exec is NULL");
    }

    return SAlertCommandPtr(pAlert);
}

SAlertCommandPtr SCommandFactory::CreateGenericAlert(const char *srcuri, const char *reqtype, int data)
{
    return CreateAlert(AC_GENERIC_ALERT, srcuri, reqtype, data);
}

SAlertCommandPtr SCommandFactory::CreateAlert(const AlertCode acode, const char *srcuri, const char *atype, int data)
{
    SAlertCommand *pAlert = new(std::nothrow) SAlertCommand(acode);
    if(pAlert == (SAlertCommand*)NULL)
    {
        GDLWARN("new SAlertCommand");
    }

    pAlert->Prepare();

    Funambol::Item item;
    if (srcuri) {
        Funambol::Source source(srcuri);
        item.setSource(&source);
    }

    if (atype) {
        Funambol::Meta meta;
        meta.setFormat("text/plain");
        meta.setType(atype);
        item.setMeta(&meta);
    }
    
    if (data) {
        char buffer[64];
        memset(buffer, '\0', 64);
        __sprintf(buffer, "%d", data);
        Funambol::ComplexData data(buffer);
        item.setData(&data);
    }
    pAlert->AddItem(item);

    return SAlertCommandPtr(pAlert);
}


SStatusCommandPtr SCommandFactory::CreateStatus(StatusCode data)
{
    return SStatusCommandPtr(new(std::nothrow) SStatusCommand(data));
}


SStatusCommandPtr SCommandFactory::CreateStatus(StatusCode data, Funambol::AbstractCommand &cmd)
{
    SStatusCommand *pStatusCmd = new(std::nothrow) SStatusCommand(data);
    if(pStatusCmd == (SStatusCommand*)NULL)
    {
        GDLWARN("new SStatusCommand");
    }

    pStatusCmd->SetCmd(cmd.getName());
    if (cmd.getCmdID())
        pStatusCmd->SetCmdRef(cmd.getCmdID()->getCmdID());

    return SStatusCommandPtr(pStatusCmd);
}


SStatusCommandPtr SCommandFactory::CreateStatus(StatusCode data, Funambol::ItemizedCommand &cmd)
{
    SStatusCommand *pStatusCmd = new(std::nothrow) SStatusCommand(data);
    if(pStatusCmd == (SStatusCommand*)NULL)
    {
        GDLWARN("new SStatusCommand");
    }

    pStatusCmd->SetCmd(cmd.getName());
    if (cmd.getCmdID())
        pStatusCmd->SetCmdRef(cmd.getCmdID()->getCmdID());

    pStatusCmd->Prepare();

    // insert TargetRef filed into the Status command
    if (cmd.getItems())
    {
        Funambol::ArrayList &arrItems = *cmd.getItems();
        if (arrItems.size() == 1)
        {
            Funambol::Item *pItem = static_cast<Funambol::Item *>(arrItems[0]);
            if (pItem && pItem->getTarget() && pItem->getTarget()->getLocURI())
            {   
                Funambol::ArrayList arrTargets;
                Funambol::TargetRef ref(pItem->getTarget()->getLocURI());
                arrTargets.add(ref);
                pStatusCmd->Internal()->setTargetRef(&arrTargets);
            }
        }
    }
    
    return SStatusCommandPtr(pStatusCmd);
}


SResultsCommandPtr SCommandFactory::CreateResult(Funambol::ItemizedCommand &cmd, Funambol::ArrayList &results, const char *msgref)
{
    SResultsCommand *pResults = new(std::nothrow) SResultsCommand();
    if(pResults == (SResultsCommand*)NULL)
    {
        GDLWARN("new SResultsCommand");
    }

    if (msgref)
        pResults->SetMsgRef(msgref);

    if (cmd.getCmdID())
        pResults->SetCmdRef(cmd.getCmdID()->getCmdID());

    for (int i=0; i<results.size(); ++i)
    {
        Funambol::Item *pItem = (Funambol::Item*)results.get(i);
        if (pItem)
        {
            pResults->AddResult(pItem->getTarget()  ?  pItem->getTarget()->getLocURI() : NULL,
                                pItem->getData()    ?  pItem->getData()->getData()     : NULL,
                                pItem->getMeta()    ?  pItem->getMeta()->getFormat()   : NULL,
                                pItem->getMeta()    ?  pItem->getMeta()->getType()     : NULL);
        }
    }

    return SResultsCommandPtr(pResults);
}


SCommandPtr SCommandFactory::CreateReplaceDevInf(Funambol::DevInf & devInf)
{
    SReplaceCommand *replace = new(std::nothrow) SReplaceCommand();
    if(replace == (SReplaceCommand*)NULL)
    {
        GDLWARN("new SReplaceCommand");
    }

    replace->Prepare();

    Funambol::Replace *pReplace = replace->GetReplace();
    if (pReplace)
    {
        Funambol::ArrayList     items;
        addItem(items, DI_DEVID, devInf.getDevID());
        addItem(items, DI_DMV,   devInf.getDmV());
        addItem(items, DI_LANG,  devInf.getLang());
        addItem(items, DI_MAN,   devInf.getMan());
        addItem(items, DI_MOD,   devInf.getMod());

        pReplace->setItems(&items);
    }

    return SCommandPtr(replace);
}
