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

    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 <sxpageadmin.h>
#include <dditemset.h>
#include <dditemlink.h>

#include <ddwebconnection.h>
#include <ddwebpage.h>
#include <ddwebserver.h>
#include <ddwebfile.h>
#include <ddweboverlay.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>


/**
	Constructor.
*/

sxpageadmin::sxpageadmin( const ddstring& name, ddwebsite* site )
: sxpage( name, site, "Administration" )
{		


	// neu: den ganzen alten dreck einsammeln	
	add_request_handler( "guestbook",				 			"xx_dummy",		(ddmemptr) &sxpageadmin::on_redirect );
	add_request_handler( "sales",				 					"xx_dummy",		(ddmemptr) &sxpageadmin::on_redirect );
	add_request_handler( "salesthread",				 		"xx_dummy",		(ddmemptr) &sxpageadmin::on_redirect );
	add_request_handler( "salescomthread",				"xx_dummy",		(ddmemptr) &sxpageadmin::on_redirect );
	add_request_handler( "salethread",				 		"xx_dummy",		(ddmemptr) &sxpageadmin::on_redirect );
	add_request_handler( "salecomthread",				 	"xx_dummy",		(ddmemptr) &sxpageadmin::on_redirect );
	
	// neu: wir kümmern uns auch noch um den adminpager.	
	add_request_handler( "admin_pager",				 		"xx_admin_pager_overview",		(ddmemptr) &sxpageadmin::admin_pager,1, dduserid::usr_is_admin );
	add_request_handler( "admin_pager_kill_msg", 	"xx_admin_pager_overview", 		(ddmemptr) &sxpageadmin::admin_pager_kill_msg, 1, dduserid::usr_can_edit_news );
	
	// alter kram
	add_request_handler( "admin_change_nick",			"xx_admin_change_nick", 			(ddmemptr) &sxpageadmin::admin_change_nick,1,dduserid::usr_is_root );

	add_request_handler( "admin_hits",		 				"xx_admin_hits",							(ddmemptr) &sxpageadmin::admin_hits, 			1, dduserid::usr_is_admin );  
 	add_request_handler( "admin_sessions",			 	"xx_admin_sessions",					(ddmemptr) &sxpageadmin::admin_sessions,	1, dduserid::usr_is_admin );
 	
	add_request_handler( "votings",  						 	"xx_admin_votings_overview",	(ddmemptr) &sxpageadmin::admin_votings_overview,		1, dduserid::usr_is_admin );
	add_request_handler( "postings", 						 	"xx_admin_postings_overview",	(ddmemptr) &sxpageadmin::admin_postings_overview );
	
	add_request_handler( "admin_halt", 						"xx_dummy",					 					(ddmemptr) &sxpageadmin::admin_halt, 				1, dduserid::usr_is_root ); 
  
  add_request_handler( "admin_aliases",		 			"xx_admin_aliases",						(ddmemptr) &sxpageadmin::admin_aliases,		 	1, dduserid::usr_is_admin ); 
	add_request_handler( "admin_aliases_kill",		"xx_admin_aliases",						(ddmemptr) &sxpageadmin::admin_aliases, 		1, dduserid::usr_is_admin ); 

  add_request_handler( "admin_redirects", 			"xx_admin_redirects",					(ddmemptr) &sxpageadmin::admin_redirects, 	1, dduserid::usr_is_admin ); 
	add_request_handler( "admin_redirects_kill",	"xx_admin_redirects",					(ddmemptr) &sxpageadmin::admin_redirects, 	1, dduserid::usr_is_admin ); 

  add_request_handler( "admin_block_ip", 				"xx_admin_block_ip",					(ddmemptr) &sxpageadmin::admin_block_ip, 		1, dduserid::usr_is_admin ); 
  add_request_handler( "admin_unblock_ip", 			"xx_admin_block_ip",					(ddmemptr) &sxpageadmin::admin_block_ip, 		1, dduserid::usr_is_admin );
  
  add_request_handler( "admin_block_mail", 			"xx_admin_block_mail",				(ddmemptr) &sxpageadmin::admin_block_mail, 	1, dduserid::usr_is_admin ); 
  add_request_handler( "admin_unblock_mail", 		"xx_admin_block_mail",				(ddmemptr) &sxpageadmin::admin_block_mail, 	1, dduserid::usr_is_admin );
  
  add_request_handler( "admin_block_word", 			"xx_admin_block_word",				(ddmemptr) &sxpageadmin::admin_block_word,	1, dduserid::usr_is_admin );
  add_request_handler( "admin_unblock_word", 		"xx_admin_block_word",				(ddmemptr) &sxpageadmin::admin_block_word,	1, dduserid::usr_is_admin );
	
	add_request_handler( "admin_censor_word", 		"xx_admin_censor_word",				(ddmemptr) &sxpageadmin::admin_censor_word,	1, dduserid::usr_is_admin );
  add_request_handler( "admin_uncensor_word", 	"xx_admin_censor_word",				(ddmemptr) &sxpageadmin::admin_censor_word,	1, dduserid::usr_is_admin );
	
	add_request_handler( "admin_linkmap",			 		"xx_admin_linkmap",						(ddmemptr) &sxpageadmin::admin_linkmap,			1, dduserid::usr_can_edit_news );
  add_request_handler( "admin_linkmap_create",	"xx_admin_linkmap",						(ddmemptr) &sxpageadmin::admin_linkmap,			1, dduserid::usr_can_edit_news ); 
  add_request_handler( "admin_linkmap_kill",		"xx_admin_linkmap",						(ddmemptr) &sxpageadmin::admin_linkmap,			1, dduserid::usr_can_edit_news );
  add_request_handler( "admin_linkmap_edit",		"xx_admin_linkmap",						(ddmemptr) &sxpageadmin::admin_linkmap,			1, dduserid::usr_can_edit_news );
	
	add_request_handler( "admin_imagemap",			 	"xx_admin_imagemap",					(ddmemptr) &sxpageadmin::admin_imagemap,		1, dduserid::usr_can_edit_news );
	add_request_handler( "admin_imagemap_create",	"xx_admin_imagemap",					(ddmemptr) &sxpageadmin::admin_imagemap,		1, dduserid::usr_can_edit_news );
  add_request_handler( "admin_imagemap_kill",		"xx_admin_imagemap",					(ddmemptr) &sxpageadmin::admin_imagemap,		1, dduserid::usr_can_edit_news );
 	add_request_handler( "admin_imagemap_edit",		"xx_admin_imagemap",					(ddmemptr) &sxpageadmin::admin_imagemap,		1, dduserid::usr_can_edit_news );
 
	
	add_request_handler( "admin_kill_entry",	 		"xx_dummy",										(ddmemptr) &sxpageadmin::admin_kill_entry,	1, dduserid::usr_is_admin  );

	//add_request_handler( "admin_list_pictures_json", 	"xx_ajax_list_flat",						(ddmemptr) &sxpageadmin::admin_list_pictures_json_flat );	
	//add_request_handler( "admin_list_pictures", 	"xx_admin_list_pictures",			(ddmemptr) &sxpageadmin::admin_list_pictures );
	//add_request_handler( "admin_kill_picture", 		"xx_admin_list_pictures",			(ddmemptr) &sxpageadmin::admin_kill_picture );
		
	add_request_handler( "admin_watch_add",	 			"xx_dummy" , 									(ddmemptr) &sxpageadmin::admin_watch_change );
	add_request_handler( "admin_watch_drop",	 		"xx_dummy", 									(ddmemptr) &sxpageadmin::admin_watch_change );
	add_request_handler( "admin_watch_update",		"xx_dummy", 									(ddmemptr) &sxpageadmin::admin_watch_change );
	
	

	
	add_request_handler( "ajax_link",							"xx_ajax_link",								(ddmemptr) &sxpageadmin::ajax_link );
	add_request_handler( "ajax_block",						"xx_ajax_block",							(ddmemptr) &sxpageadmin::ajax_block );
	add_request_handler( "ajax_test",							"xx_rss_faqs",								(ddmemptr) &sxpageadmin::ajax_test );
	
	add_request_handler( "broken_link",						"xx_admin_broken_link",				(ddmemptr) &sxpageadmin::admin_broken_link );




	// für die neuen generatoren
	_monthmap["januar"] 		= "1";
	_monthmap["februar"] 		= "2";
	_monthmap["maerz"] 			= "3";
	_monthmap["april"] 			= "4";
	_monthmap["mai"] 				= "5";
	_monthmap["juni"] 			= "6";
	_monthmap["juli"] 			= "7";
	_monthmap["august"] 		= "8";
	_monthmap["september"] 	= "9";
	_monthmap["oktober"] 		= "10";
	_monthmap["november"] 	= "11";
	_monthmap["dezember"] 	= "12";

	_monthnames.add( "januar" );
	_monthnames.add( "februar" );
	_monthnames.add( "maerz" );
	_monthnames.add( "april" );
	_monthnames.add( "mai" );
	_monthnames.add( "juni" );
	_monthnames.add( "juli" );
	_monthnames.add( "august" );
	_monthnames.add( "september" );
	_monthnames.add( "oktober" );
	_monthnames.add( "november" );
	_monthnames.add( "dezember" );

	_monthlenghts.push_back( 31 );
	_monthlenghts.push_back( 28 );
	_monthlenghts.push_back( 31 );
	_monthlenghts.push_back( 30 );
	_monthlenghts.push_back( 31 );
	_monthlenghts.push_back( 30 );
	_monthlenghts.push_back( 31 );
	_monthlenghts.push_back( 31 );
	_monthlenghts.push_back( 30 );
	_monthlenghts.push_back( 31 );
	_monthlenghts.push_back( 30 );
	_monthlenghts.push_back( 31 );

	/*
	+----------+----------+
	| id_group | countall |
	+----------+----------+
	|        5 |      491 |
	|        6 |      120 |
	|        4 |      118 |
	|       46 |       61 |
	|       56 |       54 |
	|       55 |       44 |
	|       16 |       34 |
	|       40 |       34 |
	|       15 |       34 |
	|       18 |       32 |
	|        9 |       21 |
	|       17 |       21 |
	|       42 |       18 |
	|        3 |       17 |
	|       41 |       16 |
	|       48 |       15 |
	|       49 |       13 |
	|       11 |       12 |
	|       21 |       11 |
	|       45 |       10 |
	|       39 |        9 |
	|       30 |        8 |
	|        1 |        6 |
	|       10 |        6 |
	|       51 |        6 |
	|        2 |        4 |
	|       22 |        4 |
	|        7 |        4 |
	|        8 |        4 |
	|       33 |        4 |
	|       34 |        3 |
	|       54 |        3 |
	|       29 |        2 |
	|       20 |        2 |
	|       31 |        1 |
	|       47 |        1 |
	|       27 |        1 |
	|       50 |        1 |
	+----------+----------+

	*/

	// -- PFUSCH!, das sollte automatisch erzeugt werden.
	_groupmap.add_by_key( "windows98", 					"5" );
	_groupmap.add_by_key( "windowsnt", 					"6" );
	_groupmap.add_by_key( "windows95", 					"4" ); 
	_groupmap.add_by_key( "e-mail-outlook", 		"46" );
	_groupmap.add_by_key( "windows-7", 					"56" );
	_groupmap.add_by_key( "windowsvista", 			"55" );
	_groupmap.add_by_key( "pc-sonstiges", 			"16" );
	_groupmap.add_by_key( "windowsxp", 					"40" );
	_groupmap.add_by_key( "hw-sonstiges", 			"15" );
	_groupmap.add_by_key( "bildbearbeitung", 		"18" );
	_groupmap.add_by_key( "webseiten-html", 		"9" );
	_groupmap.add_by_key( "linux", 							"17" );
	_groupmap.add_by_key( "sw-sonstige", 				"42" );
	_groupmap.add_by_key( "sn-intern", 					"3" ); 
	_groupmap.add_by_key( "telekommunikation",	"41" );
	_groupmap.add_by_key( "internet-browser", 	"48" );
	_groupmap.add_by_key( "mainboard-cpu-ram",	"49" );
	_groupmap.add_by_key( "audio-mp3-video", 		"11" );
	_groupmap.add_by_key( "textverarbeitung", 	"21" );
	_groupmap.add_by_key( "security-viren", 		"45" );
	_groupmap.add_by_key( "bs-sonstige", 				"39" );
	_groupmap.add_by_key( "test", 							"30" );
	_groupmap.add_by_key( "news", 							"1" ); 
	_groupmap.add_by_key( "nw-sonstiges", 			"10" );
	_groupmap.add_by_key( "peripherie", 				"51" );
	_groupmap.add_by_key( "evil", 							"2" ); 
	_groupmap.add_by_key( "tabellenkalkulation","22" );	
	_groupmap.add_by_key( "isdn", 							"7" );	
	_groupmap.add_by_key( "modem", 							"8" );
	_groupmap.add_by_key( "dsl", 								"33" );
	_groupmap.add_by_key( "skripte", 						"34" );	
	_groupmap.add_by_key( "w-lan", 							"54" );
	_groupmap.add_by_key( "pda-mobile", 				"29" );
	_groupmap.add_by_key( "plauderecke", 				"20" ); 	
	_groupmap.add_by_key( "windows2000", 				"31" );
	_groupmap.add_by_key( "praesentation", 			"47" );
	_groupmap.add_by_key( "anwendungen", 				"27" ); 
	_groupmap.add_by_key( "grafikkarten", 			"50" );
	_groupmap.add_by_key( "datenbanken", 				"23" );
	_groupmap.add_by_key( "digitalkameras", 		"28" );
	_groupmap.add_by_key( "windowsme", 					"35" );
	_groupmap.add_by_key( "kuehlung-modding", 	"53" );
	_groupmap.add_by_key( "admingruppe", 				"13" );
	
	
	add_request_handler( "create_master_index",		"xx_archive_index", (ddmemptr) &sxpageadmin::create_master_index );
	// hack um das item anzumelden
	add_request_handler( "create_master_moo",			"xx_archive_list",  (ddmemptr) &sxpageadmin::create_master_index );

}


