/*
* Copyright 2009 Funambol, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $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, bool keepData = true, 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 copyLeafSourceToNotExistingDestination(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);

        // dumping
		void setDumpPath(const StringMap& settings);
		void dump();

	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;

        size_t m_transactionDepth;

        AccessTypeTree m_AccessTypeTree;
	
		String m_dumpPath;
	};

}
