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

    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 <ddwebfile.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <set>
#include <stdlib.h>
#include <ddwebpage.h>
#include <dduserid.h>
#include <ddwebsite.h>


/**
	Constructor.
*/

ddwebfile::ddwebfile()
: _initcalled( false ), _is_video_file( false ), _is_rescaled( false ),
	_stateflags( 64 ), _goodvotes( 0 ), _badvotes( 0 )
{

}


/**
	Constructor.
	@param name : der filename
*/

ddwebfile::ddwebfile( const ddstring& name )
: ddioinfo( name ), _initcalled( false ), _is_video_file( false ), _is_rescaled( false ),
	_stateflags( 64 ), _goodvotes( 0 ), _badvotes( 0 )
{
	init_media_data();
}
	

/**
	Construtor für Erzeugung aus der DB von FileManager aus.
*/
ddwebfile::ddwebfile( const ddstring& flags, const ddstring& name, const ddstring&  path, const ddstring& width, const ddstring& height )
: ddioinfo( name ) 
{
	_stateflags = flags.as_size_t();
	
	//_mediabase;
	//_mediasize;	
	//_mediatype;
	_currentpath 	= path;
	_mediawidth 	= width;
	_mediaheight	= height;
	
	// ??
	_initcalled = true;
}
	

bool ddwebfile::is_video_file()
{	
	if( !_initcalled )
		init_media_data();
	return _is_video_file;
}
	

bool ddwebfile::is_rescaled()
{	
	if( !_initcalled )
		init_media_data();
	return _is_rescaled;
}
	

/**
	'Size' ist eine etwas unglückliche Bezeichnung, denn
	der Wert bzieht sich auf die Breite _oder_ Höhe eines Bildes
	nach dem reskalieren.
*/

const ddstring& ddwebfile::get_media_size()
{
	if( !_initcalled )
		init_media_data();
	return _mediasize;
}


/**
	Gibt die 'Basis' des Dateinamens zurück, also
	ohne die Skalierungsendung: 'mookoo-20' wird 'mookoo'
*/

const ddstring& ddwebfile::get_media_base()
{
	if( !_initcalled )
		init_media_data();
	return _mediabase;
}

const ddstring& ddwebfile::get_media_type()
{
	if( !_initcalled )
		init_media_data();
	return _mediatype;
}


const ddstring& ddwebfile::get_media_width()
{
	if( !_initcalled )
		init_media_data();
	return _mediawidth;
}


const ddstring& ddwebfile::get_media_height()
{
	if( !_initcalled )
		init_media_data();
	return _mediaheight;
}


const ddstring& ddwebfile::get_media_path()
{
	return _currentpath;
}


/**
	Erzeugt eine Bilddatei aus dem upload-buffer: nach tmp sichern, namen säubern
*/

bool ddwebfile::create_media_file( const char* buffer, size_t size, ddstring& rawname )
{
	// windows pfad absäbeln
	rawname.replace_all( '\\', '/' );
	size_t pos = rawname.rfind( '/' );
	if( pos != ddstring::npos )
		rawname = rawname.substr( pos+1 );
	rawname = rawname.as_plain_ascii();
	ddstring fname = DDTMPPATH + rawname;
	
	int fd = ::open( fname.c_str(), O_WRONLY|O_CREAT, 00664 );
	if( fd > -1 )
	{
		if( !::write( fd, buffer, size ) > -1 )
			perror("create_media_file: write");
		::close( fd );
	}
	else
	{
		perror("create_media_file: open");
	}
	return true;
	
}


/**
	Ein Verzeichnis erzeugen
	@param path der Pfad
*/