/**
	Redirect alten contents
*/

dd_result sxpageadmin::on_redirect( dditem& item )
{
	return create_redirect( "/linknotfound?sn_key=" + get_full_path().dup().escape(), ret_301_moved_permanently );
}


/**
 	Die Pager-Seite anzeigen, Design ala iPhone
 	Links werden 'aktive Kontakte', also Empfänger und Absender von meinen
 	PMs, als Liste angezeigt, im Body dann die Kommunikation mit einem
 	Partner in ihrer zeitlichen Abfolge.
*/

dd_result sxpageadmin::admin_pager( dditem& item )
{

	// shortcuts
	ddwebview& table = get_view();
//return rs_ok;
	// alles hübsch machen
	dditem& block = get_body()["sn_form"];
	block.clear_children(); 
  block.clear_value();	
	// und ab
	context.numrows = table.fill( "admin_pager_overview");			
	// ...testen...
	if( context.numrows <= 0 )
		return create_hint_box( block, DDHINTNOMESSAGE );	
	
	// nur den 'virtuellen' Ausschnitt rendern
	table.on_render( *this, block["sn_pager_loop"] );	
	
	return rs_ok;

}


dd_result sxpageadmin::admin_pager_kill_msg( dditem& item )
{
  
  get_view().execute( "admin_pager_kill_msg", get_cgi() );	
	return create_redirect( "/admin_pager" );
	
}


