//#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"
#include "Errors.h"
#include "commontypes.h"

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

namespace fs = boost::filesystem;

BOOST_AUTO_TEST_CASE(GetValueWithSufficientPrivilegeByRootNode)
{
	// add root with ACL = Get=*&Add=*
	URI uri = "GetValueWithSufficientPrivilegeByRootNode/RootNode";
	NS_DM_Client::Node root(uri, S_dataStorage);
	fs::path root_path(NS_DM_Client::NS_DataStorage::GetBasePath() + (String)"/"
	    + c_testProfile + (String)"/" + uri, fs::native);

	root.SetProperty(NS_DM_Client::e_format, "node");
	root.SetProperty(NS_DM_Client::e_type, "node");
	root.SetProperty(NS_DM_Client::e_ACL, "Get=*");
	BOOST_CHECK(fs::exists(root_path));

    // add child node with empty ACL
	uri = "GetValueWithSufficientPrivilegeByRootNode/RootNode/ChildWithEmptyACL";
	NS_DM_Client::Node leaf(uri, S_dataStorage);
	fs::path leaf_path(String(NS_DM_Client::NS_DataStorage::GetBasePath() + (String)"/"
	    + c_testProfile + (String)"/" + uri).c_str(), fs::native);

	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, "");
	BOOST_CHECK(fs::exists(leaf_path));


 	Funambol::Item realItem;
	const char* serverId = "someId";
	NS_DM_Client::StatusCode res = S_treeManager->Get(uri, realItem, serverId);
	BOOST_CHECK(res == NS_DM_Client::e_Ok);

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


BOOST_AUTO_TEST_CASE(GetValueWithSufficientPrivilegeByOwnACL)
{
	// add root with ACL = Get=*&Add=*
	URI uri = "GetValueWithSufficientPrivilegeByOwnACL/RootNode";
	NS_DM_Client::Node root(uri, S_dataStorage);
	fs::path root_path(String(NS_DM_Client::NS_DataStorage::GetBasePath() + (String)"/"
	    + c_testProfile + (String)"/" + uri).c_str(), fs::native);

	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=*");
	BOOST_CHECK(fs::exists(root_path));

    // add child node with empty ACL
	uri = "GetValueWithSufficientPrivilegeByOwnACL/RootNode/ChildWithEmptyACL";
	NS_DM_Client::Node leaf(uri, S_dataStorage);
	fs::path leaf_path(String(NS_DM_Client::NS_DataStorage::GetBasePath() + (String)"/"
	    + c_testProfile + (String)"/" + uri).c_str(), fs::native);

	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, "Add=*&Get=oneId+someId+anotherId&Replace=*&Add=SomeElseId&Get=*&Get=SomeElseId");
	BOOST_CHECK(fs::exists(leaf_path));

 	Funambol::Item realItem;
	const char* serverId = "someId";
	NS_DM_Client::StatusCode res = S_treeManager->Get(uri, realItem, serverId);
	BOOST_CHECK(res == NS_DM_Client::e_Ok);

    fs::remove_all(String(NS_DM_Client::NS_DataStorage::GetBasePath() +
        (String)"/" + c_testProfile + "/GetValueWithSufficientPrivilegeByOwnACL/RootNode").c_str());
}

BOOST_AUTO_TEST_CASE(GetValueWithNoSufficientPrivilege)
{
	// add root with ACL = Get=*&Add=*
	URI uri = "GetValueWithNoSufficientPrivilege/RootNode";
	NS_DM_Client::Node root(uri, S_dataStorage);
	fs::path root_path(String(NS_DM_Client::NS_DataStorage::GetBasePath() + (String)"/"
	    + c_testProfile + (String)"/" + uri).c_str(), fs::native);

	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=*");
	BOOST_CHECK(fs::exists(root_path));

    // add child node with empty ACL
	uri = "GetValueWithNoSufficientPrivilege/RootNode/ChildWithEmptyACL";
	NS_DM_Client::Node leaf(uri, S_dataStorage);
	fs::path leaf_path(String(NS_DM_Client::NS_DataStorage::GetBasePath() + (String)"/"
	    + c_testProfile + (String)"/" + uri).c_str(), fs::native);

	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, "Add=*&Get=oneId+someId+anotherId&Replace=*&Add=SomeElseId&Get=*&Get=SomeElseId");
	BOOST_CHECK(fs::exists(leaf_path));

 	Funambol::Item realItem;
	const char* serverId = "noSufficientId";
	NS_DM_Client::StatusCode res = S_treeManager->Get(uri, realItem, serverId);
	BOOST_CHECK(res == NS_DM_Client::e_PermissionDenied);

    fs::remove_all(String(NS_DM_Client::NS_DataStorage::GetBasePath() +
        (String)"/" + c_testProfile + "/GetValueWithNoSufficientPrivilege/RootNode").c_str());
}

