/*
 * Copyright (C) 2009 - 2010 Funambol, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol".
 */

/* $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;
    }
}


}
