/***************************************************************************

    supportware
    Copyright (C) 2001-2008 by c.holzheuer
    c.holzheuer@sourceworx.org

    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.

***************************************************************************/


#include <ddusersessionmanager.h>
#include <sxsites.h>
#include <dditemlink.h>
#include <sstream>

/**
	Gibt true zurück, falls der ensprechende user gerade online ist.
*/

bool ddusersessionmanager::is_member_online( const ddstring& nickname )
{
	// deadlock !? NICHT INTERN benutzen
	ddthreadautomutex tmplock( _listlock );	
	return _membermap.contains_key( nickname );

}


int	ddusersessionmanager::session_count()
{
	ddthreadautomutex tmplock( _listlock );	
	return size();
}

  
  
void ddusersessionmanager::add_admin_access( dduserid* userid, const ddstring& access )
{	
	// den admin-pointer merken ...
	_adminset.insert( userid );
	// und die zugriffsrechte merken
	_accessmap[ userid->get_nick_name() ] = access.as_int();
}
	
	
	
/**
	@return the user with sessionkey "key" or 0 on mismatch.
*/

dduserid* ddusersessionmanager::get_user_id( const ddstring& key )
{
	ddthreadautomutex tmplock( _listlock );	
	
	ddmapindex::const_iterator pos = _index.find( key );
	if( pos == _index.end() )
		return 0;	
	
	_data[(*pos).second]->update_access_time();
	
	return _data[(*pos).second];
	
}


/**
	Die Zugriffsrechte für eine UserID setzen.
*/

void ddusersessionmanager::set_access_rights( dduserid* userid )
{	
	// adminrechte setzen
	int access = _accessmap[ userid->get_nick_name() ];
	// 2 heisst standard-member
	userid->set_access_rights( access ?  access : 2 );
}


/**
	Den pointer auf eine UserID speichern.
*/

void ddusersessionmanager::add_user_id( const ddstring& key, dduserid* userid )
{
	ddthreadautomutex tmplock( _listlock );	
	
	_data.push_back( userid );
	_index[key] = _data.size()-1;
	
	userid->update_access_time();
	

	if( userid->is_member() )
		//_membermap.insert( userid );
		_membermap.add_by_key( userid->get_nick_name(), userid );

}


/**
	Drop all sessions (==userids) with a certain age.
*/

void ddusersessionmanager::cleanup_sessions()
{
	/*
		Hier soll folgendes passieren:
		
		alle uids, die älter als der timeout sind, werden
		weggeschmissen.
		Falls es sich um guests handeln, müssen sie deletet werden.
		die anderen werden wieder in den daten vector übernommen,
		wobei der index auch neu aufgebaut werden muss.
	*/
	 
	ddthreadautomutex tmplock( _listlock );	

	vector<dduserid*> newdata;
	ddmapindex 				newindex;
	
	time_t now = ::time(0);
	

	ddmapindex::const_iterator pos = _index.begin();
  for( ; pos != _index.end(); ++pos )
  {
		
		int i = (*pos).second;
		dduserid* uid = _data[i];
		
		//stringstream sstr;
		//sstr << ":" << (*pos).first << ":" << i << ":" << hex << (size_t) uid;
		//ddstring msg = sstr.str(); ":" + (*pos).first + ":" + ddstrutil::from_int( i ) + ":" + ddstrutil::from_size_t( (size_t) uid );
		
		//log_debug( "TRY: " + msg );
		size_t maxage = now - uid->get_access_time();
		//log_debug( "OK:  " + msg );
		
		// userid ist noch jung genug
		if( maxage < DDMAXSESSIONAGE )
		{
      // id sichern
			newdata.push_back( uid );
      // schlüssel auch sichern
			newindex[(*pos).first] = newdata.size()-1;
			continue;
		}
		
		// ab hier: userid abgelaufen
		
		// member tabelle ungültig setzen
		if( uid->is_member() )
			_membermap.remove_entry( uid->get_nick_name() );
		// guests löschen
		else if( !uid->user_is_locked() )
			delete uid;				

  } // for
	
	// tauscht die __datenpointer__ von _data und newdata.
	// beim abräumen von newdata wird der destructor der "alten" daten
	// _nicht_ aufgerufen ( wg. typ vector<*> ). Das ist Absicht, die 
	// die daten von ddusermanager verwaltet werden.
	
	_data.swap( newdata );	
	_index.swap( newindex );
	//erase( begin()+index );
	//erase( remove( begin(), end(), entry ), end() );
}


