/***************************************************************************
*   Copyright (C) 2004 by Denis A. Birukov aka Messenger of death         *
*   riper@fromru.com                                                      *
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
*   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 General Public License     *
*   along with this program; if not, write to the                         *
*   Free Software Foundation, Inc.,                                       *
*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
***************************************************************************/
#include "me_c_storage.h"
#include <me_debug.h>
#include <me_c_storageentry.h>
#include <me_c_parser.h>
#include <me_c_storage_driver_interface.h>
//#include <me_c_dynamic_module_interface.h>
//#include <me_c_dynamic_module.h>
 
namespace ME_n_Storage
{
	ME_c_Storage::ME_c_Storage( ME_c_Storage_Driver_Interface * drv )
	{
		_storage_driver_ = drv;
	}


	ME_c_Storage::~ ME_c_Storage( )
	{
		/// @todo реализовать корректный деструктор
		delete _storage_driver_;
	}

	ME_c_Storage::ME_c_Storage( std::string name )
	{
		ME_n_Log::_debug( ME_n_Log::ME_DEBUG_INFO ) << __FILE__ << ":" << __LINE__ << "-ME_c_Storage: Creating Storage from library " << name << std::endl;

		ME_n_Dynamic_Module::ME_c_Dynamic_Module_Interface Dynamic_Module;
		ME_n_Storage::ME_c_Storage_Driver_Interface* ( *fun ) ( void );
		fun = ( ME_n_Storage::ME_c_Storage_Driver_Interface * ( * ) ( void ) ) ( Dynamic_Module[ name ] ) [ "_create_storage_driver" ];
		_storage_driver_ = ( ME_c_Storage_Driver_Interface* ) fun();
	}
	bool ME_c_Storage::_register_parser( const std::string category )
	{
		return _register_parser( category, new ME_c_Parser );
	}

	bool ME_c_Storage::_register_parser( const std::string category, ME_c_Parser* parser )
	{
		if ( _parsers_.size() >= _parsers_.max_size() ) return false;
		/// @todo Исключение при попытке превышения размера
		ME_c_Parser * pars;
		pars = 0;
		if ( !( pars = _parsers_[ category ] ) )
		{
			_parsers_[ category ] = parser;
			return true;
		}
		return false;
	}


	bool ME_c_Storage::_unregister_parser( const std::string category )
	{
		std::map<std::string, ME_c_Parser*>::iterator pos;
		pos = _parsers_.find( category );
		if ( pos != _parsers_.end() )
		{
			_parsers_.erase( pos );
			return true;
		}
		return false;
	}

	bool ME_c_Storage::_add_value( const std::string name, const ME_c_Storage_Entry &data )
	{
		ME_c_Storage_Entry * val;
		val = new ME_c_Storage_Entry( data );
		return _add_value( name, val );
	}
	bool ME_c_Storage::_add_value( const std::string name, ME_c_Storage_Entry *data )
	{
		if ( _values_.size() >= _values_.max_size() ) return false;
		/// @todo Исключение при попытке превышения размера
		ME_c_Storage_Entry* val = 0;
		if ( !( val = _values_[ name ] ) )
		{
			//			val = new ME_c_Storage_Entry (data);
			_values_[ name ] = data;
			return true;
		}
		return false;
	}
	bool ME_c_Storage::_modify_value( const std::string name, const ME_c_Storage_Entry& data )
	{
		ME_c_Storage_Entry * val;
		val = new ME_c_Storage_Entry( data );
		if ( _values_.size() >= _values_.max_size() ) return false;
		/// @todo Исключение при попытке превышения размера
		_values_[ name ] = val;
		return true;
	}
	bool ME_c_Storage::_remove_entry ( const std::string name )
	{
		std::map<std::string, ME_c_Storage_Entry*> ::iterator pos;
		pos = _values_.find( name );
		if ( pos != _values_.end() )
		{
			_values_.erase( pos );
			return true;
		}
		return false;
	}

