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

// for test only: mock data storage with own implementation
#include <fstream>
#include <iostream>
#include "boost/filesystem/operations.hpp"
#include "boost/filesystem/path.hpp"
#include <boost/filesystem.hpp>
#include "commontypes.h"


#include "DataStorage/IDataStorage.h"
#include "common/Buffer.h"
#include "treemanager/MOTreeManager.h"

const char* const c_privateDataPath = "/tmp/Funambol/DMClient/DataStorage";

namespace fs = boost::filesystem;

namespace NS_DM_Client
{
	inline void SetDataStorage(NS_DM_Client::IMOTreeManager& manager, NS_DM_Client::NS_DataStorage::IDataStorage* dataStorage)
	{
		(dynamic_cast<NS_DM_Client::MOTreeManager&>(manager)).m_dataStorage = dataStorage;
	}

	namespace NS_DataStorage
	{
		const std::string S_workingDirectory("MockMOTree/");
		typedef std::vector<String> StringList;

		class MockDataStorage: public IDataStorage
		{
		public:
			bool Init(const String& base_path) { return true; };
			IStreamHandler* CreateStream() {return 0; }

			bool GetPrivateDataSize(const String& key, size_t& size)
			{
				return true;
			}

			void Release()
			{
				delete this;
			}
			//-------------------------------------------------------------------------------------------

			bool SavePrivateData(const String& key, const Buffer& buffer, bool profileSpecific = true)
			{
				return SavePrivateData(key, buffer.GetPointer(), buffer.Size() + 1, profileSpecific);
			}
			//-------------------------------------------------------------------------------------------

			bool RemovePrivateData(const String& key)
			{
				fs::remove_all(S_workingDirectory + key.c_str());
				return true;
			}
			//-------------------------------------------------------------------------------------------

			bool Exist(const String& key, bool)
			{
				fs::path fullPath(fs::complete(S_workingDirectory + key.c_str()));
				return fs::exists(fullPath);
			}
			//-------------------------------------------------------------------------------------------

			bool SavePrivateData(const String& key, const void* buffer, size_t size, bool)
			{
				size_t found = key.rfind("/");
				String tmpKey = key.substr(0, found);
				fs::path path(S_workingDirectory + tmpKey.c_str(), fs::native);
				fs::create_directories(path);
				fs::path fullPath = fs::complete(S_workingDirectory + key.c_str());
				std::ofstream contentFile((fullPath.string()).c_str());
				contentFile << (char*)buffer;
				return true;
			}
			//-------------------------------------------------------------------------------------------

			bool LoadPrivateData(const String& key, Buffer& buffer, bool profileSpecific = true)
			{
				fs::path path(S_workingDirectory + key.c_str(), fs::native);
				fs::path fullPath(fs::complete(S_workingDirectory + key.c_str()));

				std::string filename(fullPath.string().c_str());
				std::string content;
				std::ifstream ifs(filename.c_str(), std::ios::in | std::ios::binary);
				//std::cout << "Before reading private data from file    " << std::endl;
				std::streamoff file_size = ifs.seekg(0, std::ios::end).tellg();
				if (file_size == -1) return false;
				ifs.seekg(0);
				content.resize(file_size);
				ifs.read(&content[0], file_size);

				//std::cout << "Content = " << content << std::endl;
				buffer.Allocate(content.size() + 1);
				memset(buffer.GetPointer(), 0, content.size() + 1);
				memcpy(buffer.GetPointer(), content.c_str(), content.size() + 1);
				//std::cout << "buffer.GetPointer() " << buffer.GetPointer() << "  "<< std::string((char*)buffer.GetPointer()) << std::endl;
				return true;
			}
			//-------------------------------------------------------------------------------------------

			bool GetChildList(const String& key, StringList& list, bool)
			{
				fs::path path(S_workingDirectory + key.c_str(), fs::native);
				if (!fs::is_directory(path))
					return true;

				fs::directory_iterator end;
				for (fs::directory_iterator i(path); i != end; ++i)
				{
					String tmp = i->string().c_str();
					fs::path tmpPath(tmp, fs::native);
					if (!fs::is_directory(tmpPath))
						continue;
					size_t found = i->string().find_last_of('/');
					String tmpKey = i->string().substr(found + 1).c_str();

					list.push_back(tmpKey);
				}
				return true;
			}

            const char* GetBasePath()
            {
                return c_privateDataPath;
            }

            bool GetPrivateDataSize(const String& key, size_t& size, bool profileSpecific = true)
            {
                size = 0;
                return true;
            }

		};

		inline void LoadPrivateData(const String& key, std::string& content)
		{
			fs::path fullPath = fs::complete(S_workingDirectory + key.c_str());

			std::string filename((fullPath.string() + "/content.txt").c_str());
			std::ifstream ifs(filename.c_str(), std::ios::in | std::ios::binary);
			std::streamoff file_size = ifs.seekg(0, std::ios::end).tellg();
			ifs.seekg(0);
			content.resize(file_size);
			ifs.read(&content[0], file_size);
		}

		//-------------------------------------------------------------------------------------------
		inline const char* GetBasePath()
		{
			//return c_privateDataPath;
			return S_workingDirectory.c_str();
		}
		//------------------------------------------------------------------------------------------------------

		inline IDataStorage* CreateDataStorage(const String& profile, const String& base_path)
		{
			IDataStorage* res = new MockDataStorage();
			if (res)
			{
				if (!res->Init(c_privateDataPath))
				{
					res->Release();
					res = 0;
				}
			}
			return res;
		}
		//------------------------------------------------------------------------------------------------------

	}
}
