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

    supportware
    Copyright (C) 2001-2007 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 <ddweboverlay.h>
#include <unistd.h>


/**
	Constructor.
*/

ddweboverlaylinks::ddweboverlaylinks()
{
}


/**
	Destructor.	
*/

ddweboverlaylinks::~ddweboverlaylinks()
{
}


/**
	Einen String (für die DB) aus allen Einträgen zusammenbauen.
*/

ddstring ddweboverlaylinks::to_string()
{

	ddthreadautomutex tmp( _blockmutex );
	ddstring result;
	for( size_t i = 0; i<size(); ++i )
		result += (*this)[i].to_string();
	return result;	
	
}


/**
	Einträge aus einem String (aus der DB) erzeugen.
*/

void ddweboverlaylinks::from_string( const ddstring& src )
{
	// Quellstring in Zeilen zerlegen, die einzelnen Zeilen
	// enthalten die felder: key|link|comment

	ddthreadautomutex tmp( _blockmutex );
	ddstring source = src;	
	source.replace_all( "\r","" );
	ddstringrow row( source, "\n" );
	for( size_t i=0; i < row.size(); ++i )
	{
		ddstringrow entry( row[i], "|" );
		if( entry.size() != 3 )
			continue;
		add_entry( entry[0], entry[1], entry[2] );		
	}
	create_overlays();
}


/**
	Einen Eintrag erzeugen.
*/

void ddweboverlaylinks::add_entry( const ddstring& keyblock, const ddstring& link, const ddstring& comment )
{
	ddweboverlaylinkblock block( keyblock.as_lower(), link, comment );
	push_back( block );
	create_overlay_links( block );
}


/**
	Einen Eintrag updaten, ggf neu erzeugen
*/

void ddweboverlaylinks::update_entry( size_t index, const ddstring& keyblock, const ddstring& link, const ddstring& comment )
{
	if( index > size() )
		throw runtime_error( "ddweboverlaylinks::update_entry: index oput of range!" );
	(*this)[index] = ddweboverlaylinkblock( keyblock.as_lower(), link, comment );
	create_overlays();
}


/**
	Einen Eintrag löschen.
*/

void ddweboverlaylinks::drop_entry( size_t index )
{	
	ddthreadautomutex tmp( _blockmutex );
		if( index > size() )
		throw runtime_error( "ddweboverlaylinks::update_entry: index oput of range!" );
	erase( begin() + index );
	create_overlays();
}


/**
	Das workingset updaten.
*/

void ddweboverlaylinks::create_overlays()
{
	_workingset.clear();
	for( size_t i=0; i < size(); ++i )
		create_overlay_links( (*this)[i] );
	//_workingset.dump();
}


/**
	Einen workingset-eintrag schreiben.
*/

void ddweboverlaylinks::create_overlay_links( const ddweboverlaylinkblock& entry )
{
	// säubern
	ddstringrow rawlist( entry.keyblock, "," );
	// aus dem linkblock einzellinks machen
	for( size_t i=0; i < rawlist.size(); ++i )
	{
		rawlist[i].trim();
		if( !rawlist[i].empty() )
			//_workingset.add_by_key( rawlist[i], ddweboverlaylink( rawlist[i], entry.link, entry.comment ) );
			_workingset.add( ddweboverlaylink( rawlist[i], entry.link, entry.comment ) );
	}

}


/**
	Verwendetet Einträge werden nach hinten geschoben.
*/

void ddweboverlaylinks::rotate_entry( size_t index )
{
	// copy
	ddweboverlaylink tmp = _workingset[index];
	_workingset.kill_entry( index );
	_workingset.add_by_key( tmp.key, tmp );
}


/**
	Sucht einen Key und gibt ggf. den link und comment dafür zurück.
	
	FIX!
	klappt nicht, weil add statt add_by_key verwendet
	wird, um doppelte keys zu möglichen
	
*/


bool ddweboverlaylinks::find_link_tag( const ddstring& akey, ddweboverlaylink& entry )
{
	ddthreadautomutex tmp( _blockmutex );
	ddstring key = akey.as_lower();
	
	//_workingset.dump();
	
	// klappt nicht, weil add statt add_by_key verwendet
	// wird, um doppelte keys zu möglichen
	//int idx = _workingset.index_of( key );
	int idx = _workingset.find_link_tag( key );
	if( idx < 0 )
		return false;		
	entry = _workingset[idx];
	entry.key = akey;
	rotate_entry( idx );
	return true;
}


	
/**
	Sucht Keys in einem textblock (msgbody) und schreibt sie in eine Liste.
*/

