/*
 * 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/Add.h"
#include "syncml/core/Item.h"
#include "syncml/core/Source.h"
#include "commontypes.h"
#include "Errors.h"
#include "identifiers.h"

#include "executionqueue/IExecutionQueue.h"
#include "Logger/Logger.h"
#include "Logger/LoggerMacroses.h"
#include "treemanager/MOTreeAddCommand.h"
#include "treemanager/IMOTreeManager.h"

#include "serverexchange/firmware/FUMODefines.h"

static const char * const c_LogName = "MOTreeAddCommand";

#define LOG_INFO_ NS_Logging::FunctionNameLogHelper(__FUNCTION__, NS_Logging::e_info).Log

using namespace NS_DM_Client;


MOTreeAddCommand::MOTreeAddCommand(ProfileComponentsHolder* prholder,
    AddPtr& cmd, const String& msgID, const char* serverId)
    : MOTreeItemisedCommand(prholder, (ItemizedCommandPtr&)cmd, msgID, serverId), m_AddCommand(cmd)
{
    if(cmd.get() == NULL)
    {
        GDLWARN("cmd is NULL");
    }
}


MOTreeAddCommand::~MOTreeAddCommand(void)
{
}


bool MOTreeAddCommand::Execute()
{
    GDLINFO("FUNCTION STARTED");

    bool res = m_pProfile && m_AddCommand.get();
    if (res)
    {
        res = false;
        m_resCode = performOperation();
        res = InvokeResult();
    }
    else
    {
        GDLERROR("component holder or command instanse not valid");
    }

    GDLINFO("FUNCTION END. Res: %d", res);
    return res;
}


StatusCode MOTreeAddCommand::performOperation()
{
    StatusCode res = e_Ok;
    Funambol::ArrayList* items = m_AddCommand->getItems();
    if (items)
    {
        IMOTreeManager* treeManager = m_pProfile ? m_pProfile->GetMOTreeManager() : 0;
        if (!treeManager)
        {
            GDLERROR("can't get tree manager instance");
            return e_Failed;
        }

        if (notifyProvisionUpdate(e_Add, e_sessionStart, e_Ok))
        {
            if (treeManager->StartTransaction() == e_Ok)
            {
                if ((res = processAddOnMultipleItems(items, treeManager)) == e_Ok)
                {
                    if ((res = processAddOnFUMOMultipleItems(items, treeManager)) == e_Ok)
                    {
                        if ((res = treeManager->Commit()) != e_Ok)
                        {
                            GDLERROR("commit for successfull addition failed");
                        }
                    }
                }

                if (res != e_Ok)
                {
                    if (!treeManager->Rollback())
                    {
                        GDLERROR("rollback for unsuccessfull addition failed");
                    }
                }
            }
            else
            {
                GDLERROR("can't start transaction");
                res = e_Failed;
            }
        }
        else
        {
            GDLERROR("NotifyProvisionUpdate failed");
            res = e_Failed;
        }

        if (!notifyProvisionUpdate(e_Add, e_sessionEnd, res))
        {
            GDLERROR("NotifyProvisionUpdate failed");
        }
    }
    else
    {
        GDLERROR("get items from ItemizedCommand failed");
    }
    return res;
}

StatusCode MOTreeAddCommand::perocessAddOnFUMO(const char *uri, Funambol::Item &item)
{
	StatusCode res = e_Ok;
    Funambol::Meta *pMeta = item.getMeta();
    if (pMeta && pMeta->getType())
    {
        if (!strcmp(pMeta->getType(), NODE_TYPE_FUMO))
        {
            Funambol::StringBuffer state_uri(uri);
            if (uri)
            {
                if (uri[strlen(uri)-1] != '/')
                {
                    state_uri.append("/");
                }
                state_uri.append("State");
            }

            // add Status node
            Funambol::Item itemStatus;
            Funambol::Target target(state_uri.c_str());
            Funambol::Meta meta;
            meta.setType("text/plain");
            meta.setFormat("int");
            itemStatus.setTarget(&target);
            itemStatus.setMeta(&meta);

            char buffer[16];
            memset(buffer, '\0', 16);
            sprintf(buffer, "%d", NS_Communication::FS_NO_PENDING_OPERATIONS);
            Funambol::ComplexData data(buffer);
            itemStatus.setData(&data);

            res = m_pProfile->GetMOTreeManager()->Add(state_uri.c_str(), itemStatus, NULL);
            GDLDEBUG("adding Status node finished with status %d", res);
        }
    }
    else
    {
        GDLERROR("perocessAddOnFUMO: no meta in item. Failed to add item");
    }

    return res;
}

StatusCode MOTreeAddCommand::processAddOnMultipleItems(Funambol::ArrayList* items, IMOTreeManager* treeManager)
{
    StatusCode res = e_Failed;

    Funambol::Item* item = 0;
    int count = items->size();

    for (int i = 0; i < count; ++i)
    {
        if ((item = static_cast<Funambol::Item*> ((*items)[i])) != 0)
        {
            if (e_Ok != (res = treeManager->Add(item->getTarget()->getLocURI(), *item, m_serverID)))
            {
                GDLDEBUG("add item to MO Tree Manager failed");
                break;
            }
        }
        else
        {
            GDLDEBUG("casting to Funambol::Item failed");
            res = e_Failed;
            break;
        }
    }

    return res;
}

StatusCode MOTreeAddCommand::processAddOnFUMOMultipleItems(Funambol::ArrayList* items, IMOTreeManager* treeManager)
{
    StatusCode res = e_Failed;

    Funambol::Item* item = 0;
    int count = items->size();
    URI uri;

    for (int i = 0; i < count; ++i)
    {
        if ((item = static_cast<Funambol::Item*> ((*items)[i])) != 0)
        {
            uri = item->getTarget()->getLocURI();
            res = perocessAddOnFUMO(uri.c_str(), *item);
            if (res != e_Ok)
            {
                GDLERROR("processAddOnFUMO failed on node: %s", uri.c_str());
                break;
            }
        }
        else
        {
            GDLERROR("casting to Funambol::Item failed");
            res = e_Failed;
            break;
        }
    }

    return res;
}

Funambol::ArrayList* MOTreeAddCommand::getListOfItems()
{
    return m_AddCommand->getItems();
}