/**
	Fehlerseite für dead links anzeigen
*/

dd_result sxpageadmin::admin_broken_link( dditem& item )
{
	
	dditem& body = get_body()["sn_subbody"];
	body["sn_link1"].from_string( get_cgi()["sn_link"] );
	body["sn_link2"].from_string( get_cgi()["sn_link"] );
	
	return rs_ok;
	
	
	
}







/**
	Ajax Test: Einzellinks
*/

dd_result sxpageadmin::ajax_link( dditem& item )
{
	
	// hack: nullstring ala igor
	item.from_string("[]");
	
	context.contenttype = "application/json;charset=iso-8859-1";//text/xml; charset=iso-8859-1";//application/atom+xml";
	
	const ddstring& key = get_cgi()["sn_key"];
	if( key.empty() )
		return rs_ok;
	
	ddweboverlaylink overlay;
	if( !get_site().get_overlay_links().find_link_tag( key, overlay ) )
		return rs_ok;
	
	/*
	// hack:
	overlay.key 	= "testkey";
	overlay.link 	= "testlink";
	overlay.comment = "testcomment";
	*/
	
	item.clear_value();
	item["sn_key"].from_string( "\"" + overlay.key + "\"" );
	item["sn_link"].from_string( "\"" + overlay.link + "\"" );
	item["sn_comment"].from_string( "\"" + overlay.comment + "\"" );
	
	return rs_ok;
	
}


/**
	Ajax Test: baut einen JSON-Block aus linkvorschlägen für im text
	(sn_msgbody) vorhandene Schlüsselbegriffe.
	
	Beispiel:
		
	{"Key":"homepage","Comment":"Wie erstellt man eine Webseite / Homepage (html)?","Link":"http://www.supportnet.de/faqsthread/887"},
	{"Key":"supportnet","Comment":"Supportnet - Computer und Internet Forum","Link":"http://www.supportnet.de"}
	...


	Neu:
	
	Vorgehen bei Replies:
	
	Ersetzungen werden nicht automatisch vorgenommen, es existiert ein button 'Links vorschlagen', der ein popup-layer erzeugt,
	in dem Ersetzungsvorschläge aufgelistet sind. Beim klick auf einen Vorschlag wird dieser per Javascript in den Text übernommen.
	Bei Erstellung der Vorschlags-Liste muss darauf geachtet werden, dass nicht innerhalb von link- oder code-tags ersetzt wird.
	Es sollen alle machbaren Ersetzungen vorgeschlagen werden, nicht nur das 'First-match'
	
*/

dd_result sxpageadmin::ajax_block( dditem& item )
{
	
	context.contenttype = "application/json;charset=iso-8859-1";//text/xml; charset=iso-8859-1";//application/atom+xml";
	
	
	item.from_string("[]");
	ddstring result;
	
	// daten checken
	const ddstring& msg = get_cgi()["sn_msgbody"];
	if( msg.empty() )
		return rs_ok;
	
	// erbegnisliste aufbauen
	ddweboverlaylinkmap list;
	if( !get_site().get_overlay_links().find_link_tags( msg, list ) )
		return rs_ok;
	
	// säubern
	item.clear_value();
	dditem& block = item["sn_linkblock"];	
	block.clear_value();
	
	for( int i = 0; i < list.size(); ++ i )
	{
		const ddweboverlaylink& overlay = list[i];
		// werte übernehmem
		block["sn_key"].from_string( "\"" + overlay.key + "\"" );
		block["sn_link"].from_string( "\"" + overlay.link + "\"" );
		block["sn_comment"].from_string( "\"" + overlay.comment + "\"" );
		// speichern
		result += block.to_string();
			
		// komma nicht im letzten eintrag
		if( i < list.size()-1 ) 
			result += ',';
	}
	
	item["sn_linkblock"].from_string( result );
	
	return rs_ok;
	
}

dd_result sxpageadmin::ajax_test( dditem& item )
{
	
	context.contenttype = "application/json;charset=iso-8859-1";//text/xml; charset=iso-8859-1";//application/atom+xml";
	//context.contenttype = "text/xml; charset=iso-8859-1";
	ddusermanager& uma = get_user_manager();
	const ddstring& nick = get_split_path()[1];
	item.from_string( "ok" );	
	if( uma.index_of( nick.as_lower() ) >= 0 || !uma.check_nickname_valid( nick ) )
		item.from_string( "nickname" );
	
	return rs_ok;
	
}

/**
	Ändert den Nickname eines users. Root only.
*/

dd_result sxpageadmin::admin_change_nick( dditem& item )
{
	
	dditem& block = get_body()["sn_subbody"];
	block.clear_value();
	ddusermanager& mgr = get_user_manager();
	ddstring id = get_cgi()["id"];
	ddstring newnick = get_cgi()["sn_nicknew"];
	ddstring oldnick = mgr.get_nick_name( id );
	
	block["id"].from_string( id );
	block["sn_nickold"].from_string( oldnick );
	// nix? dann abhauen
	if( newnick.empty() )
		return rs_ok;
	
	mgr.usr_change_nickname( oldnick, newnick );
	block.from_string( "<h3>'" + oldnick + "' heisst jetzt '" + newnick + "'<h3>" );
	
	return rs_ok;
	
	(void) item;
}
/**
	Einen Eintrag physikalisch löschen.
*/

dd_result sxpageadmin::admin_kill_entry( dditem& item )
{
	get_view().execute( "admin_kill_entry", context.id );	
	// anzeige updaten	
	get_site().get_user_content_count() = "";
	return create_redirect( "/admin_user_content" );
	
	(void) item;
}


/**
	Bilder für einen Artikel anzeigen.
*/

dd_result sxpageadmin::admin_list_pictures( dditem& item )
{
	if( get_split_path().size() < 2 )
		return create_hint_box( get_body(), "Kein Verzeichnis angegeben!" );
		
	ddioinfo dirinfo;
	ddstring realdir = ddstring(DDPICPATH) + "sn_" + get_site().get_name() + "/" + context.id;
	try
	{
		dirinfo.load_files( realdir ); 
	}
	catch( exception& error )
	{
		::system( "pwd" );
		return create_hint_box( get_body(), "Fehler: Keine Bilder vorhanden" );
	}
  
 	size_t max = dirinfo.size();
	if( !max )
		return create_hint_box( get_body(), "Keine Bilder vorhanden" );
	
	get_body().clear_value();
	dditem& sub = get_body()["sn_subbody"];		
  sub.clear_value();
  ddstring result;
  for( size_t i=0; i<max; ++i )
  {
  	ddstring name = DDPICPATH + context.id + "/" + dirinfo[i].get_full_name();
  	// PFUSCH
  	sub["id"].from_string( context.id );
  	sub["sn_image0"].from_string( dirinfo[i].get_full_name() );
  	sub["sn_image1"].from_string(  dirinfo[i].get_full_path() );
  	sub["sn_image2"].from_string( name );
  	sub["sn_image3"].from_string( name );
  	result += sub.to_string();
	}
	sub.from_string( result );
	
	return rs_ok;		
}