/**
	Rendert den 'members online' kasten. Das stand mal in 
	'sxblockmemberbox', war aber instabil wegen locking problemen.
*/

/*
void ddusersessionmanager::create_block_memberbox( ddstring& result )
{
	
	ddthreadautomutex tmplock( _listlock );	
	
	result = "";
	set<ddstring>	checkset;
	dditemlink link( "sn_subbody" );
	ddstring base="<li>";
	int max = size();
	int len = 0;
	int i = max;
	
	while( i && len<max )
	{
		const ddstring& nick = _data[i-1]->get_nick_name();
		// das crashed	
		size_t uc = checkset.count(nick );
		
		if( _data[i-1]->is_member() && !uc )
		{			
			checkset.insert( nick );
			ddwebsite::create_user_link( link, _data[i-1]->get_id(), nick );
			result += base + link.to_string()+"<br>\n";
			len++;
		}				
		--i;
	}

}
*/





/**
	rendert die teambox. Alte Version.
*/

const ddstring& ddusersessionmanager::create_team_box()
{
	
	ddthreadautomutex tmplock( _listlock );	

	_teambox = "";	
	//return _teambox;
		
	if( _adminset.size() > 0 )
	{
		dditemlink link( "sn_subbody" );
		ddstring base="<li>";
		dduseridset::const_iterator pos = _adminset.begin();
		for( ; pos != _adminset.end(); ++pos )
		{	
			
			//ddstring msg = " pointer:" + ddstrutil::from_size_t( (size_t) (*pos) );				
			//log_debug( "TRY-: " + msg );		
						
			const ddstring& nick = (*pos)->get_nick_name();
			
			//log_debug( "OK--: " + msg );
			
			// FIX: hack: chat admins & tonja Ssollen nicht angezeigt werden
			if( _accessmap[ nick ] == 8194 || _accessmap[ nick ] == 578 )
				continue;
			
			//ddwebsite::create_user_link( link, *(*pos) );
			ddwebsite::create_user_link( link, (*pos)->get_id(), nick );
	
			_teambox += base+link.to_string();				
			if( _membermap.contains_key( nick ) )
				_teambox += "*";
			_teambox += "</li>\n";
		}
	}
	
	return _teambox;
	
}



const ddstring& ddusersessionmanager::create_member_box()
{
  
  ddthreadautomutex tmplock( _listlock );	
		
	_memberbox = "";
	//return _memberbox;
	
	if( !_membermap.empty() > 0 )
	{
		
		dditemlink link( "sn_subbody" );
		ddstring base="<li>";
		
		// rückwärts: die neuesten oben
		for( int i = _membermap.size() - 1; i >= 0; --i )
  	{	
  		
  		//ddstring msg = " pointer:" + ddstrutil::from_size_t( (size_t) _membermap[i] );		
			//log_debug( "TRY+: " + msg );
		
  		const ddstring& nick = _membermap[i]->get_nick_name();
		  
		  //log_debug( "OK++: " + msg );
		  
		  ddwebsite::create_user_link( link, _membermap[i]->get_id(), nick );
			
			_memberbox += base + link.to_string()+"<br>\n";		
		}
	}
	return _memberbox;
	
}


/**
	Dump all active session .
*/

void ddusersessionmanager::dump() const
{
	/*
	ddmapindex::const_iterator pos = _index.begin();
  for( ; pos != _index.end(); ++pos )
  {		
		_data[(*pos).second]->dump();
  }
  */
}


