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

//#define BOOST_TEST_MAIN

#include <boost/test/unit_test.hpp>
#include "boost/filesystem/operations.hpp"
#include "boost/filesystem/path.hpp"

#include "../Node.h"
#include <iostream>
#include "treemanager/MOTreeManager.h"
#include "MockDataStorage.h"
#include <syncml/core/Item.h>
#include "Common.h"

const std::string S_root;
//const std::string S_workingDirectory("MockMOTree");

namespace fs = boost::filesystem;

BOOST_AUTO_TEST_CASE(GetValueForLeaf)
{
	std::string uri = "GetValueForLeaf/Node1/Node2";
	NS_DM_Client::Node leaf(uri, S_dataStorage);
	std::string content("some content");
	leaf.SetContent(content.c_str());
	leaf.SetProperty(NS_DM_Client::e_format, "chr");
	leaf.SetProperty(NS_DM_Client::e_type, "text/plain");
	leaf.SetProperty(NS_DM_Client::e_ACL, "");

	std::string realContent;
	BOOST_CHECK(S_treeManager->GetValue(uri, realContent));
	//std::cout << "realContent = " << realContent << std::endl;
	BOOST_CHECK(content == realContent);

    fs::remove_all(NS_DM_Client::NS_DataStorage::GetBasePath());
}

// TODO: add test GetUnexistingProperty

BOOST_AUTO_TEST_CASE(GetItemForLeaf)
{
	// set node before retriving
	std::string uri = "GetItemForLeaf/Node1/Node2";
	NS_DM_Client::Node leaf(uri, S_dataStorage);
	leaf.SetProperty(NS_DM_Client::e_format, "chr");
	leaf.SetProperty(NS_DM_Client::e_type, "text/plain");
	leaf.SetProperty(NS_DM_Client::e_ACL, "");

	std::string content("Some data");
	leaf.SetContent(content);

	// retrieve data from storage
	Funambol::Item item;
	NS_DM_Client::StatusCode code = S_treeManager->Get(uri, item);
	BOOST_CHECK(NS_DM_Client::e_Ok == code);
	std::string realData = item.getData()->getData();
	BOOST_CHECK(realData == "Some data");

    fs::remove_all(NS_DM_Client::NS_DataStorage::GetBasePath());
}

// this test is commented because of MockDataStorage should create intermidiate folders
BOOST_AUTO_TEST_CASE(AddNodeWithUnexistingUri)
{
	// add node
 	std::string uri = "AddNodeWithUnexistingUri/Node1/Node2/NodeUnexisted";
 	NS_DM_Client::Node node(uri, S_dataStorage);
 	std::string content("Some data");

 	Funambol::Item newItem;
	Funambol::Meta meta;
	meta.setFormat("chr");
	meta.setType("text/plain");
	newItem.setMeta(&meta);
	Funambol::ComplexData complexData(content.c_str());
 	newItem.setData(&complexData);

 	BOOST_CHECK(S_treeManager->Add(uri, newItem) == NS_DM_Client::e_Ok);

 	// get added node
 	Funambol::Item realItem;
	S_treeManager->Get(uri, realItem);
 	std::string realData = realItem.getData()->getData();
 	BOOST_CHECK(realData == content);

    fs::remove_all(NS_DM_Client::NS_DataStorage::GetBasePath());
}

//-------------------------------------------------------------------------------------------

BOOST_AUTO_TEST_CASE(DeleteExistingNode)
{
	// add node
	std::string uri = "DeleteExistingNode/Node1/Node2";
	NS_DM_Client::Node node(uri, S_dataStorage);
	std::string content("Some data");

	Funambol::Item newItem;
	Funambol::Meta meta;
	meta.setFormat("chr");
	meta.setType("text/plain");
	newItem.setMeta(&meta);
	Funambol::ComplexData complexData(content.c_str());
	newItem.setData(&complexData);
	Funambol::Target target(uri.c_str());
	newItem.setTarget(&target);

	S_treeManager->Add(uri, newItem);

	// remove added node
	BOOST_CHECK( NS_DM_Client::e_Ok == S_treeManager->Delete(uri));
	BOOST_CHECK(S_treeManager->Get(uri, newItem) == NS_DM_Client::e_NotFound);

    fs::remove_all(NS_DM_Client::NS_DataStorage::GetBasePath());
}
//-------------------------------------------------------------------------------------------

BOOST_AUTO_TEST_CASE(DeleteUnexistingNode)
{
	// add node
	std::string uri = "DeleteUnexistingNode/Node1/Node2";

	Funambol::Item item;
	BOOST_CHECK(S_treeManager->Get(uri, item) == NS_DM_Client::e_NotFound);
	BOOST_CHECK(NS_DM_Client::e_NotFound == S_treeManager->Delete(uri));

    fs::remove_all(NS_DM_Client::NS_DataStorage::GetBasePath() +
        (NS_DM_Client::String)"/" + c_testProfile);
}
//-------------------------------------------------------------------------------------------