/**
	Ein Bild löschen
*/

dd_result sxpageadmin::admin_kill_picture( dditem& item )
{
	// fix! nur besitzer darf löschen
	const ddstring& id 		= get_cgi()["id"];
	const ddstring& name 	= get_cgi()["name"];	
	//??
	if( name.empty() || id.empty() )
		return rs_ok;
	ddstring uid;
	get_view().execute( "admin_get_uid", id ).read( uid );
	
	if( uid == get_user_id().get_id() || get_user_id().is_admin() )
		::unlink( name.c_str() );
	
	return create_redirect();

}


/**
	Die Hits-per-page Anzeige basteln.
*/

dd_result sxpageadmin::admin_hits( dditem& item )
{
	ddwebpagemap& pageletmap = get_site().get_pagelet_map();
	dditem& msgentry = get_body()["sn_subbody"]["sn_msgloop"];
  ddstring result;
	size_t sum=0;
  
	// inhalte basteln
	for( int i=0; i<pageletmap.size(); ++i )
  {
		 msgentry["sn_pagelet"].from_string( pageletmap[i]->get_name() );
	  // hack: don't count chat reqs
		//if( pageletmap[i]->get_name() != "snpagechat" )
			sum += pageletmap[i]->get_request_count();
		msgentry["sn_numreq"].from_size_t( pageletmap[i]->get_request_count() );
	  msgentry["sn_queue"].from_size_t( pageletmap[i]->get_queue_size() );
		msgentry["sn_max"].from_size_t( pageletmap[i]->get_queue_max_size() );
		msgentry["sn_timeout"].from_size_t( pageletmap[i]->get_max_timeout() );
		msgentry["sn_timeout_count"].from_size_t( pageletmap[i]->get_timeout_count() );
		result += msgentry.join();
  }
	msgentry.from_string( result );
	
	// connections
	dditem& msgsummary = get_body()["sn_subbody"];
	msgsummary["sn_sumreq"].from_size_t( sum );
	ddwebserver& parent = get_site().get_server();
	msgsummary["sn_sumcon"].from_size_t( parent.num_active_connections() );
	//msgsummary["sn_lokcon"].from_size_t( parent.num_locked_connections() );
	msgsummary["sn_maxcon"].from_size_t( parent.num_connections() );
	
	// mails
	msgsummary["sn_sumrep"].from_size_t( get_site().get_mail_manager().get_reply_count() );
	
  (void) item;
  return rs_ok;
  
}


/**
	Die aktuellen User-Sessions anzeigen.
*/

dd_result sxpageadmin::admin_sessions( dditem& item )
{	
	// get the map of currently present users
	dditem& msgentry = get_body()["sn_subbody"]["sn_msgloop"];
  	
	ddusersessionmanager& mgr = get_session_manager();	
	ddwebcgi& cgi = get_cgi();
	
	bool hideguests = !cgi["hideguests"].empty();
	const ddstring& sort = cgi["sort"];
	
	int keyindex = 0;
	if( !sort.empty())
	  keyindex = sort.as_int();

	// DAU-Sort:
	map<ddstring, dduserid*> tmpmap;		
	const ddmapindex& index = mgr.get_index();
	ddmapindex::const_iterator iter = index.begin();
	for( ; iter != index.end(); ++iter )
	{
		dduserid* userid = mgr[(*iter).second];
		if( hideguests && userid->is_guest() )
			continue;
	
		switch( keyindex )
		{
			case 1 :	
				tmpmap[userid->get_nick_name().as_lower()] = userid;
				break;
				
			case 2 :				
				tmpmap[userid->get_host_ip()] = userid;				
				break;
			
			default:
				tmpmap[(*iter).first] = userid;
			
		}
		
	}
	
	ddstring result;
	dditemlink link( "sn_subbody" );
	
	// dirty
	map<ddstring, dduserid*>::const_iterator pos = tmpmap.begin();
	for( ; pos != tmpmap.end(); ++pos )
	{
		dduserid& user = *((*pos).second);
		ddstring key = (*pos).first;
		msgentry["sn_key"].from_string( key );	
		link.set_link( user.get_nick_name(), "" );
		msgentry["sn_nickname"].from_string( "Nick:" + link.to_string() );
		msgentry["sn_ip1"].from_string( user.get_host_ip() );
		msgentry["sn_ip2"].from_string( user.get_host_ip() );		
		msgentry["sn_hits"].from_size_t( user.get_hits() );
		msgentry["sn_path1"].from_string( user.get_property( DDLASTPATH ) );
		msgentry["sn_path2"].from_string( user.get_property( DDLASTPATH ) );
		
		result += msgentry.join();
	}
	msgentry.from_string( result );

	return rs_ok;
	(void) item;
	
}


/**
	Neue Postings mit Body anzeigen, user version ohne autoreload.
*/

dd_result sxpageadmin::admin_postings_overview( dditem& item )
{	
	context.pagetype = "admin";
	ddwebview& table = get_view();
	
	// ...daten holen...	
	// and sn_datecreated > '{date} 00:00:00'
	context.numrows = table.fill( "on_postings_overview" );	
	
	// ...anzeigen...
	table.on_render( *this, get_body()["sn_subbody"], 0, context.numrows );	

	return rs_ok;
	(void) item;
}


/**
	Neue Votings mit Subject anzeigen.
*/

dd_result sxpageadmin::admin_votings_overview( dditem& item )
{	
	ddwebview& table = get_view();
	
	// ...daten holen...	
	context.numrows = table.fill( "on_votings_overview" );	
	
	// ...anzeigen...
	table.on_render( *this, get_body()["sn_subbody"], 0, context.numrows );	

	return rs_ok;

	(void) item;
}


/**
	Den Server anhalten. Es werden keine Requests mehr bearbeitet. Statt
	dessen wird eine Hinweiseseite angezeigt.
	@see ddwebserver.halt
*/

dd_result sxpageadmin::admin_halt( dditem& item )
{
	get_site().get_server().halt();
	return create_redirect( "/" );
	(void) item;
}


/**
	Die Alias-List bearbeiten.
*/