	bool ME_c_Storage::operator() ( std::istream &stream )
	{
		return _storage_driver_->_parse_stream( stream, _parsers_, this );
	}
	const std::map<std::string, ME_c_Storage_Entry*>& ME_c_Storage::_get_all()
	{
		return _values_;
	}
	bool ME_c_Storage::exist( const std::string name )
	{
		if ( _values_.count( name ) > 0 )
		{
			ME_n_Log::_debug( ME_n_Log::ME_DEBUG_INFO ) << __FILE__ << ":" << __LINE__ << "-ME_c_Storage:exist(  " << name << ") is exist" << std::endl;
			_latest_ = name;
			return true;
		}
		ME_n_Log::_debug( ME_n_Log::ME_DEBUG_INFO ) << __FILE__ << ":" << __LINE__ << "-ME_c_Storage:exist(  " << name << ") isn't exist" << std::endl;
		_latest_ = "";
		return false;
	}
	ME_c_Storage_Entry& ME_c_Storage:: operator*()
	{
		ME_n_Log::_debug( ME_n_Log::ME_DEBUG_INFO ) << __FILE__ << ":" << __LINE__ << " - ME_c_Storage: operator*: latest is  " << _latest_ << std::endl;
		if ( _latest_ == "" ) throw( new std::string( "ME_c_Storage::exist wasn`t called before" ) );
		return *operator[] ( _latest_ );
	}


	ME_c_Storage_Entry* ME_c_Storage::operator[] ( const std::string name )
	{
		/// @todo реализовать возвращение объекта(или ссылки) и бросание исключения в случае отсутсвия записи
		ME_c_Storage_Entry * val;
		val = _values_[ name ];
		ME_n_Log::_debug( ME_n_Log::ME_DEBUG_INFO ) << __FILE__ << ":" << __LINE__ << "-ME_c_Storage: _values_[" << name << "]=" << val << std::endl;
		if ( val ) return val;
		return 0;
	}
	const ME_c_Storage_Driver_Interface& ME_c_Storage::_get_driver()
	{
		return * _storage_driver_;
	}
	bool ME_c_Storage::_set_driver( ME_c_Storage_Driver_Interface *drv )
	{
		/// @todo реализовать проверку возможности смены драйвера
		if ( _storage_driver_ ) delete _storage_driver_;
		_storage_driver_ = drv;
		return true;
	}

	template <class T> T ME_n_Storage::ME_c_Storage::_get_value_( const std::string name, const T & def, ME_STORAGE_TYPE entry_type, bool rise_exception )
	{
		if ( exist( name ) )
		{
			ME_c_Storage_Entry * entr;
			entr = operator[] ( name );
			/// @todo Реализовать определение типа с использованием rtti
			if ( entr->_get_type() == entry_type || entry_type==ME_STORAGE_NONE)
			{
				return ( *( T* ) entr->_get_value() );
			}
			if ( rise_exception ) throw( new ME_Exception( ME_STORAGE_TYPE_MISMATCH, "Type mismatch in " + name ) );
			return def;
		}
		else if ( rise_exception ) throw( new ME_Exception( ME_STORAGE_NO_ENTRY, "No such entry " + name ) );
		return def;
	}
	Uint32 ME_c_Storage::_get_value( const std::string name, const Uint32 &def, bool rise_exception )
	{
		return _get_value_( name, def, ME_STORAGE_UINT32, rise_exception );
	}
	Sint32 ME_c_Storage::_get_value( const std::string name, const Sint32 &def, bool rise_exception )
	{
		return _get_value_( name, def, ME_STORAGE_SINT32, rise_exception );
	}
	double ME_c_Storage::_get_value( const std::string name, const double &def, bool rise_exception )
	{
		return _get_value_( name, def, ME_STORAGE_DOUBLE, rise_exception );
	}
	std::string ME_c_Storage::_get_value( const std::string name, const std::string &def, bool rise_exception )
	{
		return _get_value_( name, def, ME_STORAGE_STRING, rise_exception );
	}

}
