/*
 * 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 "treemanager/MOTreeReplaceCommand.h"
#include "treemanager/IMOTreeManager.h"

#include "syncml/core/Replace.h"
#include "syncml/core/Item.h"
#include "syncml/core/Source.h"

#include "commontypes.h"
#include "Errors.h"

#include "executionqueue/IExecutionQueue.h"
#include "Logger/Logger.h"
#include "Logger/LoggerMacroses.h"

const char* const c_LogName = "MOTreeReplaceCommand";

const char* const c_ReplaceCommandLog = "MOTreeReplaceCommand";

const char* const c_PropertyDelimiter = "?prop=";

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

using namespace NS_DM_Client;


MOTreeReplaceCommand::MOTreeReplaceCommand(ProfileComponentsHolder* prholder,
										   ReplacePtr& cmd,
										   const String& msgID,
								            const char* serverId)
    : MOTreeItemisedCommand(prholder, cmd, msgID, serverId), m_ReplaceCommand(cmd)
{
    if(cmd.get() == NULL)
    {
        GDLWARN("cmd is NULL");
    }
}


MOTreeReplaceCommand::~MOTreeReplaceCommand(void)
{
}


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

    bool res = m_pProfile && m_ReplaceCommand.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 MOTreeReplaceCommand::performOperation()
{
    StatusCode res = e_Ok;
    Funambol::ArrayList* items = m_ReplaceCommand->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_Replace, e_sessionStart, e_Ok))
        {
            if (treeManager->StartTransaction() == e_Ok)
            {
                if ((res = processReplaceOnMultipleItems(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_Replace, e_sessionEnd, res))
        {
            GDLERROR("NotifyProvisionUpdate failed");
        }
    }
    else
    {
        GDLERROR("get items from ItemizedCommand failed");
    }

    return res;
}

StatusCode MOTreeReplaceCommand::processReplaceOnMultipleItems(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)
        {
            if (!item->getTarget())
            {
                GDLERROR("Item in Replace command has no Target node");
                res = e_CommandFailed;
                break;
            }

            uri = item->getTarget()->getLocURI();
            URI res_uri = uri;
            // check if uri represent property
            size_t pos = uri.find(c_PropertyDelimiter);
            URI property_name;
            String property_value;
            if (pos != URI::npos)
            {   // we have property request
                property_value = item->getData()->getData();
                res_uri = uri.substr(0, pos);
                property_name = uri.substr(pos + strlen(c_PropertyDelimiter));
                if ((res = m_pProfile->GetMOTreeManager()->ReplacePropertyValue(res_uri, property_name, property_value, m_serverID)) != e_Ok)
                {
                    GDLERROR("replace item property from MO Tree Manager failed");
                    break;
                }
            }
            else
            {
                if ( (res = m_pProfile->GetMOTreeManager()->Replace(uri, *item, m_serverID)) != e_Ok)
                {
                    GDLERROR("replace item on MO Tree Manager failed");
                    break;
                }
            }
        }
        else
        {
            GDLDEBUG("casting to Funambol::Item failed");
            res = e_Failed;
            break;
        }
    }

    return res;
}

Funambol::ArrayList* MOTreeReplaceCommand::getListOfItems()
{
    return m_ReplaceCommand->getItems();
}