BOOST_AUTO_TEST_CASE(AddValueWithInteriorNodesAndRootWithoutReplaceInACL)
{
	// add root with ACL = Get=*&Add=*
	NS_DM_Client::Node root("AddValueWithInteriorNodesAndRootWithoutReplaceInACL/RootNode", S_dataStorage);
	fs::path root_path(String(NS_DM_Client::NS_DataStorage::GetBasePath() + (String)"/"
	    + c_testProfile + (String)"/" + "AddValueWithInteriorNodesAndRootWithoutReplaceInACL/RootNode").c_str(), fs::native);

	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=*"); // root without Replace
	BOOST_CHECK(fs::exists(root_path));

    // add child node
  	Funambol::Item item;
	Funambol::Meta meta;
	meta.setFormat("chr");
	meta.setType("text/plain");
	item.setMeta(&meta);
	std::string oldContent("Some data");
	item.setData(&Funambol::ComplexData(oldContent.c_str()));
    NS_DM_Client::StatusCode res = S_treeManager->Add("AddValueWithInteriorNodesAndRootWithoutReplaceInACL/RootNode/InteriorNode1/InteriorNode2/InteriorNode3/ChildWithEmptyACL", item, "www.test_server.com");
	BOOST_CHECK(res == NS_DM_Client::e_Ok);

    String ACL_value;
	// check ACL of InteriorNode3
	NS_DM_Client::Node interior3("AddValueWithInteriorNodesAndRootWithoutReplaceInACL/RootNode/InteriorNode1/InteriorNode2/InteriorNode3", S_dataStorage);
	BOOST_CHECK(interior3.Exist());
    BOOST_CHECK(interior3.GetProperty(NS_DM_Client::e_ACL, ACL_value));
    BOOST_CHECK(ACL_value.empty());

	// check ACL of InteriorNode2
	NS_DM_Client::Node interior2("AddValueWithInteriorNodesAndRootWithoutReplaceInACL/RootNode/InteriorNode1/InteriorNode2", S_dataStorage);
	BOOST_CHECK(interior2.Exist());
    BOOST_CHECK(interior2.GetProperty(NS_DM_Client::e_ACL, ACL_value));
    BOOST_CHECK(ACL_value.empty());

	// check ACL of InteriorNode1
	NS_DM_Client::Node interior1("AddValueWithInteriorNodesAndRootWithoutReplaceInACL/RootNode/InteriorNode1", S_dataStorage);
	BOOST_CHECK(interior1.Exist());
    BOOST_CHECK(interior1.GetProperty(NS_DM_Client::e_ACL, ACL_value));
    BOOST_CHECK(ACL_value.compare("Add=www.test_server.com&Get=www.test_server.com&Delete=www.test_server.com&Replace=www.test_server.com") == 0);

    fs::remove_all(String(NS_DM_Client::NS_DataStorage::GetBasePath() +
        (String)"/" + c_testProfile + "/AddValueWithInteriorNodesAndRootWithoutReplaceInACL/RootNode").c_str());
}

