/**
 * settings_xml.c: Stores and loads parameters from users to/from XML file
 * 
 * Copyright: See COPYING file that comes with this distribution
 *
 * Author: Matthias Feistel <hitman_47@users.sourceforge.net>, (C) 2007
 */

#include <fstream>
#include <map>
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include "utils.h"
#include "settings.h"
#include "settings_xml.h"
#include "ext/xmlParser/xmlParser.h"

std::string cXmlconfig::LoadXmlfile( const std::string filename )
{
	std::fstream f;
	std::string str_tmp, str_tmp2;
	
	f.open( filename.c_str( ) ) ;
	
	if( f.is_open( ) )
	{
		while( !f.eof( ) ) // Solange noch Daten vorliegen
		{
			getline( f, str_tmp ); // Lese eine Zeile
			str_tmp2.append( str_tmp );
		}
		
		f.close( );
	}
	
	return str_tmp2;
}

/**
 * Load: Read the XML file and fill the values in the appropriate cSettings
 * @return:	errorcode ( 0 == noerror; 1 == profilenotfound )
 */

int cXmlconfig::Load(
		const std::string profilename,
		std::map<std::string,std::string> &ParameterMap,
		std::list<std::string> &FavouriteList
)
{
	// reinit ParameterMap and FavouriteList:
	ParameterMap.clear();
	// Standardparameter init.:
	// Userdetails:
	ParameterMap[ "Username" ] = "";
	ParameterMap[ "Password_md5" ]= "";
	// Other settings:
	ParameterMap[ "Receivermode" ] = "0";
	ParameterMap[ "Scrobblemode" ] = "0";
	// OSD settings:
	ParameterMap[ "Albumcovermode" ] = "0";
	ParameterMap[ "Osd_Mode" ] = "0";
	ParameterMap[ "Osd_Autostartmode" ] = "1";
	ParameterMap[ "Osd_Refreshinterval" ] = "13";
	
	FavouriteList.clear();
	
	
	
	std::string configfileurl;
	
	XMLNode xMainNode, xNode_Favourites, xNode_ProfileList, xNode_Profile,
			xMainNode_tmp;
	XMLResults xe;
	
	configfileurl = cSettings::GetInstance().GetXmlconfig_Fileurl( );
	
	xMainNode = XMLNode::parseString( cXmlconfig::LoadXmlfile(
							configfileurl ).c_str( ), "LastfmData", &xe );
	
	
	// single profile
	xNode_ProfileList = xMainNode.getChildNode( "ProfileList" ); // look for profilelist node
	

	if( !xNode_ProfileList.isEmpty( ) )
	{
		// look for existing profile
		xNode_Profile = xNode_ProfileList.getChildNodeWithAttribute( "Profile",
				"ProfileName", profilename.c_str( ) ); // look for profilelist node

		if( xNode_Profile.isEmpty( ) )
			return 1;
		
		
		
		
		// parse the profile node:
		int n = xNode_Profile.nChildNode( );
		std::string nodename, nodevalue;
		
		for( int i = 0; i < n-1; i++ ) // n-1: do not read favourite node
		{
			nodename = xNode_Profile.getChildNode( i ).getName( );
			nodevalue = xNode_Profile.getChildNode( i ).getText( );

			ParameterMap[ nodename ] = nodevalue;
		}
		
		
		// Favourites:
		xNode_Favourites = xNode_Profile.getChildNode( "FavouriteList" );
	}
	
	int n = xNode_Favourites.nChildNode( );
	std::string nodename, nodevalue;
	
	for( int i = 0; i < n; i++ )
	{
		nodename = xNode_Favourites.getChildNode( i ).getName( );
		nodevalue = xNode_Favourites.getChildNode( i ).getText( );
		
		FavouriteList.push_back( nodevalue );
	}
	
	
	// sort favouritelist
	// data will be sorted here, because of new entered items by user;
	// these items have not been stored in setup.conf, yet.
	FavouriteList.sort( cUtils::compare_nocase );
	
	return 0;
}