BOOST_AUTO_TEST_CASE(ReplaceUnexistingNode)
{
	std::string uri = "ReplaceUnexistingNode/Node1/Node2";
	Funambol::Item item;
	BOOST_CHECK(S_treeManager->Get(uri, item) == NS_DM_Client::e_NotFound);
	BOOST_CHECK(NS_DM_Client::e_NotFound == S_treeManager->Replace(uri, item));

    fs::remove_all(NS_DM_Client::NS_DataStorage::GetBasePath());
}
//-------------------------------------------------------------------------------------------

BOOST_AUTO_TEST_CASE(ReplaceNode)
{
	// add node
	std::string uri = "ReplaceNode/Node1/Node2";
	Funambol::Item item;
	Funambol::Meta meta;
	meta.setFormat("chr");
	meta.setType("text/plain");
	meta.setSize(9);
	item.setMeta(&meta);
	std::string content("Some data");
	Funambol::ComplexData complexData(content.c_str());
	item.setData(&complexData);

	S_treeManager->Add(uri, item);

	Funambol::Item newItem;
	newItem.setMeta(&meta);
	std::string newContent("Some another data");
	complexData.setData(newContent.c_str());
	newItem.setData(&complexData);
	BOOST_CHECK(NS_DM_Client::e_Ok == S_treeManager->Replace(uri, newItem));

	Funambol::Item realItem;
	S_treeManager->Get(uri, realItem);
	std::string realData = realItem.getData()->getData();
	BOOST_CHECK(realData == newContent);

    fs::remove_all(NS_DM_Client::NS_DataStorage::GetBasePath());
}

BOOST_AUTO_TEST_CASE(CopyLeafNodeToExistingDestinationNode)
{
	// add root with ACL = Get=*&Add=*
	NS_DM_Client::Node root("CopyLeafNodeToExistingDestinationNode/RootNode", S_dataStorage);
	root.SetProperty(NS_DM_Client::e_format, "node");
	root.SetProperty(NS_DM_Client::e_type, "node");
	root.SetProperty(NS_DM_Client::e_ACL, "Get=*&Add=*");

	// add source node
	std::string uri1 = "CopyLeafNodeToExistingDestinationNode/RootNode/Node1/Node2/SourceNode";
	Funambol::Item sourceItem;
	Funambol::Meta meta;
	meta.setFormat("chr");
	meta.setType("text/plain");
	sourceItem.setMeta(&meta);
	std::string oldContent("Some data");
	Funambol::ComplexData complexData(oldContent.c_str());
	sourceItem.setData(&complexData);

	// add destination node
	std::string uri2 = "CopyLeafNodeToExistingDestinationNode/RootNode/Node1/Node2/DestNode";
	Funambol::Item destItem;
	meta.setFormat("chr");
	meta.setType("text/plain");
	destItem.setMeta(&meta);
	std::string newContent("Some another data");
	complexData.setData(newContent.c_str());
	destItem.setData(&complexData);

	S_treeManager->Add(uri1, sourceItem);
	S_treeManager->Add(uri2, destItem);
	BOOST_CHECK(NS_DM_Client::e_Ok == S_treeManager->Copy(uri1, uri2));

	Funambol::Item realItem;
	S_treeManager->Get(uri2, realItem);
	std::string realData = realItem.getData()->getData();
	BOOST_CHECK(realData == oldContent);

    fs::remove_all(NS_DM_Client::NS_DataStorage::GetBasePath());
}


BOOST_AUTO_TEST_CASE(CopyLeafNodeToNotExistingDestinationNode)
{
	// add root with ACL = Get=*&Add=*
	NS_DM_Client::Node root("CopyLeafNodeToNotExistingDestinationNode/RootNode", S_dataStorage);
	root.SetProperty(NS_DM_Client::e_format, "node");
	root.SetProperty(NS_DM_Client::e_type, "node");
	root.SetProperty(NS_DM_Client::e_ACL, "Get=*&Add=*");

	// add source node
	std::string uri1 = "CopyLeafNodeToNotExistingDestinationNode/RootNode/Node1/Node2/SourceNode";
	Funambol::Item sourceItem;
	Funambol::Meta meta;
	meta.setFormat("chr");
	meta.setType("text/plain");
	sourceItem.setMeta(&meta);
	std::string oldContent("source node content");
	Funambol::ComplexData complexData(oldContent.c_str());
	sourceItem.setData(&complexData);

	BOOST_CHECK(NS_DM_Client::e_Ok == S_treeManager->Add(uri1, sourceItem));

	std::string uri2 = "CopyLeafNodeToNotExistingDestinationNode/RootNode/SomeInteriorNode1/Node2/DestNode";
	BOOST_CHECK(NS_DM_Client::e_Ok == S_treeManager->Copy(uri1, uri2));

	Funambol::Item realItem;
	S_treeManager->Get(uri2, realItem);
	std::string realData = realItem.getData()->getData();
	BOOST_CHECK(realData == oldContent);

    fs::remove_all(NS_DM_Client::NS_DataStorage::GetBasePath());
}


