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

#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 <syncml/core/ObjectDel.h>

#include "Common.h"

const std::string S_root;

namespace fs = boost::filesystem;

void AddNode(const std::string& name)
{
	NS_DM_Client::Node node(name, S_dataStorage);
	node.SetProperty(NS_DM_Client::e_format, "node");
	node.SetProperty(NS_DM_Client::e_type, "text/plain");
	node.SetProperty(NS_DM_Client::e_ACL, "");
}
//-------------------------------------------------------------------------------------------

void AddLeaf(const std::string& name, const std::string& value)
{
	NS_DM_Client::Node leaf(name, S_dataStorage);
	leaf.SetContent(value.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_AUTO_TEST_CASE(GetAttributeTNDSOneProperty)
{
	// add leaf node
	std::string uri = "Leaf";
	NS_DM_Client::Node node(uri, S_dataStorage);
	node.SetContent("some content");
	node.SetProperty(NS_DM_Client::e_format, "chr");
	node.SetProperty(NS_DM_Client::e_type, "text/plain");
	node.SetProperty(NS_DM_Client::e_ACL, "");

	NS_DM_Client::IMOTreeManager::RequiredProperties requiredProp;
	requiredProp.push_back(NS_DM_Client::e_TNDS_name);
	Funambol::StringBuffer* buffer = 0;
	BOOST_CHECK(NS_DM_Client::e_Ok == S_treeManager->GetAttributeTNDS(uri, requiredProp, buffer));

	std::string expectedBuffer(
		"<MgmtTree xmlns='syncml:dmddf1.2'>"
		"<VerDTD>1.2</VerDTD>\n"
		"<Node>"
		"<NodeName>Leaf</NodeName>\n"
		"<RTProperties>"
		"</RTProperties>"
		"</Node>"
		"</MgmtTree>"
		);
	std::string realBuffer = buffer->c_str();
	BOOST_CHECK(expectedBuffer == realBuffer);
	Funambol::deleteStringBuffer(&buffer);

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

BOOST_AUTO_TEST_CASE(GetAttributeTNDSUnexistingNode)
{
	std::string uri = "Node1";
	NS_DM_Client::IMOTreeManager::RequiredProperties requiredProp;
	Funambol::StringBuffer* buffer = 0;
	BOOST_CHECK(NS_DM_Client::e_CommandFailed == S_treeManager->GetAttributeTNDS(uri, requiredProp, buffer));
	Funambol::deleteStringBuffer(&buffer);
}
//-------------------------------------------------------------------------------------------

BOOST_AUTO_TEST_CASE(GetAttributeTNDSLeaf)
{
	// add Node1
	std::string uriNode1 = "Node1";
	NS_DM_Client::Node node1(uriNode1, S_dataStorage);
	node1.SetProperty(NS_DM_Client::e_format, "node");
	node1.SetProperty(NS_DM_Client::e_type, "text/plain");
	node1.SetProperty(NS_DM_Client::e_ACL, "");

	// add subnode of Node1
	std::string uriNode1_1 = uriNode1 + "/Node1_1";
	NS_DM_Client::Node node1_1(uriNode1_1, S_dataStorage);
	node1_1.SetProperty(NS_DM_Client::e_format, "node");
	node1_1.SetProperty(NS_DM_Client::e_type, "text/plain");
	node1_1.SetProperty(NS_DM_Client::e_ACL, "");

	// add leaf
	std::string uriLeaf = uriNode1_1 + "/Leaf";
	NS_DM_Client::Node leaf(uriLeaf, 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, "");

	// this node should be skipped in result
	std::string uriNode1_2 = "Node1/Node1_2";
	NS_DM_Client::Node node1_2(uriNode1_2, S_dataStorage);
	node1_2.SetContent("some content");
	node1_2.SetProperty(NS_DM_Client::e_format, "node");
	node1_2.SetProperty(NS_DM_Client::e_type, "text/plain");
	node1_2.SetProperty(NS_DM_Client::e_ACL, "");

	NS_DM_Client::IMOTreeManager::RequiredProperties requiredProp;
	requiredProp.push_back(NS_DM_Client::e_TNDS_ACL);
	requiredProp.push_back(NS_DM_Client::e_TNDS_name);
	requiredProp.push_back(NS_DM_Client::e_TNDS_format);
	requiredProp.push_back(NS_DM_Client::e_TNDS_type);
	requiredProp.push_back(NS_DM_Client::e_TNDS_size);
	requiredProp.push_back(NS_DM_Client::e_TNDS_title);
	requiredProp.push_back(NS_DM_Client::e_TNDS_tstamp);
	requiredProp.push_back(NS_DM_Client::e_TNDS_verNo);
	requiredProp.push_back(NS_DM_Client::e_TNDS_value);

	Funambol::StringBuffer* buffer = 0;
	BOOST_CHECK(NS_DM_Client::e_Ok == S_treeManager->GetAttributeTNDS(uriLeaf, requiredProp, buffer));

	std::string expectedBuffer(
		"<MgmtTree xmlns='syncml:dmddf1.2'>"
		"<VerDTD>1.2</VerDTD>\n"
// 		"<Node>"
// 		"<NodeName>Node1</NodeName>\n"
// 		"<RTProperties>"
// 		"<Format>node</Format>\n"
// 		"<Type>text/plain</Type>\n"
// 		"</RTProperties>"
//		"</Node>"
// 		"<Node>"
// 		"<Path>Node1</Path>\n"
// 		"<NodeName>Node1_1</NodeName>\n"
// 		"<RTProperties>"
// 		"<Format>node</Format>\n"
// 		"<Type>text/plain</Type>\n"
// 		"</RTProperties>"
//		"</Node>"
		"<Node>"
		"<Path>Node1/Node1_1</Path>\n"
		"<NodeName>Leaf</NodeName>\n"
		"<Value><![CDATA[some content]]></Value>\n"
		"<RTProperties>"
			"<Format>chr</Format>\n"
			"<Type>text/plain</Type>\n"
			"<Size>0</Size>\n"
		"</RTProperties>"
		"</Node>"

		"</MgmtTree>"
		);
	std::string realBuffer = buffer->c_str();
	BOOST_CHECK(expectedBuffer == realBuffer);
	if (expectedBuffer != realBuffer)
    {
		std::cout << "realBuffer: \n" << realBuffer << std::endl;
		std::cout << std::endl;
		std::cout << "expectedBuffer: \n" << expectedBuffer << std::endl;
    }

	Funambol::deleteStringBuffer(&buffer);

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

BOOST_AUTO_TEST_CASE(GetAttributeTNDSInteriorNode)
{
	// add Node1
	std::string uriNode1 = "Node1";
	AddNode(uriNode1);
	// add subnode of Node1 - Node1_1
	std::string uriNode1_1 = uriNode1 + "/Node1_1";
	AddNode(uriNode1_1);
	// add leaf for Node1_1
 	std::string uriLeaf1_1 = uriNode1_1 + "/Leaf1_1";
	std::string content1_1("some content 1_1");
	AddLeaf(uriLeaf1_1, content1_1);

	// add subnode of Node1_1 - Node1_1_1
	std::string uriNode1_1_1 = uriNode1_1 + "/Node1_1_1";
	AddNode(uriNode1_1_1);

	// add leaf for Node1_1_1
	std::string uriLeaf1_1_1 = uriNode1_1_1 + "/Leaf1_1_1";
	std::string content1_1_1("some content 1_1_1");
	AddLeaf(uriLeaf1_1_1, content1_1_1);

	// this node should be skipped in result
	std::string uriNode1_2 = uriNode1 + "/Node1_2";
	AddNode(uriNode1_2);

	NS_DM_Client::IMOTreeManager::RequiredProperties requiredProp;
	requiredProp.push_back(NS_DM_Client::e_TNDS_ACL);
	requiredProp.push_back(NS_DM_Client::e_TNDS_name);
	requiredProp.push_back(NS_DM_Client::e_TNDS_format);
	requiredProp.push_back(NS_DM_Client::e_TNDS_type);
	requiredProp.push_back(NS_DM_Client::e_TNDS_size);
	requiredProp.push_back(NS_DM_Client::e_TNDS_title);
	requiredProp.push_back(NS_DM_Client::e_TNDS_tstamp);
	requiredProp.push_back(NS_DM_Client::e_TNDS_verNo);
	requiredProp.push_back(NS_DM_Client::e_TNDS_value);

	Funambol::StringBuffer* buffer = 0;
	BOOST_CHECK(NS_DM_Client::e_Ok == S_treeManager->GetAttributeTNDS(uriNode1_1, requiredProp, buffer));

	std::string expectedBuffer(
		"<MgmtTree xmlns='syncml:dmddf1.2'>"
		"<VerDTD>1.2</VerDTD>\n"
// 		"<Node>"
// 			"<NodeName>Node1</NodeName>\n"
// 			"<RTProperties>"
// 				"<Format>node</Format>\n"
// 				"<Type>text/plain</Type>\n"
// 			"</RTProperties>"
//		"</Node>"
//
 		"<Node>"
			"<Path>Node1</Path>\n"
			"<NodeName>Node1_1</NodeName>\n"
			"<RTProperties>"
				"<Format>node</Format>\n"
				"<Type>text/plain</Type>\n"
			"</RTProperties>"
		"</Node>"

		"<Node>"
			"<Path>Node1/Node1_1</Path>\n"
			"<NodeName>Leaf1_1</NodeName>\n"
			"<Value><![CDATA[some content 1_1]]></Value>\n"
			"<RTProperties>"
				"<Format>chr</Format>\n"
				"<Type>text/plain</Type>\n"
				"<Size>0</Size>\n"
			"</RTProperties>"
		"</Node>"

		"<Node>"
			"<Path>Node1/Node1_1</Path>\n"
			"<NodeName>Node1_1_1</NodeName>\n"
			"<RTProperties>"
				"<Format>node</Format>\n"
				"<Type>text/plain</Type>\n"
			"</RTProperties>"
		"</Node>"

		"<Node>"
			"<Path>Node1/Node1_1/Node1_1_1</Path>\n"
			"<NodeName>Leaf1_1_1</NodeName>\n"
			"<Value><![CDATA[some content 1_1_1]]></Value>\n"
			"<RTProperties>"
				"<Format>chr</Format>\n"
				"<Type>text/plain</Type>\n"
				"<Size>0</Size>\n"
			"</RTProperties>"
		"</Node>"

		"</MgmtTree>"
		);
	std::string realBuffer = buffer->c_str();
	//std::cout << "realBuffer = " << realBuffer << std::endl;
	BOOST_CHECK(expectedBuffer == realBuffer);
	Funambol::deleteStringBuffer(&buffer);

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

BOOST_AUTO_TEST_CASE(GetAttributeStructData)
{
	// add Node1
	std::string uriNode1 = "GetAttributeStructData/Node1";
	NS_DM_Client::Node node1(uriNode1, S_dataStorage);
	node1.SetProperty(NS_DM_Client::e_format, "node");
	node1.SetProperty(NS_DM_Client::e_type, "text/plain");
	node1.SetProperty(NS_DM_Client::e_ACL, "");

	// add subnode of Node1
	std::string uriNode1_1 = uriNode1 + "/Node1_1";
	NS_DM_Client::Node node1_1(uriNode1_1, S_dataStorage);
	node1_1.SetProperty(NS_DM_Client::e_format, "node");
	node1_1.SetProperty(NS_DM_Client::e_type, "text/plain");
	node1_1.SetProperty(NS_DM_Client::e_ACL, "");

	std::string uriLeaf = uriNode1 + "/Leaf";
	NS_DM_Client::Node leaf(uriLeaf, 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, "");

	Funambol::ArrayList items;
	BOOST_CHECK(NS_DM_Client::e_Ok == S_treeManager->GetAttributeStructData(uriNode1, items));
	BOOST_CHECK(items.size() == 3);

	Funambol::Item* item1 = (Funambol::Item*)items.get(0);
	BOOST_CHECK(uriLeaf == item1->getTarget()->getLocURI()
		|| uriNode1 == item1->getTarget()->getLocURI() || uriNode1_1 == item1->getTarget()->getLocURI());

	Funambol::Item* item2 = (Funambol::Item*)items.get(1);
	BOOST_CHECK(uriLeaf == item2->getTarget()->getLocURI()
		|| uriNode1 == item2->getTarget()->getLocURI() || uriNode1_1 == item2->getTarget()->getLocURI());


	Funambol::Item* item3 = (Funambol::Item*)items.get(2);
	BOOST_CHECK(uriLeaf == item3->getTarget()->getLocURI()
		|| uriNode1 == item3->getTarget()->getLocURI() || uriNode1_1 == item3->getTarget()->getLocURI());

	BOOST_CHECK(std::string(item1->getTarget()->getLocURI()) != item2->getTarget()->getLocURI());
	BOOST_CHECK(std::string(item2->getTarget()->getLocURI()) != item3->getTarget()->getLocURI());

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

BOOST_AUTO_TEST_CASE(GetAttributeTNDSOneNode)
{
	// add leaf node
	std::string uri = "Leaf";
	NS_DM_Client::Node node(uri, S_dataStorage);
	node.SetContent("some content");
	node.SetProperty(NS_DM_Client::e_format, "chr");
	node.SetProperty(NS_DM_Client::e_type, "text/plain");
	node.SetProperty(NS_DM_Client::e_ACL, "");

	NS_DM_Client::IMOTreeManager::RequiredProperties requiredProp;
	requiredProp.push_back(NS_DM_Client::e_TNDS_ACL);
	requiredProp.push_back(NS_DM_Client::e_TNDS_name);
	requiredProp.push_back(NS_DM_Client::e_TNDS_format);
	requiredProp.push_back(NS_DM_Client::e_TNDS_type);
	requiredProp.push_back(NS_DM_Client::e_TNDS_size);
	requiredProp.push_back(NS_DM_Client::e_TNDS_title);
	requiredProp.push_back(NS_DM_Client::e_TNDS_tstamp);
	requiredProp.push_back(NS_DM_Client::e_TNDS_verNo);
	requiredProp.push_back(NS_DM_Client::e_TNDS_value);

	Funambol::StringBuffer* buffer = 0;
	BOOST_CHECK(NS_DM_Client::e_Ok == S_treeManager->GetAttributeTNDS(uri, requiredProp, buffer));

	std::string expectedBuffer(
		"<MgmtTree xmlns='syncml:dmddf1.2'>"
			"<VerDTD>1.2</VerDTD>\n"
			"<Node>"
			"<NodeName>Leaf</NodeName>\n"
			"<Value><![CDATA[some content]]></Value>\n"
			"<RTProperties>"
				"<Format>chr</Format>\n"
				"<Type>text/plain</Type>\n"
				"<Size>0</Size>\n" // size is 0 because of MockDataStorage
			"</RTProperties>"
			"</Node>"
			"</MgmtTree>"
	);
	std::string realBuffer = buffer->c_str();
	//std::cout << "realBuffer = " << realBuffer << std::endl;
	BOOST_CHECK(expectedBuffer == realBuffer);
	Funambol::deleteStringBuffer(&buffer);

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

