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

    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 <ddwebcategory.h>

using namespace std;

/**
	Rekursiv den Pfad (betriebssysteme/linux/ubuntu) berechenen,
	Einstiegspunkt.
*/

const ddstring& ddwebcategory::create_path( ddwebcategorymap& tmptree )
{
	path = "/";
	//idpath = id + "-|";
	calculate_path( tmptree, path, idpath );
	return path;		
}


/**
	Rekursiv den Pfad (betriebssysteme/linux/ubuntu) berechenen,
	Rekursionsfunktion.
*/

void ddwebcategory::calculate_path( ddwebcategorymap& tmptree, ddstring& fullpath, ddstring& fullidpath )
{
		// bin ich root?
		if( parent.empty() || parent == "0" )
			return;
		// wenn nein, muss ich einen papa haben
		fullpath = "/" + key + fullpath;
		fullidpath =  id + "|" + fullidpath;
		// wenn nicht -> throw			
		if( !tmptree.contains_key( parent ) )
			throw runtime_error( "void calculate_path: Kategorien DB Fehlerhaft: Parent not found!" );
		tmptree.get_entry( parent ).calculate_path( tmptree, fullpath, fullidpath );	
}
	

/**
	Die Blatt-Kategorien einsammeln, z.B 'Betriebssysteme' -> 'win 98, win 95 ...'
	Das wird für die überischts-queries 'select * where catid in ( ... )' gebraucht 
*/

void ddwebcategory::collect_siblings( ddstring& result )
{
	// bin ich blatt? 
	if( children.empty() )
	{
		// erster eintrag ohne komma
		if( !result.empty() )
			result += ", ";
		result += id;
		return;
	}
	
	// ich bin kein blatt (==endknoten), also über alle kinder
	for( int x=0; x<children.size(); ++x )
		children[x]->collect_siblings( result );
		
}

	
/**
	Selbst rendern
*/

void ddwebcategory::render( dditem& item, ddstring& result, int indent, bool highlight ) const
{
	// 1. render myself
	item["sn_catcomment"].from_string( name );
	
	// optionale felder
	item.set_field_value( "sn_catpath", path );
	item.set_field_value( "sn_catid",  id );
	item.set_field_value( "sn_catname2", name );
	
	// ev. highlighten: ich bin gemeint
	item.set_field_value( "sn_highlight", highlight ? "style='color:#ff0000;font-weight:bold;'" : "" );
	
	item["sn_cattitle1"].from_string( title );
	item["sn_cattitle2"].from_string( title );	
	
	item["sn_catlevel"].from_int( indent );	
	item["sn_catname"].from_string( name );
	
	result += item.to_string();

}


/**
	Den Baum rekursiv rendern
*/

void ddwebcategory::render_tree( dditem& item, ddstring& result, int indent ) const
{
		
	// root: nur die kinder anzeigen
	if( path == "/" )
		return render_children( item, result, indent - 1 );
	
	// 1. render myself
	render( item, result, indent );
	// 2. render children
	for( int x=0; x<children.size(); ++x )
		children[x]->render_tree( item, result, indent+1 );
					
	// rekursiver abschluss
	result += "</li></ul><!-- Ende " + name + " -->\n\n";
}


/**
	Die Kindknoten rendern
*/

void ddwebcategory::render_children( dditem& item, ddstring& result, int indent ) const
{
	
	for( int x = 0; x < children.size(); ++x )
		children[ x ]->render_tree( item, result, indent + 1 );
		
}

/**
	Den Zusammengefalteten Baum anzeigen: Der Pfad /Betriebssysteme/Linux/Ubuntu soll folgendermassen
	gerendert werden:
	 
	für alle Pfadelemente
		Element highlighten
		Nachbarn rendern
			recurse
*/

