/*
* 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 "MOTreeManagerTransactionData.h"

#include "daemon/ProfileComponentsHolder.h"

#include "Node.h"

namespace NS_DM_Client
{
MOTreeManagerTransactionData::MOTreeManagerTransactionData()
{
}
//-------------------------------------------------------------------------------------------
MOTreeManagerTransactionData::~MOTreeManagerTransactionData()
{
}
//-------------------------------------------------------------------------------------------
bool MOTreeManagerTransactionData::BackupAdd(const URI& uri, bool needSerialize)
{
    // before - nothing to add

    // after - add info about added node (only name)
    Node tree_node(uri, m_dataStorage);
    return backupNode(tree_node, "Add" , 0, needSerialize);
}
//-------------------------------------------------------------------------------------------
bool MOTreeManagerTransactionData::backupDeleteSubnodes(Node& parent)
{
    bool res = true;
    String value;
    Node::ChildrenPaths childs;
    parent.GetChildren(childs);
    for (Node::ChildrenPaths::iterator i = childs.begin(); i != childs.end(); ++i)
    {
        String node_path = parent.GetPath() + "/" + (*i);
        Node tree_node(node_path, m_dataStorage);
        res = backupNode(tree_node, "Delete");

        if (!tree_node.IsLeaf())
        {
            // need recursivelly store all deleted nodes
            res = backupDeleteSubnodes(tree_node);
        }
    }
    return res;
}
//-------------------------------------------------------------------------------------------
bool MOTreeManagerTransactionData::BackupDelete(const URI& uri)
{
    bool res = true;
    // before - deleted node and all sybnodes
    Node tree_node(uri, m_dataStorage);
    res = backupNode(tree_node, "Delete");
    if (!tree_node.IsLeaf())
    {
        // need recursivelly store all deleted nodes
        res = backupDeleteSubnodes(tree_node);
    }

    // after - nothing to add
    return res;
}
//-------------------------------------------------------------------------------------------
bool MOTreeManagerTransactionData::BackupReplace(const URI& uri, const String& rep_value, bool needSerialize)
{
    // store node with original content and changed content
    Node tree_node(uri, m_dataStorage);
    String new_value = rep_value;
    return backupNode(tree_node, "Replace", &new_value, needSerialize);
}
//-------------------------------------------------------------------------------------------
struct BackupReplacePropertyAdditionalData
{
    String m_prop_name;
    String m_prop_value;
};

bool MOTreeManagerTransactionData::BackupReplaceProperty(const URI& uri, const String& property_name, const String& rep_value)
{
    // store property with original content and changed content
    Node tree_node(uri, m_dataStorage);
    BackupReplacePropertyAdditionalData data;
    data.m_prop_name = property_name;
    data.m_prop_value = rep_value;
    return backupNode(tree_node, "ReplaceProperty", &data);
}
//-------------------------------------------------------------------------------------------
bool MOTreeManagerTransactionData::BackupCopy(const URI& source, const URI& dest)
{
    Node tree_node_src(source, m_dataStorage);
    Node tree_node_dest(dest, m_dataStorage);

    String value;
    tree_node_src.GetContent(value);

    return backupNode(tree_node_dest, "Copy", &value);
}
//-------------------------------------------------------------------------------------------
TransactionDataElement* MOTreeManagerTransactionData::getFirstTransactionElement()
{   // walk from the end to begin of the vector
    m_cucle_index = 0;
    if (m_data.empty())
    {
        return 0;
    }
    m_cucle_index = m_data.size() - 1;
    return &(m_data[m_cucle_index--]);
}
//-------------------------------------------------------------------------------------------
TransactionDataElement* MOTreeManagerTransactionData::getNextTransactionElement()
{   // walk from the end to begin of the vector
    if (m_data.empty())
    {
        return 0;
    }
    if (m_cucle_index == (std::vector<TransactionDataElement>::size_type)(0 - 1))
    {
        return 0;
    }
    return &(m_data[m_cucle_index--]);
}
//-------------------------------------------------------------------------------------------
bool MOTreeManagerTransactionData::rollbackAdd(const TransactionDataElement* data)
{
    String added_node_name = data->m_after.m_name;
    Node tree_node(added_node_name, m_dataStorage);
    return tree_node.Delete();
}
//-------------------------------------------------------------------------------------------
bool MOTreeManagerTransactionData::rollbackDelete(const TransactionDataElement* data)
{
    String node_name = data->m_before.m_name;
    Node tree_node(node_name, m_dataStorage);

    std::vector<TransactionMOProperty> props = data->m_before.m_properties;
    for (std::vector<TransactionMOProperty>::iterator i = props.begin(); i != props.end(); ++i)
    {
        if (i->m_name.compare(S_permanentFile) == 0)
        {
            tree_node.SetPermanent();
        }
        else
        {
            Property prop;
            if (GetPropertyByName(i->m_name, prop))
            {
                tree_node.SetProperty(prop, i->m_value);
            }
            else
            {
                return false;
            }
        }
    }
    if (tree_node.IsLeaf())
    {
        String node_value = data->m_before.m_value;
        tree_node.SetContent(node_value);
    }
    return true;
}
//-------------------------------------------------------------------------------------------
bool MOTreeManagerTransactionData::rollbackReplace(const TransactionDataElement* data)
{
    String node_name = data->m_before.m_name;
    String node_value;

    Node tree_node(node_name, m_dataStorage);
    tree_node.SetContent(data->m_before.m_value);

    return true;
}
//-------------------------------------------------------------------------------------------
bool MOTreeManagerTransactionData::rollbackReplaceProperty(const TransactionDataElement* data)
{
    Node tree_node(data->m_before.m_name, m_dataStorage);

    Property property;
    GetPropertyByName(data->m_before.m_properties[0].m_name, property);
    tree_node.SetProperty(property, data->m_before.m_properties[0].m_value);

    return true;
}
//-------------------------------------------------------------------------------------------
bool MOTreeManagerTransactionData::rollbackCopy(const TransactionDataElement* data)
{
    String node_name = data->m_before.m_name;
    String node_value;

    Node tree_node(node_name, m_dataStorage);
    tree_node.SetContent(data->m_before.m_value);

    return true;
}
//-------------------------------------------------------------------------------------------
void MOTreeManagerTransactionData::clearData()
{
    m_data.clear();
}
//-------------------------------------------------------------------------------------------
bool MOTreeManagerTransactionData::backupNode(Node& node, const String& operation, void* additional_data, bool needSerialize)
{
    String value;
    TransactionDataElement data;
    setDataElementBackupType(operation, data);

    TransactionMONode backup_node;
    backup_node.m_name = node.GetPath();
    if (operation.compare("Add") != 0)
    {
        if (node.IsLeaf())
        {
            node.GetContent(value);
            backup_node.m_value = value;
        }
        if (operation.compare("ReplaceProperty") == 0)
        {
            String& prop_name = ((BackupReplacePropertyAdditionalData*)additional_data)->m_prop_name;
            TransactionMOProperty property;
            property.m_name = (prop_name.compare("Title") == 0) ? ("Title") : ("ACL");
            property.m_value = (node.GetProperty((prop_name.compare("Title") == 0) ? e_title : e_ACL, value)) ? value : "";
            backup_node.m_properties.push_back(property);
        }
        if ((operation.compare("Replace") != 0) && (operation.compare("ReplaceProperty") != 0) && (operation.compare("Copy") != 0))
        {
            // get properties
            TransactionMOProperty property;
            // Format
            node.GetProperty(e_format, value);
            property.m_name = "Format";
            property.m_value = value;
            backup_node.m_properties.push_back(property);
            // Type
            node.GetProperty(e_type, value);
            property.m_name = "Type";
            property.m_value = value;
            backup_node.m_properties.push_back(property);
            // ACL
            node.GetProperty(e_ACL, value);
            property.m_name = "ACL";
            property.m_value = value;
            backup_node.m_properties.push_back(property);
            // permanence
            if (node.IsPermanent())
            {
                property.m_name = "permanent";
                property.m_value = "true";
                backup_node.m_properties.push_back(property);
            }
        }
    }
    if ((operation.compare("Delete") == 0) || (operation.compare("Replace") == 0) || (operation.compare("ReplaceProperty") == 0) || (operation.compare("Copy") == 0))
    {
        data.m_before = backup_node;
    }
    else
    {
        data.m_after = backup_node;
    }
    if ((operation.compare("Replace") == 0) || (operation.compare("ReplaceProperty") == 0) || (operation.compare("Copy") == 0))
    {
        if (operation.compare("Replace") == 0)
        {
            backup_node.m_value = *((String*)additional_data);
        }
        else if (operation.compare("ReplaceProperty") == 0)
        {
            backup_node.m_value = ((BackupReplacePropertyAdditionalData*)additional_data)->m_prop_value;
        }
        else
        {   // Copy
            // under construction
        }
        data.m_after = backup_node;
    }

    data.m_needSerialize = needSerialize;
    m_data.push_back(data);
    return true;
}
//-------------------------------------------------------------------------------------------
void MOTreeManagerTransactionData::setDataElementBackupType(const String& operation, TransactionDataElement& data)
{
    if (operation.compare("Add") == 0)
    {
        data.m_type = e_transactionAdd;
    }
    else if (operation.compare("Delete") == 0)
    {
        data.m_type = e_transactionDelete;
    }
    else if (operation.compare("Replace") == 0)
    {
        data.m_type = e_transactionReplace;
    }
    else if (operation.compare("ReplaceProperty") == 0)
    {
        data.m_type = e_transactionReplaceProperty;
    }
    else if (operation.compare("Copy") == 0)
    {
        data.m_type = e_transactionCopy;
    }
}


}