dd_result sxpageadmin::admin_aliases( dditem& item )
{

	ddwebaliasmap& list = get_site().get_alias_map();
	ddstring& alias = get_cgi()["sn_alias"];
	
	
	// erst die arbeit, dann das vergnügen:
	// liste berabeiten ...
	
	if( !alias.empty() )
	{
		if( get_split_path()[0] == "admin_aliases" )
			list.add_entry( alias, get_cgi()["sn_link"] );
		else
			list.drop_entry( alias );
			
		get_site().store_data_entry( DDKEYALIASESMAP, list.to_string() );
	}	
	
	// ..dann anzeigen
	dditem& block = get_body()["sn_subbody"]["sn_msgloop"];
	
	ddstringmap& aliases = list.get_aliases();
	if( !aliases.size() )
	{
		block.from_string( "(kein Eintrag)" ); 
		return rs_ok;
	}
	
	block.clear_value(); 
	ddstring result;
	ddstringmap::const_iterator pos = aliases.begin();
	int i=0;
	for( ; pos != aliases.end(); ++pos )
	{
		// FIX! multimap einbauen!
		block["sn_link1"].from_string( (*pos).second );
		block["sn_link2"].from_string( (*pos).second );
		block["sn_alias2"].from_string( (*pos).first );
		block["sn_alias1"].from_string( (*pos).first );
		result += block.to_string();
		++i;
	}
	block.from_string( result ); 

	return rs_ok;

	(void) item;

}


/**
	Die Redirect-List bearbeiten.
*/

dd_result sxpageadmin::admin_redirects( dditem& item )
{

	ddwebredirectmap& list = get_site().get_redirect_map();
	ddstring& alias = get_cgi()["sn_alias"];
	alias.replace_all( "&amp;", "&" );	
	
	// erst die arbeit, dann das vergnügen:
	// liste berabeiten ...
	
	if( !alias.empty() )
	{
		if( get_split_path()[0] == "admin_redirects" )
		{
			get_cgi()["sn_link"].replace_all( "&amp;", "&" );	
			list[ alias ] = get_cgi()["sn_link"];
		}
		else
		{
			list.erase( alias );
		}
			
		get_site().store_data_entry( DDKEYREDIRECTMAP, list.to_string() );
	}	
	
	// ..dann anzeigen
	dditem& block = get_body()["sn_subbody"]["sn_msgloop"];
	
	if( !list.size() )
	{
		block.from_string( "(kein Eintrag)" ); 
		return rs_ok;
	}
	
	block.clear_value(); 
	ddstring result;
	ddstringmap::const_iterator pos = list.begin();
	int i=0;
	for( ; pos != list.end(); ++pos )
	{
		// FIX! multimap einbauen!
		block["sn_link1"].from_string( (*pos).second );
		block["sn_link2"].from_string( (*pos).second );
		block["sn_alias1"].from_string( (*pos).first );
		block["sn_alias2"].from_string( (*pos).first );
		block["sn_alias3"].from_string( (*pos).first );
		
		result += block.to_string();
		++i;
	}
	block.from_string( result ); 

	return rs_ok;

	(void) item;

}


/**
	Eine mail-Adresse Blocken
*/


dd_result sxpageadmin::admin_block_mail( dditem& item )
{
	
	ddstringset& list = get_site().get_server().get_blocked_mails();
	ddstring& killmail = get_cgi()["sn_blockmail"].to_lower();
	//get_body()["sn_subbody"]["sn_x_word"].from_string( get_cgi()["sn_x_word"] );
	
	
	// erst die arbeit, dann das vergnügen:
	// liste berabeiten ...
	
	if( !killmail.empty() )
	{
		if( get_split_path()[0] == "admin_block_mail" )
			list.add_entry( killmail );
		else
			list.drop_entry( killmail );
			
		get_site().store_data_entry( DDKEYBLOCKEDMAILS, list.to_string() );
	}	
	
	// ..dann anzeigen
	dditem& block = get_body()["sn_subbody"]["sn_msgloop"];
	ddstringrow row;
	list.to_row( row );
	if( !row.size() )
	{
		block.from_string( "(kein Eintrag)" ); 
		return rs_ok;
	}
	block.clear_value(); 
	ddstring result;
	
	//for( size_t i=0; i<row.size(); ++i )
	for( size_t i = row.size(); i > 0; --i )
	{
		// FIX! multimap einbauen!
		block["sn_blockmail2"].from_string( row[i-1] );
		block["sn_blockmail1"].from_string( row[i-1].dup().escape() );
		result += block.to_string();
	}
	block.from_string( result ); 

	return rs_ok;

	(void) item;
}



/**
	Eine IP Blocken
*/

dd_result sxpageadmin::admin_block_ip( dditem& item )
{
	ddstringrowset& list = get_site().get_server().get_blocked_ips();
	ddstring& ip = get_cgi()["sn_ip"];
	get_body()["sn_subbody"]["sn_x_ip"].from_string( get_cgi()["sn_x_ip"] );
	
	// erst die arbeit, dann das vergnügen:
	// liste berabeiten ...
	
	if( !ip.empty() )
	{
		if( get_split_path()[0] == "admin_block_ip" )
			list.add_entry( ip, get_cgi()["sn_comment"] );
		else
			list.drop_entry( ip );
		get_site().store_data_entry( DDKEYBLOCKEDIPS, list.to_string() );
	}	
	
	// ..dann anzeigen
	dditem& block = get_body()["sn_subbody"]["sn_msgloop"];
	const ddstringrow& data = list.get_data();
	if( !data.size() )
	{
		block.from_string( "(kein Eintrag)" ); 
		return rs_ok;
	}
	block.clear_value(); 
	ddstring result;
	//for( size_t i=0; i<data.size(); ++i )
	for( size_t i = data.size(); i > 0; --i )
	{
		ddstringrow row( data[i-1], "|", 3 );	

		// FIX! multimap einbauen!
		block["sn_ip1"].from_string( row[0] );
		block["sn_ip2"].from_string( row[0] );
		block["sn_ip3"].from_string( row[0] );

		block["sn_date"].from_string( row[1] );	
		block["sn_comment"].from_string( row[2] );

		result += block.to_string();
	}
	block.from_string( result ); 
	
	return rs_ok;

	(void) item;
}


/**
	Funktion zur Verwaltung der "bösen Worte" (etwa spamdomains, die ins
	Gästebuch gepostet werden)
*/

dd_result sxpageadmin::admin_block_word( dditem& item )
{
	ddstringset& list = get_site().get_form_manager().get_blocked_words();
	ddstring& killword = get_cgi()["sn_blockword"];
	//get_body()["sn_subbody"]["sn_x_word"].from_string( get_cgi()["sn_x_word"] );
	
	
	// erst die arbeit, dann das vergnügen:
	// liste berabeiten ...
	
	if( !killword.empty() )
	{
		if( get_split_path()[0] == "admin_block_word" )
			list.add_entry( killword );
		else
			list.drop_entry( killword );
			
		get_site().store_data_entry( DDKEYBLOCKEDWORDS, list.to_string() );
	
	}	
	
	// ..dann anzeigen
	dditem& block = get_body()["sn_subbody"]["sn_msgloop"];
	ddstringrow row;
	list.to_row( row );
	if( !row.size() )
	{
		block.from_string( "(kein Eintrag)" ); 
		return rs_ok;
	}
	block.clear_value(); 
	ddstring result;
	//for( size_t i=0; i<row.size(); ++i )
	for( size_t i = row.size(); i > 0; --i )
	{
		// FIX! multimap einbauen!
		block["sn_blockword2"].from_string( row[i-1] );
		block["sn_blockword1"].from_string( row[i-1].dup().escape() );
		result += block.to_string();
	}
	block.from_string( result ); 
	
	return rs_ok;

}




/**
	Funktion zur Verwaltung der zensierten Worte (etwa spamdomains, die ins
	Gästebuch gepostet werden)
*/