BOOST_AUTO_TEST_CASE(AddValueWithInteriorNodesAndRootWithReplaceInACL)
{
	// add root with ACL = Get=*&Add=*&Replace=*
	NS_DM_Client::Node root("AddValueWithInteriorNodesAndRootWithReplaceInACL/RootNode", S_dataStorage);
	fs::path root_path(String(NS_DM_Client::NS_DataStorage::GetBasePath() + (String)"/"
	    + c_testProfile + (String)"/" + "AddValueWithInteriorNodesAndRootWithReplaceInACL/RootNode").c_str(), fs::native);

	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=*&Replace=*"); // root with Replace
	BOOST_CHECK(fs::exists(root_path));

    // add child node
  	Funambol::Item item;
	Funambol::Meta meta;
	meta.setFormat("chr");
	meta.setType("text/plain");
	item.setMeta(&meta);
	std::string oldContent("Some data");
	item.setData(&Funambol::ComplexData(oldContent.c_str()));
    NS_DM_Client::StatusCode res = S_treeManager->Add("AddValueWithInteriorNodesAndRootWithReplaceInACL/RootNode/InteriorNode1/InteriorNode2/InteriorNode3/ChildWithEmptyACL", item, "www.test_server.com");
	BOOST_CHECK(res == NS_DM_Client::e_Ok);

    String ACL_value;
	// check ACL of InteriorNode3
	NS_DM_Client::Node interior3("AddValueWithInteriorNodesAndRootWithReplaceInACL/RootNode/InteriorNode1/InteriorNode2/InteriorNode3", S_dataStorage);
	BOOST_CHECK(interior3.Exist());
    BOOST_CHECK(interior3.GetProperty(NS_DM_Client::e_ACL, ACL_value));
    BOOST_CHECK(ACL_value.empty());

	// check ACL of InteriorNode2
	NS_DM_Client::Node interior2("AddValueWithInteriorNodesAndRootWithReplaceInACL/RootNode/InteriorNode1/InteriorNode2", S_dataStorage);
	BOOST_CHECK(interior2.Exist());
    BOOST_CHECK(interior2.GetProperty(NS_DM_Client::e_ACL, ACL_value));
    BOOST_CHECK(ACL_value.empty());

	// check ACL of InteriorNode1
	NS_DM_Client::Node interior1("AddValueWithInteriorNodesAndRootWithReplaceInACL/RootNode/InteriorNode1", S_dataStorage);
	BOOST_CHECK(interior1.Exist());
    BOOST_CHECK(interior1.GetProperty(NS_DM_Client::e_ACL, ACL_value));
    BOOST_CHECK(ACL_value.empty());

    fs::remove_all(String(NS_DM_Client::NS_DataStorage::GetBasePath() +
        (String)"/" + c_testProfile + "/AddValueWithInteriorNodesAndRootWithReplaceInACL/RootNode").c_str());
}

BOOST_AUTO_TEST_CASE(AddValueWithInteriorNodesAndRootWithoutReplaceInACLAndTryChangeACL)
{
	// add root with ACL = Get=*&Add=*
	NS_DM_Client::Node root("AddValueWithInteriorNodesAndRootWithoutReplaceInACLAndTryChangeACL/Root", S_dataStorage);
	fs::path root_path(String(NS_DM_Client::NS_DataStorage::GetBasePath() + (String)"/"
	    + c_testProfile + (String)"/" + "AddValueWithInteriorNodesAndRootWithoutReplaceInACLAndTryChangeACL/Root").c_str(), fs::native);

	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=*"); // root with Replace
	BOOST_CHECK(fs::exists(root_path));

    // add child node
  	Funambol::Item item;
	Funambol::Meta meta;
	meta.setFormat("chr");
	meta.setType("text/plain");
	item.setMeta(&meta);
	std::string oldContent("Some data");
	item.setData(&Funambol::ComplexData(oldContent.c_str()));
    NS_DM_Client::StatusCode res = S_treeManager->Add("AddValueWithInteriorNodesAndRootWithoutReplaceInACLAndTryChangeACL/Root/X/FwV", item, "*");
	BOOST_CHECK(res == NS_DM_Client::e_Ok);

    // try change ACL of node
    res = S_treeManager->ReplacePropertyValue("AddValueWithInteriorNodesAndRootWithoutReplaceInACLAndTryChangeACL/Root/X/FwV", "ACL", "Add=*&Exec=*&Replace=*&Get=*&Delete=*", "*");
	BOOST_CHECK(res == NS_DM_Client::e_Ok);

	// check ACL of node
	String ACL_value;
	NS_DM_Client::Node leaf("AddValueWithInteriorNodesAndRootWithoutReplaceInACLAndTryChangeACL/Root/X/FwV", S_dataStorage);
	BOOST_CHECK(leaf.Exist());
    BOOST_CHECK(leaf.GetProperty(NS_DM_Client::e_ACL, ACL_value));
    BOOST_CHECK(ACL_value.compare("Add=*&Exec=*&Replace=*&Get=*&Delete=*") == 0);

    fs::remove_all(String(NS_DM_Client::NS_DataStorage::GetBasePath() +
        (String)"/" + c_testProfile + "/AddValueWithInteriorNodesAndRootWithoutReplaceInACLAndTryChangeACL/Root").c_str());
}