ddstring ddwebfile::create_media_dir( const ddstring& targetpath, const ddstring& newfilename, ddwebcgi& cgi )
{
	
	init_media_data();
	
	_currentpath = targetpath;
	int err = ::mkdir( _currentpath.c_str(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP );	
	if( err<0 && errno != EEXIST )
		throw runtime_error( "ddwebfile::create_dir: " + _currentpath );
	
	// es sollen keine doppelten bilder erzeugt werden,
	// daher speichern wir die bildgrößen und schmeissen 
	// doppelte weg.
		
	// hack: videos nicht skalieren, das sollte allerdings anders implementiert sein	
	if( !is_video_file() )
	{
		set<size_t> imgsizes;	
		// die angeforderten auflösungen produzieren
		
		/*
			
			Alt: steuerung checkboxen
			
			<tr>
			<td colspan="2">
			<input type="checkbox" name="sn_format1" value="x40" checked>{#snstuff_dlg.img_imgsize_40height}
			&nbsp;<input type="checkbox" name="sn_format2" value="x80" checked>{#snstuff_dlg.img_imgsize_80height}
			&nbsp;<input type="checkbox" name="sn_format3" value="200" checked>{#snstuff_dlg.img_imgsize_200width}
			&nbsp;<input type="checkbox" name="sn_format4" value="470" checked>{#snstuff_dlg.img_imgsize_470width}
			</td>
		</tr>
			*/
			
		/*
		Also es gibt verschiedene Standardformate auf die man sich einfach einigen muss, da Digitalkameras alle 3:2 Fotografieren d.h. die längere Seite ist 1,5 mal so lang wie die kürzere sollten wir das auch nehmen. Beispiel: Bild 200 Pixel hoch dann muss es 300 Pixel breit sein.

			Daraus ergeben sich dann folgende neue Formate:
			
			40 Pixel hoch und 60 Pixel breit (den brauchen wir eigentlich nicht mehr)
			80 Pixel hoch und 120 Pixel breit
			
			200 Pixel breit und Höhe egal
			470 Pixel breit und Höhe egal
			
			600 Pixel breit und Höhe egal
			
			Für ein Icon brauchen wir dann in der Übersicht der Tipps Icons a:
			
			25 mal 25 Pixel für die Übersichten von Tipps
			
			75 x 56 Newsteaser Startseite
			Für die Newsübersicht brauchen wir noch ein Format. Kommt noch.
			[ anzeigen » ]
			Fabian Gränzer [27/Okt/10 12:48 PM] Also es gibt verschiedene Standardformate auf die man sich einfach einigen muss, da Digitalkameras alle 3:2 Fotografieren d.h. die längere Seite ist 1,5 mal so lang wie die kürzere sollten wir das auch nehmen. Beispiel: Bild 200 Pixel hoch dann muss es 300 Pixel breit sein. Daraus ergeben sich dann folgende neue Formate: 40 Pixel hoch und 60 Pixel breit (den brauchen wir eigentlich nicht mehr) 80 Pixel hoch und 120 Pixel breit 200 Pixel breit und Höhe egal 470 Pixel breit und Höhe egal 600 Pixel breit und Höhe egal Für ein Icon brauchen wir dann in der Übersicht der Tipps Icons a: 25 mal 25 Pixel für die Übersichten von Tipps 75 x 56 Newsteaser Startseite Für die Newsübersicht brauchen wir noch ein Format. Kommt noch.
			
			[ Permlink | Löschen | « verbergen ]
			Fabian Gränzer [27/Okt/10 01:26 PM]
			Das 470 ger Bild muss durch ein 442er im Forum ersetzt werden da 470 zu breit sind.

			
			
			Moin,
			Ich hab jetzt auch rausgefunden, wie man mit imagemagick bilder mit
			hintergrund skaliert.
			
			Das gillt dann ja für alle "FIX-Formate", oder?
			
			40 Pixel hoch und 60 Pixel breit (den brauchen wir eigentlich nicht mehr)
			80 Pixel hoch und 120 Pixel breit
			25 mal 25 Pixel für die Übersichten von Tipps
			-75 x 56 Newsteaser Startseite

		*/
		// neue version:
					
		//alt ddstringrow entries( "x40|x80|200|470", "|" );
		ddstringrow params( "-resize x80\\>|-resize 200\\>|-resize 442\\>|-thumbnail 75x56 -background white -gravity center -extent 75x56|-thumbnail 25x25 -background white -gravity center -extent 25x25|-thumbnail 80x120 -background white -gravity center -extent 80x120|-thumbnail 40x60 -background white -gravity center -extent 40x60", "|" );
		ddstringrow names( "80|200|442|75|25|120|40", "|" );
		
		for( size_t i=0; i < params.size(); ++i )
		{			
			
			
			// format erzeugen: Wenn sich nix geändert hat, also die Filegröße gleich geblieben ist,
			// wird das gerade erzeugt bild wieder gelöscht.
			
			ddstring filepath;		
			size_t imgsize = resize_image_file( params[i], names[i], newfilename, filepath );
			// gibbet schon?
			if( imgsizes.count( imgsize ) )
				::unlink( filepath.c_str() );
			else
				imgsizes.insert( imgsize );
		
		}	
	}
	
	// altes bild wegräumen
	ddstring newname = _currentpath + newfilename;
	::rename( get_full_path().c_str(), newname.c_str() );
	
	return _currentpath;
}


size_t ddwebfile::resize_image_file( const ddstring& format, const ddstring appendix, const ddstring& newname, ddstring& newpath  )
{	
	
	
	ddstring newfilename = newname.trim_pattern( "." );
	
	ddstring cmd = "convert " + format + " " + ddstring(DDTMPPATH) + get_full_name() + " ";
	newpath  = _currentpath + newfilename + "-" + appendix + "." + get_file_type();
	cmd += newpath;
	
	if( ::system( cmd.c_str() ) < 0 )
		throw runtime_error( "ddwebfile::resize: " + cmd );
	
	ddioinfo file( newpath );	
	return file.get_file_size();
	
}


void ddwebfile::init_media_data()
{
	//make_abs();
	
	_initcalled = true;
	
	char buf[1024];
	
	// defaultwert 
	_mediasize = "0";
	_mediabase = get_file_name();
	
	// Per 'file -i' den filetype als mime.type ermitteln.

	ddstring cmd = "/usr/bin/file -i " +  get_full_path();
	ddstring data;
	
	FILE* instream = ::popen( cmd.c_str(), "r" );
	if( !instream )
		goto error;
	
	::fgets( buf, 1023, instream );
	::fclose( instream );
	
	data = buf;
	
	if( data.rfind( "video" ) != ddstring::npos )
	{
		_mediatype = "video";
		_is_video_file = true;
		cmd = "/usr/bin/mediainfo \"--Inform=Video;%Width% %Height%\" ";		
	}
	else
	{
		_mediatype = "pic";		
		_is_video_file = false;
		_is_rescaled = false;
		cmd = "/usr/bin/identify -format \"%w %h\" ";
		
		// Versucht anhand des Dateinamens herauszufinden, ob das
		// Bild skaliert wurde.
		
		const ddstring& fname = get_file_name();
		size_t pos = fname.rfind( "-" );
		if( pos != ddstring::npos )
		{
			
			ddstring msize = fname.substr( pos+1 );
			
			// hack: das ist dazu, um beinamen wie 'screen_17.jpg' zu verhindern, 
			// das size: 17 übertragen wird, also nur erlaubte Formate zulassen
			
			if( msize == "40" || msize == "80" 
	 			|| msize == "200" || msize == "470" )
	 		{
	 			_mediabase = fname.substr( 0, pos );
				_mediasize = msize;
				_is_rescaled = true;
			}
			
			
		}
	
			
	}
	
	cmd += get_full_path();

	instream = ::popen( cmd.c_str(), "r" );
	if( !instream )
		goto error;
	
	::fgets( buf, 1023, instream );
	::fclose( instream );

	data = buf;
	data.trim();
	
	data.split( " ", _mediawidth, _mediaheight );
	
	return;

error:
	
	::perror( "mediainfo: ");  	

}


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

    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.

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


/**
	Mit Hilfe der Konfigurationsdatei die Userdatenbank laden.
*/

void ddwebfilemanager::init_data( ddconfig& config )
{
	// setup filemanager
  int idx = config.index_of( "webfilemanager" );
  if( idx<0 ) 
		throw runtime_error( "webfilemanager config missing!" );
	
	_mytable.init_queries( config[idx], config["main"]["connectstring"] );
	// PFUSCH, wir nehmen doch die user db
	//_mytable.init_queries( config[idx], "users;localhost;dope;moomoo" );
	
	if( _mytable.fill() <= 0 )
		//throw runtime_error( "webfilemanager fill failed!" );
	return;
	
	// neu: selbst ist der zonc:
	for( int i=0; i<_mytable.size(); ++i )
	{
		const dddatastaterow& row = _mytable[ i ];		
		// ddwebfile( const ddstring& flags, const ddstring& name, const ddstring&  path, const ddstring& width, const ddstring& height );
		ddwebfile* newfile = new ddwebfile( row["id_state"], row["sn_imgname"], row["sn_imgpath"], row["sn_imgwidth"], row["sn_imgheight"] );
		add_by_key( row["sn_imgname"], newfile );		

	}
	
	// weg mit dem mist
	_mytable.clear();
	
}



/**
	Category-Tree aufbauen
*/



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


/**
	Ein Bildverzeichnis für einen User erstellen. Das Format: memberimage/19748/lenka-470.jpg
*/

void ddwebfilemanager::create_user_files( ddwebpage& pagelet, ddwebcgi& cgi )
{
	const ddstring& id = pagelet.context.id;
	ddstring targetpath = ddstring(DDUSERPICPATH) + id  + "/";		
	create_files( pagelet,targetpath, id, "/member/" + id, cgi, DDUSERPICPREFIX );
}



/**
	Ein Bildverzeichnis für neue Postings erstellen. Das Format: articleimage/sn_computer/19748/lenka-470.jpg
*/

void ddwebfilemanager::create_image_files( ddwebpage& pagelet, ddwebcgi& cgi, const ddstring& newid )
{
	ddstring targetpath = ddstring(DDPICPATH) + "sn_" + pagelet.get_site().get_name() + "/" + newid+ "/";	
	create_files( pagelet,targetpath, newid, "/t/" + newid, cgi );
}


/**
	Interner Einsprung, um jetzt tatsächlich das Verzeichnis für user- und article-files anzulegen.
*/

void ddwebfilemanager::create_files( ddwebpage& pagelet, const ddstring& targetpath, const ddstring& id, const ddstring& threadpath, ddwebcgi& cgi, const ddstring& prefix )
{ 
	
	
	// 1. Schritt: Verzeichnis anlegen und 
	// Bild analysieren
	
	// cgi["sn_filename"] ist der reale filename: lenka.jpg, bei bildern von membern
	// muss noch 'memimg-' davor gehängt werden
	ddwebfile file( DDTMPPATH + cgi["sn_filename"] );
	file.create_media_dir( targetpath, prefix + cgi["sn_filename"], cgi );
	
	// 2. Schritt: Die Bilddaten speichern
	//insert into tr_image( id_parent, id_state, id_user, sn_imgname, sn_imgpath, sn_imgwidth, sn_imgheight,
	//	sn_datecreated, sn_senderip ) values( '{id_parent}', 2, '{id_user}', '{sn_imgname}', '{sn_imgpath}', '{sn_imgwidth}', '{sn_imgheight}',
	//	now(), '{sn_senderip}' )";
	
	
	cgi[ "id_parent" ] 		= id; 
	cgi[ "id_user" ] 			= pagelet.get_user_id().get_id();
	cgi[ "sn_nickname" ]	= pagelet.get_user_id().get_nick_name();
	//cgi[ "sn_threadpath" ]= pagelet.get_full_path();
	cgi["sn_filename"]		= prefix + cgi["sn_filename"];
	cgi[ "sn_threadpath" ]= threadpath;
	cgi[ "sn_imgpath" ]		= file.get_media_path();
	cgi[ "sn_imgwidth" ] 	= file.get_media_width();
	cgi[ "sn_imgheight" ]	= file.get_media_height();
	cgi[ "sn_senderip" ]	= pagelet.get_connection().get_host_ip();
	cgi.dump();
		
	_mytable.execute( cgi );
	
			// webfilemanager setup
	init_data( pagelet.get_site().get_config() );
	
}