dd_result sxpageadmin::admin_censor_word( dditem& item )
{
	ddstringset& list = get_site().get_form_manager().get_censored_words();
	ddstring& killword = get_cgi()["sn_blockword"].to_lower();
	//get_body()["sn_subbody"]["sn_x_word"].from_string( get_cgi()["sn_x_word"] );
	
	
	// erst die arbeit, dann das vergnügen:
	// liste berabeiten ...
	
	if( !killword.empty() )
	{
		if( get_split_path()[0] == "admin_censor_word" )
			list.add_entry( killword );
		else
			list.drop_entry( killword );
			
		get_site().store_data_entry( DDKEYBADWORDS, list.to_string() );
	}	
	
	// ..dann anzeigen
	dditem& block = get_body()["sn_subbody"]["sn_msgloop"];
	ddstringrow row;
	list.to_row( row );
	if( !row.size() )
	{
		block.from_string( "(kein Eintrag)" ); 
		return rs_ok;
	}
	block.clear_value(); 
	ddstring result;
	for( size_t i=0; i<row.size(); ++i )
	{
		// FIX! multimap einbauen!
		block["sn_blockword2"].from_string( row[i] );
		block["sn_blockword1"].from_string( row[i].dup().escape() );
		result += block.to_string();
	}
	block.from_string( result ); 
	
	return rs_ok;

	(void) item;
}


/**
	Verwaltet die overlay-links.
*/

dd_result sxpageadmin::admin_linkmap( dditem& item )
{
	
	ddweboverlaylinks& linkmap = get_site().get_overlay_links();				
	return admin_overlay( "admin_linkmap", DDKEYLINKSET, linkmap );
	
}


/**
	Verwaltet die overlay-images
*/

dd_result sxpageadmin::admin_imagemap( dditem& item )
{
	ddweboverlaylinks& linkmap = get_site().get_overlay_images();				
	return admin_overlay( "admin_imagemap", DDKEYIMAGESET, linkmap );
	(void) item;
	
}


/**
	Allgemeine Methode für die Overlay-Verwaltung.
*/

dd_result sxpageadmin::admin_overlay( const ddstring& baselink, const ddstring& databasekey, ddweboverlaylinks& target )
{
	dditem& subbody = get_body()["sn_subbody"];
	subbody.clear_children();
		
	const ddstring& request = get_split_path()[0];	
	ddwebcgi& cgi = get_cgi();
	
	// index fängt bei eins an um leeres index-feld (==0) zu filtern
	int index = cgi["sn_index"].as_int();
	int realindex = index;
	if( realindex )
		realindex--;
	
	
	// neu anlegen
	if( request == baselink + "_create" )
	{
		// ändern oder anlegen? Achtung! index wird 
		if( !index )
			target.add_entry( cgi["sn_key"], cgi["sn_link"], cgi["sn_comment"] );
		else
			target.update_entry( realindex, cgi["sn_key"], cgi["sn_link"], cgi["sn_comment"] );		
		
		// in die db schreiben
		get_site().store_data_entry( databasekey, target.to_string() );
		return create_redirect( "/" + baselink );
	}
	

	
	if( request == baselink + "_edit" )
	{
		
		if( realindex >= (int) target.size() )
			return create_error( "Ups! Index out of range!" );
		
		ddweboverlaylinkblock& entry = target[realindex];
		subbody["sn_key"].from_string( entry.keyblock );
		subbody["sn_link"].from_string( entry.link );
		subbody["sn_comment"].from_string( entry.comment );
		// den index speichern, fängt bei eins an um leeres index-feld (==0) zu filtern
		subbody["sn_index"].from_int( index );
	}
	else if( request == baselink + "_kill" && realindex )
	{
		
		// erst die arbeit, dann das vergnügen: liste berabeiten ...
		// Wenn CGI-Daten vorhanden sind, eintragen
		
		target.drop_entry( realindex );
		get_site().store_data_entry( databasekey, target.to_string() );
		return create_redirect( "/" + baselink );
						
	}	
	
	// ..dann anzeigen: über alle Einträge, über alle Sub-einträge
	dditem& block = subbody["sn_msgloop"];
	if( !target.size() )
		return create_hint_box( block, DDHINTNOTFOUND );
	
	block.clear_value(); 
	ddstring result;
	
	ddstring link = "http://" + get_connection().get_request().get_host_port();

	for( size_t i = 0; i < target.size(); ++i )
	{
		block["sn_key"].from_string( target[i].keyblock );	
		block["sn_link1"].from_string( link + target[i].link );	
		block["sn_link2"].from_string( target[i].link );	
		block["sn_comment"].from_string( target[i].comment );

		// index soll bei eins anfangen um leeres index-feld (==0) zu filtern
		block["sn_index1"].from_size_t( i+1 );	
		block["sn_index2"].from_size_t( i+1 );	
		
		result += block.to_string();
	}
	block.from_string( result ); 
	
	return rs_ok;

	
}


/**
	Ein zu beobachtendes Object (Threads etc) hinzufügen
	bzw. aus der Liste entfernen.
*/

dd_result sxpageadmin::admin_watch_change( dditem& item )
{
	// Jeder User darf nur einmal!
	if( get_user_id().is_guest() )
		return create_hint_box( get_body(), "<h3>Favoriten k&ouml;nnen nur von Membern gespeichert werden!</h3><br>" );
	
	get_body().clear_value();
	
	ddwebview& table = get_view();
	
	const ddstring& link = get_split_path()[0];
	ddstring& id = get_cgi()["id"];
	table.execute( link, get_user_id().get_id(), id );
		
	if( link == "admin_watch_update" )
		return create_redirect( "/threads/"+id );
	
	// create a redirect
  return create_redirect( "/threadwatch" );
  
	(void) item;
}



/**
	Alle neo-statischen en block erzeugen. Diese Funktion ist der Einstiegspunkt
	via webrequest 'create_master_index' und verzweigt auf die einzelnen Gererator-
	unterfunktionen. Schema: index erzeugen, dann endfiles erzeugen.
*/

dd_result sxpageadmin::create_master_index( dditem& item )
{
	
	dditem* child = lookup_item( "xx_archive_list" );
	
	
	// gruppen nach einträgen sortieren
	ddwebview& table = get_view();
	int numrows = table.fill( "on_count_faq_entries" );
	for( int i = 0; i < numrows; ++i )
	{
		// den gruppeneintrag per id finden
		for( int x = 0; x < _groupmap.size(); ++x )
		{	
			if( _groupmap[x] == table[i][0] )
			{
				const ddstring& grpname = _groupmap.key_of( x );
				_groupmapfaqs.add_by_key( grpname, _groupmap[x] );				
			}
		}

	}
	
	
	// die gruppen-indices erzeugen
	// einmal die faqs ...
	create_faq_group_index( *child );
	
	// gruppen nach einträgen sortieren
	numrows = table.fill( "on_count_thread_groups" );
	for( int i = 0; i < numrows; ++i )
	{
		// den gruppeneintrag per id finden
		for( int x = 0; x < _groupmap.size(); ++x )
		{	
			if( _groupmap[x] == table[i][0] )
			{
				const ddstring& grpname = _groupmap.key_of( x );
				_groupmapthreads.add_by_key( grpname, _groupmap[x] );				
			}
		}

	}
	
	// ... und die threads...
	create_thread_group_index( *child );
	
	// ... und jetzt die listen nach datum, erst die faqs...
	create_faq_list_index( *child );
	
	// ... und die threads...
	create_thread_list_index( *child );

	
	return rs_ok;
	
}

