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

// 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);
				return true;
			}
			//-------------------------------------------------------------------------------------------

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

			bool SavePrivateData(const String& key, const void* buffer, size_t size, bool)
			{
				size_t found = key.find_last_of('/');
				String tmpKey = key.substr(0, found);
				fs::path path(S_workingDirectory + tmpKey, fs::native);
				fs::create_directories(path);
				fs::path fullPath = fs::complete(S_workingDirectory + key);
				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, fs::native);
				fs::path fullPath(fs::complete(S_workingDirectory + key));

				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, 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();
					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);

					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);

			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;
		}
		//------------------------------------------------------------------------------------------------------

	}
}