bool ddweboverlaylinks::find_link_tags( const ddstring& ablock, ddweboverlaylinkmap& list )
{
	
	ddthreadautomutex tmp( _blockmutex );
	//list.clear();
	ddstring block = ablock.as_lower();
	
	for( int i = 0; i < _workingset.size(); ++i )
	{	
		const ddweboverlaylink& entry = _workingset[i];
		// key ist da ...
		ddstring key = entry.key.as_lower();
		size_t pos = block.find( key );
		if( pos != ddstring::npos )
		{
			// alt:
			// nur dranhängen wenn noch nicht vorhanden
			//if( list.index_of( entry.link ) < 0 )
			//  list.add_by_key( entry.link, entry );
			
			// neu: alle vorschläge speichern,
			// aber vorher prüfen, ob der key innherhalb
			// url- oder code-tags liegt.
			if( check_tag_position( block, pos ) )
				list.add( entry );
		}
	}
	
	
	return !list.empty();
	
}




void ddweboverlaylinks::replace_keys( ddstring& target )
{
	ddthreadautomutex tmp( _blockmutex );
	
	// den text in kleinbuchstaben speichern, für die suche
	_lowtext = target.as_lower();	
	
	// die linkratio ist 1 zu x (links zu worten)
	size_t maxlinks = _lowtext.count_words() / _linkratio;	
	
	// links zählen ...
	_numlinks = _lowtext.count_all( "[url" );
	// ... auch die overlay-links
	_numlinks += _lowtext.count_all( "[xurl" );		
	
	// linkspeicher löschen
	_linkset.clear();
	
	// gehe über alle keys, falls der key vorhanden ist,
	// jeden zweiten ersetzen, falls die link-ratio ok ist
	
	// über jeden key
	size_t i = 0, j = _workingset.size();
	for( ; i < j; ++i )
	{
			
		// linkdichte bzw. maximale ersetzungsanzahl 
		// erreicht?		
		if( _numlinks >= maxlinks || _numlinks >= _linkreplacements )
			break;	
		
		// neu: es werden nicht mehr einzelkeys sonder listen von gleichwertigen
		// schlüsseln verwendet: sosse, soße, soßen ...
		// also: über jeden teilschlüssel gehen
		
		// bei erfolg muss wird der ersetzte key
		// nach hinten geschoben
		
		if( replace_entry( _workingset[i], target ) )
		{
			
			rotate_entry( i );
			
			// i steht auf einem neuen key
			// der nunmehr letzte eintrag ist schon 
			// ersetzt:
			--i; 
			--j;
			
		}
	
	}
	

}


/**
	das müssen hier zehn worte sein mit mail und mp3 im text 
	drin. sind das schon zehn? jedes wort darf nur einmal und 
	erst beim zweiten mal ersetzt werden: mail-reader, 
	mp3-player und dann nimmer: mail-reader, mp3-player
*/

bool ddweboverlaylinks::replace_entry( const ddweboverlaylink& entry, ddstring& target )
{
	
	// schon mal behandelt?
	if( _linkset.count( entry.key ) > 0 )
		return false;

	ddstring key = " " + entry.key + " ";
	// nach dem ersten treffer suchen
	size_t keylen = key.size();
	
	size_t found = 0;
	size_t idx = 0;
	
	while( found != _linkoccurence )
	{	
		// n-tes vorkommen suchen
		idx = _lowtext.find( key, idx );
		// nicht gefunden? dann raus
		if( idx == ddstring::npos )
			return false;
		// doch gefunden?
		found++;
		idx += keylen;
	}

	idx -= keylen;
	
	// befinden wir uns innerhalb eines links ?
	if( !check_tag_position( _lowtext, idx) )
		return false;
	
	// gefunden? dann einmal ersetzen und zwar in beiden blocks, wg.
	// der längen
	
	// die blanks am key ausblenden
	idx++;
	keylen -= 2;
	
	ddstring origkey = target.substr( idx, keylen );
	//ddstring link = "[url=" + entry.link + DDLINKSEPARATOR + entry.comment + "]" + entry.key + "[/url]";
	ddstring link = "[xurl=" + entry.link + DDLINKSEPARATOR + entry.comment + "]" + origkey + "[/url]";
	_lowtext.replace( idx, keylen, link );
 	  target.replace( idx, keylen, link );
	
	// gesamtzahl der links erhöhen.
	_numlinks++;
	
	// key speichern
	_linkset.insert( key );
	
	return true;

	
}