void sxpageadmin::create_faq_group_index( dditem& item )
{
	
	ddstring result;
		
	dditem& block = get_body()["sn_subbody"]["sn_msgentry"];
	block.clear_value();
	get_item().clear_value();
	get_item()["sn_title"].from_string( "Supportnet Tipp-Archiv" );
	
	for( int i =0 ; i < _groupmapfaqs.size(); ++i  )
	{
		const ddstring& grpname = _groupmapfaqs.key_of( i );
		// pfusch
		if( grpname == "admingruppe" || grpname == "news" || grpname == "evil" || grpname == "test" )
			continue;
			
		
		int allentries;
		get_view().execute( "on_count_faq_groups", _groupmapfaqs[i] ).read( allentries );
		int numblocks = 1 + allentries / DDITEMSPERARCHIVE;

		if( allentries )
		{
			create_faq_group_entry( item, grpname, numblocks, allentries );
			block["sn_link1"].from_string( "direkt/tippgruppen-" + grpname + "-" + ddstrutil::from_int( numblocks )+ ".html" ); 
			ddstring text = "Tipp-Index der Gruppe " + grpname;
			block["sn_link2"].from_string( text  );
			result += block.to_string();
		}		
		
	}
	block.from_string( result ); 
	get_item().to_string().to_file( "direkt/tippgruppen.html" );

}


int sxpageadmin::create_faq_group_entry( dditem& item, const ddstring& grpname, int numblocks, int allentries )
{
	
	ddstring grp = _groupmapfaqs[ grpname ];
	
	dditem& list = item["sn_body"]["sn_list"];
	
	// daten holen...
	ddwebview& table = get_view();
	
	int numrows;
	for( int blockno = 0; blockno < numblocks; ++blockno )
	{
		ddstring sfrom = ddstrutil::from_int( blockno * DDITEMSPERARCHIVE );
		numrows = table.fill( "on_list_faq_groups", grp, sfrom, ddstrutil::from_int( DDITEMSPERARCHIVE ) );
		// ...testen...
		if( numrows <= 0 )
			return 0;
		
		// ...alles fein...
		list.set_visible( true );
		// hints
		ddstring hint = "der Gruppe " + grpname + " (" + ddstrutil::from_int( allentries ) + " Eintr&auml;ge)";
		list["sn_subheader"]["sn_hint"].from_string( hint );
		
		// ...anzeigen...
		dditem& entry = list["sn_subbody"]["sn_msgentry"];
		table.on_render( *this, entry, 0, numrows );	
		
		// create navigator
		ddstring linkbase =  "direkt/tippgruppen-" + grpname+ "-";
		// navi hier immer anzeigen
		dditem& navi = list["sn_navigator"];	
		// links basteln: blocknum ist 0-basiert
		navi["sn_nxt"]["sn_lnk"].from_string( linkbase + ddstrutil::from_int( blockno + 2 ) + ".html" );
		navi["sn_lst"]["sn_lnk"].from_string( linkbase + ddstrutil::from_int( blockno ) + ".html" );
		// anzeigen?
		// 
		navi["sn_nxt"].set_visible( blockno+1 < numblocks );
		navi["sn_lst"].set_visible( blockno>0 );
	
		item["sn_title"].from_string( "Supportnet Tipp-Archiv" + hint );
	
		ddstring filename = linkbase + ddstrutil::from_int( blockno+1 ) + ".html";
		item.to_string().to_file( filename );
		
	}

	return numrows;
	
}


/**
	Das Indexfile 'threadgruppen.html' erzeugen. Die Unterseiten sind alle Threads einer Gruppe, diesmal
	müssen also noch Unterblöcke bzw. Unterfiles erzeugt werden. Es wird auf den höchsten (=neuesten)
	block verlinkt.
*/

void sxpageadmin::create_thread_group_index( dditem& item )
{
	
	ddstring result;
		
	dditem& block = get_body()["sn_subbody"]["sn_msgentry"];
	block.clear_value();
	get_item().clear_value();
	get_item()["sn_title"].from_string( "Supportnet Thread-Archiv" );
	
	for( int i =0 ; i < _groupmapthreads.size(); ++i  )
	{
		const ddstring& grpname = _groupmapthreads.key_of( i );
		// pfusch
		if( grpname == "admingruppe" || grpname == "news" || grpname == "evil" || grpname == "test" )
			continue;
			
		// Anzahl blöcke rausfinden
		int allentries;
		get_view().execute( "on_count_threads", _groupmapthreads[i] ).read( allentries );
		int numblocks = 1 + allentries / DDITEMSPERARCHIVE;
		// link soll auf den höchsten block zeigen		
		ddstring filebase = "direkt/threadgruppen-" + grpname + "-";
		block["sn_link1"].from_string( filebase + ddstrutil::from_int( numblocks ) + ".html" ); 
		ddstring text = "Thread-Index der Gruppe " + grpname; 
		block["sn_link2"].from_string( text  );
		result += block.to_string();
		
		// hier müssen _alle_ blöcke erzeugt werden		
		for( int i = 0; i < numblocks; ++i )
			create_thread_group_entry( item, grpname, i, allentries );		
		
	}
	
	block.from_string( result ); 
	get_item().to_string().to_file( "direkt/threadgruppen.html" );
	
}	


void sxpageadmin::create_thread_group_entry( dditem& item, const ddstring& grpname, int blocknum, int allentries )
{
	item.clear_value();
	
	ddstring grp = _groupmapthreads[ grpname ];
	ddstring sfrom = ddstrutil::from_size_t( DDITEMSPERARCHIVE * blocknum );

	dditem& list = item["sn_body"]["sn_list"];
	
	// daten holen...
	ddwebview& table = get_view();
	int numrows = table.fill( "on_list_thread_groups", grp, sfrom, ddstrutil::from_int( DDITEMSPERARCHIVE ) );
	// ...alles fein...
	list.set_visible( true );
	// hints
	ddstring hint = "der Gruppe " + grpname + " (" + ddstrutil::from_int( allentries ) + " Eintr&auml;ge)";
	list["sn_subheader"]["sn_hint"].from_string( hint );
	
	// ...anzeigen...
	dditem& entry = list["sn_subbody"]["sn_msgentry"];
	table.on_render( *this, entry, 0, numrows );	
	
	// create navigator
	// geht es weiter
	ddstring linkbase =  "direkt/threadgruppen-" + grpname + "-";
	// navi hier immer anzeigen
	dditem& navi = list["sn_navigator"];
	// links basteln: blocknum ist 0-basiert
	navi["sn_nxt"]["sn_lnk"].from_string( linkbase + ddstrutil::from_int( blocknum + 2 ) + ".html" );
	navi["sn_lst"]["sn_lnk"].from_string( linkbase + ddstrutil::from_int( blocknum ) + ".html" );
	// anzeigen?
	navi["sn_nxt"].set_visible( blocknum < allentries/DDITEMSPERARCHIVE );
	navi["sn_lst"].set_visible( blocknum>0 );
	
	item["sn_title"].from_string( "Supportnet Thread-Archiv" + hint );
	
	ddstring filename = linkbase + ddstrutil::from_int( blocknum+1 ) + ".html";
	item.to_string().to_file( filename );
	
}	