BOOST_AUTO_TEST_CASE(CopyInteriorNode)
{
	// add root with ACL = Get=*&Add=*
	NS_DM_Client::Node root("CopyInteriorNode/RootNode", S_dataStorage);
	root.SetProperty(NS_DM_Client::e_format, "node");
	root.SetProperty(NS_DM_Client::e_type, "node");
	root.SetProperty(NS_DM_Client::e_ACL, "Get=*&Add=*");

	// add childs
	std::string uri = "CopyInteriorNode/RootNode/Node1/Node2/SourceNode";
	Funambol::Item sourceItem;
	Funambol::Meta meta;
	meta.setFormat("chr");
	meta.setType("text/plain");
	sourceItem.setMeta(&meta);
	std::string oldContent("Some data");
	Funambol::ComplexData complexData(oldContent.c_str());
	sourceItem.setData(&complexData);
	BOOST_CHECK(NS_DM_Client::e_Ok == S_treeManager->Add(uri, sourceItem));

	uri = "CopyInteriorNode/RootNode/Subnode/Node1/SourceNode";
	sourceItem.setData(&complexData);
	BOOST_CHECK(NS_DM_Client::e_Ok == S_treeManager->Add(uri, sourceItem));

	uri = "CopyInteriorNode/RootNode/Subnode/Node2/SourceNode2";
	sourceItem.setData(&complexData);
	BOOST_CHECK(NS_DM_Client::e_Ok == S_treeManager->Add(uri, sourceItem));

	uri = "CopyInteriorNode/RootNode/Subnode/LeafNode";
	sourceItem.setData(&complexData);
	BOOST_CHECK(NS_DM_Client::e_Ok == S_treeManager->Add(uri, sourceItem));

	BOOST_CHECK(NS_DM_Client::e_Ok == S_treeManager->Copy("CopyInteriorNode/RootNode", "CopyInteriorNode/copy_dest"));

    fs::remove_all(NS_DM_Client::NS_DataStorage::GetBasePath());
}


BOOST_AUTO_TEST_CASE(CheckPermanentStatus)
{
	// add node
	std::string uri = "CheckPermanentStatus/PermanentNode";
	fs::path path(uri, fs::native);

	NS_DM_Client::Node root("CopyInteriorNode/RootNode", S_dataStorage);
	root.SetProperty(NS_DM_Client::e_format, "chr");
	root.SetProperty(NS_DM_Client::e_type, "text/plain");
	root.SetProperty(NS_DM_Client::e_ACL, "Get=*&Delete=*");
    root.SetContent("permanent leaf node");
    root.SetPermanent();

    BOOST_CHECK(true == root.IsPermanent());

    fs::remove_all(NS_DM_Client::NS_DataStorage::GetBasePath());
}

BOOST_AUTO_TEST_CASE(ReplaceNamePropertyOfNode)
{
	NS_DM_Client::Node root("ReplaceNamePropertyOfNode/RootNode", S_dataStorage);

	root.SetProperty(NS_DM_Client::e_format, "node");
	root.SetProperty(NS_DM_Client::e_type, "node");
	root.SetProperty(NS_DM_Client::e_ACL, "Get=*&Add=*");

	// add childs
	std::string uri = "ReplaceNamePropertyOfNode/RootNode/Node1/Node2/SourceNode";
	Funambol::Item sourceItem;
	Funambol::Meta meta;
	meta.setFormat("chr");
	meta.setType("text/plain");
	sourceItem.setMeta(&meta);
	std::string oldContent("Some data");
	Funambol::ComplexData complexData(oldContent.c_str());
	sourceItem.setData(&complexData);
	BOOST_CHECK(NS_DM_Client::e_Ok == S_treeManager->Add(uri, sourceItem));

	uri = "ReplaceNamePropertyOfNode/RootNode/Subnode/Node1/SourceNode";
	sourceItem.setData(&complexData);
	BOOST_CHECK(NS_DM_Client::e_Ok == S_treeManager->Add(uri, sourceItem));

	uri = "ReplaceNamePropertyOfNode/RootNode/Subnode/Node2/SourceNode2";
	sourceItem.setData(&complexData);
	BOOST_CHECK(NS_DM_Client::e_Ok == S_treeManager->Add(uri, sourceItem));

	uri = "ReplaceNamePropertyOfNode/RootNode/Subnode/LeafNode";
	sourceItem.setData(&complexData);
	BOOST_CHECK(NS_DM_Client::e_Ok == S_treeManager->Add(uri, sourceItem));

	BOOST_CHECK(NS_DM_Client::e_Ok == S_treeManager->ReplacePropertyValue("ReplaceNamePropertyOfNode/RootNode", "Name", "ReplacedNode"));

	BOOST_CHECK(NS_DM_Client::e_Ok == S_treeManager->Get("ReplaceNamePropertyOfNode/ReplacedNode/Subnode/Node2/SourceNode2", sourceItem));

    fs::remove_all(NS_DM_Client::NS_DataStorage::GetBasePath());
}
//-------------------------------------------------------------------------------------------