/**
	Testet, ob das zu ersetzende keyword sich innerhalb eines [url]- oder 
	[code] tags befindet.
*/

bool ddweboverlaylinks::check_tag_position( const ddstring& src, size_t idx )
{
		
	// befinden wir uns innerhalb eines links ?
	// folgendes soll verhindert werden: [url] <neuer link> [/url], 
	// also: liegt ein tag-anfang hinter uns?
	size_t url1 = src.rfind( "[url", idx );
	// und xurl?
	if( url1 == ddstring::npos )
		url1 = src.rfind( "[xurl", idx );

	// anfang liegt hinter uns, jetzt muss das ende auch hinter uns liegen
	// sonst sind wir im link
	if( url1 != ddstring::npos )
	{
		// kein ende hinter uns: wir sind im link
		if( src.find( "[/url", url1+4 ) > idx )
			return false;
	
	}

	// dito: [code] <neuer link> [/code]
	url1 = src.rfind( "[code", idx );
	// anfang liegt hinter uns, jetzt muss das ende auch hinter uns liegen
	// sonst sind wir im link
	if( url1 != ddstring::npos )
	{
		// kein ende hinter uns: wir sind im link
		if( src.find( "[/code", url1+6 ) > idx )
			return false;
	
	}
	
	return true;

}

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

    supportware
    Copyright (C) 2001-2007 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.

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


/**
	Stopwords initialisieren.
*/

void ddweboverlayimages::init_stop_words( const ddstring& stopwords, const ddstring& domainname )
{
	_stopwords.from_string( stopwords );	
	_domainname = "sn_" + domainname;
}


/**
im prinzip wie overlays: ne neue liste: key, alt-tag,bildname

    * key im subject suchen
      beim 1.treffer bild vor den body schreiben, imgl-tag
      bildnamen ändert sich subject.gif , stopwortliste benutzen: drucker_spinnt.gif
      in die db schreiben.
*/


void ddweboverlayimages::replace_keys( ddstring& target, ddstring& subject )
{
	ddthreadautomutex tmp( _blockmutex );
	
	// den text in kleinbuchstaben speichern, für die suche
	_lowtext = subject.as_lower();	
		
	// linkspeicher löschen
	_linkset.clear();
	
	// gehe über alle keys, falls der key vorhanden ist,
	// jeden zweiten ersetzen, falls die link-ratio ok ist
		
	// über jeden key
	size_t i = 0, j = _workingset.size();
	for( ; i < j; ++i )
	{
		// neu: es werden nicht mehr einzelkeys sonder listen von gleichwertigen
		// schlüsseln verwendet: sosse, soße, soßen ...
		// also: über jeden teilschlüssel gehen
		
	
		// bei erfolg muss wird der ersetzte key
		// nach hinten geschoben
	
		if( replace_entry( _workingset[i], target ) )
		{
			rotate_entry( i );
			// i steht auf einem neuen key
			// der nunmehr letzte eintrag ist schon 
			// ersetzt:
			--i; 
			--j;
				
			// und aus der schleife raus
			break;
			
		}

	
	}

	
}

bool ddweboverlayimages::replace_entry( const ddweboverlaylink& entry, ddstring& target )
{
	
	// key im subject nicht gefunden? dann raus
	if( !_lowtext.contains( entry.key ) )
		return false;

	// ab hier: key ist im subject
	//ddstring link = "[imgl=" + entry.link + DDLINKSEPARATOR + entry.comment + "]" + entry.link + "[/imgl]";
	
	// subject in filenamen umbauen
	ddstring file, suffix, result, word;
	entry.link.split( ".", file, suffix );
					
	for( size_t i=0; i<_lowtext.size(); ++i )
	{
		char c = _lowtext[i];
		// im word
		if( isalpha( c ) && isascii( c ) )
		{
			word += c;
		}
		// wordende
		else
		{
			if( !word.empty() && !_stopwords.contains_key( word ) )
				result += word + "_";
			word = "";
		}

	}
	if( !word.empty() && !_stopwords.contains_key( word ) )
		result += word;
	result += "." + suffix;

	// solftlink basteln
	ddstring base = _domainname + "/html/overlayimage/";
	ddstring oldname = base + entry.link;
	ddstring newname = base + result;
	
	::symlink( entry.link.c_str(), newname.c_str() );
	
	//ddstring link = "[pic=" + entry.link  + "]" + entry.link + "[/pic]";
	ddstring link = "[pic=" + entry.comment  + "]" + result + "[/pic]";
	target = link + target;
	
	return true;
	

	
}