void ddwebcategory::render_path( dditem& item, ddstring& result, size_t indent, const ddstringrow& splitpath  ) const
{

	indent++;
	
	if( indent >= splitpath.size() )
		return;
	
	const ddstring& pathpart = splitpath[ indent ];
		
	// render children
	for( int x=0; x<children.size(); ++x )
	{
		
		const ddwebcategory& child = children.get_entry( x );
		
		// kind malen
		bool highlight = pathpart == child.id;
		child.render( item, result, indent, highlight );					
		
		// wenn der nächste pfadanteil ein kind ist, auch rendern
		
		if( indent < splitpath.size()-1 && child.children.contains_key( splitpath[ indent+1 ]) )
		{
			child.render_path( item, result, indent, splitpath );
		}
		// unterkategorien des kindes auch anzeigen, so vorhanden und wenn das kind ausgewählt ist
		else if( highlight && !child.children.empty() )
		{
			const ddwebcategorymap& subcats = child.children;
			for( int y = 0; y < subcats.size(); ++y )
			{
				subcats[y]->render( item, result, indent + 1 );
				result += "</li></ul><!-- Ende sub -->\n\n";
			}
		}
		// rekursiver abschluss
		result += "</li></ul><!-- Ende " + name + " -->\n\n";
	
	}
	
	
}


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

    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.

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

/**
	Category-Tree aufbauen
*/

void ddwebcategorymap::init_data( const ddwebview& table )
{
	
	clear();
	
	// 1. Kompletten Kategorieabaum nach IDs zusammenbasteln
	for( int x=0; x<table.size(); ++x )
	{ 
		const dddatastaterow& row = table[x];		
		add_by_key( row[0], new ddwebcategory( row[0], row[1], row[2], row[3], row[4] ) );		
	}
	
	// 2. Für jede Kategorie den Pfad (Betriebssystem/Linux/Ubuntu) berechnen
	// und die Eltern-Kind Beziehung speichern
	for( int i=0; i<size(); ++i )
	{
		ddwebcategory& tmpcat = get_entry( i );
		// 1. für jeden knoten  den pfad rauskriegen	
		const ddstring& fullpath = tmpcat.create_path( *this );
		// 2. den full path als zusatzkey verwenden
		add_key( fullpath, i );
		// 2b. den key auch als zusatzkey verwenden
		add_key( tmpcat.key, i );
		// 3. Für Kategorie die Eltern-Kind Beziehung speichern	
		// bzw. den vätern die kinder zuschieben, so vorhanden
		if( tmpcat.parent != "0" )
			get_entry( tmpcat.parent ).children.add_by_key( tmpcat.id, (*this)[i] );
	
	}
	

}

void ddwebcategorymap::dump() const
{				
	for( int i=0; i<size(); ++i  )
		get_entry(i).dump();			
}


void ddwebcategorymap::render_path( dditem& item, ddstring& result, const ddstring& idpath )
{
	
	ddstringrow splitidpath( idpath, "|" );
	splitidpath.dump();
	get_entry( "/" ).render_path( item, result, -1, splitidpath );

}


/**
	Anhand eines Pfades wie etwa '700|710|' die category finden.
*/

const ddwebcategory& ddwebcategorymap::find_category_by_id_path( const ddstring& path ) const
{

	// die letze unterkategorie rausfinden
	size_t pos = path.rfind( '|', path.size() - 2 );
	if( pos == ddstring::npos )
		throw runtime_error( "ddwebcategorymap::find_category_by_id_path( const ddstring& path ): not found:" + path );
	
	return get_entry( path.substr( pos+1, 3 ) );
	
}

/**
	Anhand des keys wie etwa 'betriebssysteme' die category rausfinden.
*/

const ddwebcategory& ddwebcategorymap::find_category_by_key( const ddstring& catkey ) const
{

	for( int i=0; i<size(); ++i )
	{
		if( get_entry( i ).key == catkey )
			return get_entry( i );
	}
	// die letze unterkategorie rausfinden
	throw runtime_error( "ddwebcategorymap::find_category_by_key( const ddstring& path ): not found:" + catkey );
	
}