/**
	Für jedes Jahr wird eine Index-Datei, etwa 'tippliste-2000.html' erzeugt,
	die auf tipplisten nach dem dem schema 'tipps-jahr-monat-blockno.html' verlinkt.
	Es werden nur Monate angezeigt, die Tatsächlich Tipps enthalten.
*/

void sxpageadmin::create_faq_list_index( dditem& item )
{
	time_t now = ::time( 0 );
	struct tm tm_now;
	::localtime_r( &now, &tm_now );
	tm_now.tm_year += 1900;
	
	dditem& block = get_body()["sn_subbody"]["sn_msgentry"];
	
	// über alle jahre ab 2001
	for( int iyear = 2000; iyear <= tm_now.tm_year; ++iyear )
	{
		
		// hack: für 2001 gibbet nix
		if( iyear == 2001 )
			continue;
			
		ddstring syear = ddstrutil::from_int( iyear );
		block.clear_value();
		get_item().clear_value();
		get_item()["sn_title"].from_string( "Supportnet Tipp-Liste von " + syear );
	
		ddstring result;
	
		int count = 0;
		ddstring base = "direkt/tipps-" + syear + "-";
		for( int imonth = 0; imonth < 12; ++imonth )
		{
				// wir können nicht in die zukunft schauen
			if( iyear == tm_now.tm_year && imonth > tm_now.tm_mon  )
				break;
		
			ddstring smonth = ddstrutil::from_int( imonth + 1 );
			
			// Anzahl blöcke rausfinden
			int allentries;
			get_view().execute( "on_count_faqs", syear, smonth ).read( allentries );
			int numblocks = 1 + allentries / DDITEMSPERARCHIVE;
		
			ddstring linkstr = base + _monthnames[ imonth ] + "-";
		
			// hier müssen _alle_ blöcke erzeugt werden				
			// die Liste für diesen Monat erzeugen, aber nur, wenn es überhaupt faqs gibt
			int numentries = 0;
			for( int i = 0; i < numblocks; ++i )
				numentries += create_faq_list_entry( item, syear, smonth, linkstr, i, allentries );
			
			// nur verlinken, wenn überhaupt inhalte da sind
			if( !numentries )
				continue;
				
			// auf den _ersten_ block verlinken
			block["sn_link1"].from_string( linkstr + "1.html" ); 
			ddstring text = "Tipp-Index vom " + _monthnames[ imonth ] + " " + syear;
			block["sn_link2"].from_string( text  );
			result += block.to_string();
			++count;	
		
		}
	
		block.from_string( result ); 
		ddstring filename = "direkt/tippliste-" + syear + ".html";
		get_item().to_string().to_file( filename );
	
	}	

}


/**
 Eine Linkliste auf Faqs nach dem dem schema 'tipps-jahr-monat-blockno.html' erzeugen, es wird auf die Endfiles verlinkt.
*/

int sxpageadmin::create_faq_list_entry( dditem& item, const ddstring& year, const ddstring& monthno, const ddstring& linkbase, int blocknum, int allentries )
{
	// daten holen...
	item.clear_value();
	ddwebview& table = get_view();
	
	ddstring sfrom = ddstrutil::from_size_t( DDITEMSPERARCHIVE * blocknum );

	int numrows = table.fill( "on_list_faqs", year, monthno, sfrom, ddstrutil::from_int( DDITEMSPERARCHIVE ) );
	if( numrows <= 0)
		return 0;
	
	// ...testen...
	dditem& list = item["sn_body"]["sn_list"];
	
	// ...alles fein...
	list.set_visible( true );
	
	// ...anzeigen...
	dditem& entry = list["sn_subbody"]["sn_msgentry"];
	table.on_render( *this, entry, 0, numrows );	
	
	// navi hier immer anzeigen
	dditem& navi = list["sn_navigator"];
	// links basteln: blocknum ist 0-basiert
	navi["sn_nxt"]["sn_lnk"].from_string( linkbase + ddstrutil::from_int( blocknum + 2 ) + ".html" );
	navi["sn_lst"]["sn_lnk"].from_string( linkbase + ddstrutil::from_int( blocknum  ) + ".html" );
	// anzeigen?
	
	navi["sn_nxt"].set_visible( blocknum < allentries/DDITEMSPERARCHIVE );
	navi["sn_lst"].set_visible( blocknum > 0 );
	
	item["sn_title"].from_string( "Supportnet Tipp-Liste von " + monthno + "/" + year );
	
	ddstring filename = linkbase + ddstrutil::from_int( blocknum+1 ) + ".html";
	item.to_string().to_file( filename );
	
	return numrows;
	
}



void sxpageadmin::create_thread_list_index( dditem& item )
{
	time_t now = ::time( 0 );
	struct tm tm_now;
	::localtime_r( &now, &tm_now );
	tm_now.tm_year += 1900;
	
	dditem& block = get_body()["sn_subbody"]["sn_msgentry"];
	
	// über alle jahre ab 2009
	for( int iyear = 2009; iyear <= tm_now.tm_year; ++iyear )
	{

		block.clear_value();
		get_item().clear_value();
		ddstring result;
	
		int count = 0;
		ddstring year = ddstrutil::from_int( iyear );
		
		ddstring base = "direkt/threads-" + year + "-";
		for( int month = 0; month < 12; ++month )
		{
			int to = _monthlenghts[ month ];
			for( int day = 1; day <= to; ++day )
			{
				// wir können nicht in die zukunft schauen
				if( iyear == tm_now.tm_year && month == tm_now.tm_mon && day > tm_now.tm_mday )
					goto x;
					
				ddstring sday = ddstrutil::from_int( day );
				ddstring link = base + _monthnames[ month ] + "-" + sday + ".html";
				block["sn_link1"].from_string( link ); 
				ddstring text = "Thread-Index vom " + sday + "." + _monthnames[ month ] + " " + year;
				block["sn_link2"].from_string( text  );
				result += block.to_string();
				++count;
				
				// die Liste für diesen Monat erzeugen
				create_thread_list_entry( item, year, ddstrutil::from_int( month+1 ), sday, link );
	
			}
	
		}
		
x:	block.from_string( result ); 
		ddstring filename = "direkt/threadliste-" + year + ".html";
		get_item()["sn_title"].from_string( "Supportnet Thread-Liste von " + year );
	
		get_item().to_string().to_file( filename );

	}

}

void sxpageadmin::create_thread_list_entry( dditem& item, const ddstring& year, const ddstring& monthno, const ddstring& day, const ddstring& filename  )
{

	
	//ddstring sfrom = ddstrutil::from_size_t( 100 * get_split_path()[3].as_int() );
	
	// daten holen...
	ddwebview& table = get_view();
	int numrows = table.fill( "on_list_threads", year, monthno, day );
	
	// ...testen...
	dditem& list = item["sn_body"]["sn_list"];
	list["sn_navigator"]["sn_nxt"].set_visible( false );
	list["sn_navigator"]["sn_lst"].set_visible( false );
	// ...alles fein...
	list.set_visible( true );
	
	// ...anzeigen...
	dditem& entry = list["sn_subbody"]["sn_msgentry"];
	table.on_render( *this, entry, 0, numrows );	
	item["sn_title"].from_string( "Supportnet Thread-Liste vom " + day + "." + monthno + "." + year );
	
	item.to_string().to_file( filename );
	
}

	