int cXmlconfig::Save(
		const std::string profilename,
		std::map<std::string,std::string> ParameterMap,
		std::list<std::string> FavouriteList
)
{
	std::string configfileurl;
	
	XMLNode xMainNode, xNode_Favourites, xNode_ProfileList, xNode_Profile;
	std::stringstream sstream_tmp;
	std::string str_tmp;
	XMLResults xe;

	configfileurl = cSettings::GetInstance().GetXmlconfig_Fileurl( );

	// check, whether we have already a XMLfile with XMLTopNode: create or append
	xMainNode = XMLNode::parseString( cXmlconfig::LoadXmlfile( configfileurl ).c_str( ), "LastfmData", &xe );

	if( xe.error ) // an error occured, so we assume there is no xml data.
	{
		xMainNode = XMLNode::createXMLTopNode( "LastfmData" );
		// profilelist:
		xNode_ProfileList = xMainNode.addChild( "ProfileList" );
	}

	////////////////////////////////////////////////////////////////////////////

	// single profile
	xNode_ProfileList = xMainNode.getChildNode( "ProfileList" ); // look for profilelist node

	if( xNode_ProfileList.isEmpty( ) )
		xNode_ProfileList = xMainNode.addChild( "ProfileList" );

	// look for existing profile
	xNode_Profile = xNode_ProfileList.getChildNodeWithAttribute( "Profile",
			"ProfileName", profilename.c_str( ) ); // look for profilelist node

	
	// Before creating or updating, we clear the node and all subnodes.
	// So, we will not have duplicates:
	// But save the Password_md5 temporarily before!
	std::string Password_md5_str;
	
	if( !xNode_Profile.getChildNode( "Password_md5" ).isEmpty() )
	{
		Password_md5_str = xNode_Profile.getChildNode( "Password_md5" ).getText( );
		ParameterMap[ "Password_md5" ] = Password_md5_str;
	}
	xNode_Profile.deleteNodeContent( );

	
	xNode_Profile = xNode_ProfileList.addChild( "Profile" );
	xNode_Profile.addAttribute( "ProfileName", profilename.c_str( ) );

	// standardparameters:
	for( std::map<std::string, std::string>::iterator elParameterMap = ParameterMap.begin( );
			elParameterMap!= ParameterMap.end( );
			elParameterMap++
	)
	{
		if( !elParameterMap->second.empty( ) )
			xNode_Profile.addChild(
					elParameterMap->first.c_str() ).updateText( elParameterMap->second.c_str( ) );
	}

	// Favourites:
	xNode_Favourites = xNode_Profile.addChild( "FavouriteList" );

	for( std::list<std::string>::iterator it = FavouriteList.begin( );
		it!= FavouriteList.end( );
		it++
	)
	{
		std::string it_string = *it;

		if( !it_string.empty( ) )
		xNode_Favourites.addChild( "Favourite" ).updateText( it_string.c_str( ) );
	}

	// sort favouritelist
	// data will be sorted here, because of new entered items by user;
	// these items have not been stored in setup.conf, yet.
	FavouriteList.sort( cUtils::compare_nocase );

	// store the CountOfChildren attribute:
	sstream_tmp.clear( );
	sstream_tmp.str( "" );
	sstream_tmp << xNode_Favourites.nChildNode( );
	xNode_Favourites.updateAttribute( sstream_tmp.str( ).c_str( ), "Count" );

	// store the CountOfChildren attribute:
	sstream_tmp.clear( );
	sstream_tmp.str( "" );
	sstream_tmp << xNode_ProfileList.nChildNode( );
	xNode_ProfileList.updateAttribute( sstream_tmp.str( ).c_str( ), "Count" );

	// Finally, store the file:
	xMainNode.writeToFile( configfileurl.c_str( ) );

	return 0;
}

std::list<std::string> cXmlconfig::GetProfilenames( )
{
	std::list<std::string> profilelist;
	XMLNode xMainNode, xNode_Favourites, xNode_ProfileList, xNode_Profile;
	XMLResults xe;
	
	std::string configfileurl(cSettings::GetInstance().GetXmlconfig_Fileurl( ) );
	
	xMainNode = XMLNode::parseString( cXmlconfig::LoadXmlfile( configfileurl ).c_str( ), "LastfmData", &xe );
	
	if( xe.error )
		return profilelist;
	
	xNode_ProfileList = xMainNode.getChildNode( "ProfileList" ); // look for profilelist node
	int n = xNode_ProfileList.nChildNode( );
	std::string attributename;
	
	for( int i = 0; i < n; i++ )
	{
		attributename = xNode_ProfileList.getChildNode( i ).getAttribute( "ProfileName" );
		profilelist.push_back( attributename );
	}

	
	return profilelist;
}

int cXmlconfig::DeleteProfile( const std::string profilename )
{
	std::string configfileurl;
	std::map<std::string, std::string>::iterator elParameterMap;
	XMLNode xMainNode, xNode_Favourites, xNode_ProfileList, xNode_Profile;
	std::stringstream sstream_tmp;
	std::string str_tmp;
	XMLResults xe;
	
	configfileurl = cSettings::GetInstance().GetXmlconfig_Fileurl( );
	
	
	// check, whether we have already a XMLfile with XMLTopNode: create or append
	xMainNode = XMLNode::parseString( cXmlconfig::LoadXmlfile( configfileurl ).c_str( ), "LastfmData", &xe );
	
	if( xe.error ) // an error occured, so we assume there is no xml data.
	{
		return 1;
	}
	
	
	// single profile
	xNode_ProfileList = xMainNode.getChildNode( "ProfileList" ); // look for profilelist node

	// look for existing profile
	if( !xNode_ProfileList.isEmpty( ) )
		xNode_Profile = xNode_ProfileList.getChildNodeWithAttribute( "Profile",
				"ProfileName", profilename.c_str( ) ); // look for profilelist node

	if( !xNode_ProfileList.isEmpty( ) )
		xNode_Profile.deleteNodeContent( );
	
	// store the CountOfChildren attribute:
	sstream_tmp.clear( );
	sstream_tmp.str( "" );
	sstream_tmp << xNode_ProfileList.nChildNode( );
	xNode_ProfileList.updateAttribute( sstream_tmp.str( ).c_str( ), "Count" );

	// Finally, store the file:
	xMainNode.writeToFile( configfileurl.c_str( ) );
	
	return 0;
}
