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

#pragma once

#include "Errors.h"
#include "treemanager/IMOTreeManager.h"
#include <vector>
#include <list>

#include <stdio.h>

namespace Funambol
{
    class Item;
	class ArrayList;
}

namespace NS_Logging
{
	class Logger;
}

namespace NS_DM_Client
{
	namespace NS_DataStorage
	{
		class IDataStorage;
	}
}

namespace NS_DM_Client
{
	class Node;
    class MOTreeManagerTransaction;
    class MOTreeManagerListenerCollection;
    class IDeviceUpdater;

	class MOTreeManager: public IMOTreeManager
	{
		friend void SetDataStorage(IMOTreeManager& manager, NS_DM_Client::NS_DataStorage::IDataStorage* dataStorage); // for tests only
		friend void SetDeviceUpdater(IMOTreeManager& manager, NS_DM_Client::IDeviceUpdater* deviceUpdater); // for tests only

        enum AccessTypeOperation
        {
            e_atGet = 0,
            e_atAdd,
            e_atReplace,
            e_atDelete,
            e_atExec
        };

        struct AccessTypeTree
        {
            String m_Name;
            std::vector<AccessTypeOperation> m_operations;
            std::list<AccessTypeTree> m_childs;
        };

	public:
		MOTreeManager();
		~MOTreeManager();

		virtual bool Init(const StringMap& settings, const String& loggerInstance, ProfileComponentsHolder& pch);
		virtual bool Start() { return true; }
		virtual bool Stop() { return true; }
		virtual void Release();

		virtual bool Exist(const URI& uri, const char* serverId = 0);
		virtual StatusCode Get(const URI& uri, Funambol::Item& item, const char* serverId = 0);
		virtual StatusCode GetAttributeStructData(const URI& uri, Funambol::ArrayList& items, const char* serverId = 0);
		virtual StatusCode GetAttributeTNDS(const URI& uri, const RequiredProperties& requiredProp, Funambol::StringBuffer*& xml, const char* serverId = 0);

		virtual StatusCode GetValue(const URI& uri, String& value, const char* serverId = 0); // works for leaves only
		virtual StatusCode GetPropertyValue(const URI& uri, const String& property_name, String& value, const char* serverId = 0); // works for leaves only
		virtual StatusCode GetChildren(const URI& uri, ChildrenPaths& children, const char* serverId = 0); // for interior node only
		virtual StatusCode Add(const URI& uri, const Funambol::Item& item, const char* serverId = 0, bool isUpdateRequired = true);
		virtual StatusCode Delete(const URI& uri, const char* serverId = 0);
		virtual StatusCode Replace(const URI& uri, const Funambol::Item& item, const char* serverId = 0, bool isUpdateRequired = true);
		virtual StatusCode ReplacePropertyValue(const URI& uri, const String& property_name, const String& new_value, const char* serverId = 0);
		virtual StatusCode Copy(const URI& source, const URI& dest, const char* serverId = 0); // works for leaves only

        virtual StatusCode ExecPermitted(const URI& path, const char* serverId = 0);

        virtual StatusCode SetPropertyValue(const URI& uri, const String& property_name, const String& value);

	    virtual StatusCode StartTransaction();
	    virtual StatusCode Rollback();
	    virtual StatusCode Commit();

	private:
		void release();

		bool checkFormat(const Node& node, Funambol::Item& item);
		bool getFormatValue(const Node& node, String& value);

        StatusCode replaceNode(const URI& source, const URI& destination);
        StatusCode addIntermediateInteriorNodes(const URI& source, const char* serverId, bool isUpdateRequired = true);
        StatusCode addACLPropertyForNewNode(Node& node, bool isLeaf, const char* serverId);

        StatusCode checkOperationPermission(const String& operation, const Node& node, const char* serverId);
        StatusCode checkUnifiedOperationPermission(const String& operation, const Node& node, const char* serverId);
	    void retrieveOperationServersIdsFromACL(const String& ACL, const String& operation, std::vector<String>& Ids);
	    void retrieveServerIdsFromACLCommand(const String& command, std::vector<String>& Ids);

	    void startTransaction(const URI& uri);
	    void finishTransaction(StatusCode operationResult);

        StatusCode copyNode(const Node& source, Node& dest, const char* serverId = 0);
        StatusCode copyLeafSourceToExistingDestination(const Node& source, Node& dest);
        StatusCode copyLeafSourceToNoExistingDestination(const Node& source, Node& dest, const char* serverId = 0);
        StatusCode copyInteriorSource(const Node& source, const URI& dest, const char* serverId = 0);

		// TNDS
		Funambol::StringBuffer* getAboveNodeXMLRepresentation(const URI& uri, const RequiredProperties& requiredProp);
		Funambol::StringBuffer* getBelowNodeXMLRepresentation(const URI& uri, const RequiredProperties& requiredProp);
		void appendValue(Funambol::StringBuffer*& nodeXml, const String& target, const char* value);
		void appendRequiredProperties(Funambol::StringBuffer*& nodeXml, const Node& node, const RequiredProperties& requiredProp);

        // AccessType
        bool getAccessTypeTree(const StringMap& settings, ProfileComponentsHolder& pch);
        StatusCode checkAccessTypePermission(const String& operation, const Node& node, const char* serverId);

        FILE* openAccessTypeFile(const String& path);
        bool readAccessTypeTree(FILE* file);
        bool appendAccessTypeKey(const String& key);
        bool formAccessTypeOperationsFromKey(const String& strOperations, std::vector<AccessTypeOperation>& operations);
        bool addAccessTypeKeyToTree(const String& keyName, const std::vector<AccessTypeOperation>& operations);
        AccessTypeOperation ConvertFromStringToAccessTypeOperation(const String& operation);

        // DRMD
        void collectDRMD(const StringMap& settings);

	private:
		ProfileComponentsHolder*	m_pch;
		NS_DM_Client::NS_DataStorage::IDataStorage* m_dataStorage;
		MOTreeManagerTransaction* m_transaction;
        MOTreeManagerListenerCollection* m_listeners;
		NS_Logging::Logger* m_logger;
        bool m_isInited;
        bool m_needFinishThansaction;
		URI m_transactionURI;

        AccessTypeTree m_AccessTypeTree;
	};

}
