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

    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.

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


#ifndef DDCONNECTION_H
#define DDCONNECTION_H


#include <ddwebrequest.h>
#include <ddwebbuffer.h>

using namespace std;

class ddwebserver;
class ddiourl;

/// ddwebiohandler: Enthält die Basisfunktionalitï¿½t für Netzwerk-IO.
/**
	Die Implemetierung befindet sich in den Unterklassen ddwebconnection (Verbindung zu Browser)
	und ddwebreader (Importieren von Blöcken über Http)
	
	@see ddwebconnection
	@see ddwebreader
*/

class ddwebiohandler : public ddbasestate
{

public:

  enum con_state
	{
		con_free         		= 0,
		con_locked	     		= 1, 
		con_reading      		= 2,
		con_reading_post 		= 4,
		con_writing					= 8,
	};
	
	ddwebiohandler()
	{
		set_state_flags( con_free );	
	}

	
	/**
		Destructor
	*/

	virtual ~ddwebiohandler()
	{

	}


	/**
  	true, wenn die Verbindung frei und wiederverwertbar ist.
  */

  inline bool is_free() const
  {
  	return ( _flags == ddwebiohandler::con_free );
  }

  
	/**
  	true, wenn die Verbindung gesperrt ist.
  	Das ist der Fall, wenn der Request bearbeitet und
  	die Response erzeugt wird.
  */
 
  inline bool is_locked() const
  {
  	return ( _flags == ddwebiohandler::con_locked );
  }
 
  
	/**
  	true, wenn die aktiv (lesend,schreibend) ist.
  */

  inline bool is_active() const
  {
		// active : waiting, reading, writing
		
		// waiting is active, da bei keep-alive == true
		// durchaus daten nachkommen können.
		// locked ist _nicht_ active, da sonst
		// der in bearbeitung befindliche request
		// überschrieben wird.
		
		return ( _flags >= ddwebiohandler::con_reading ); 
	} 
  
  /**
  	true, wenn die Verbindung im Schreibmodus ist.
  */

  inline bool is_writing() const
  {
  	return ( _flags >= ddwebiohandler::con_writing );
  }
  
  
  /**
  	Gibt den Filedeskriptor des Verbindungspartners zurück.
  */

	inline int get_fd()
  {
  	return _multibuffer.get_fd();
  }
	
	
	/**
  	Gibt den internen Ausgabepuffer zurück.
  */

  inline ddiobuffer& get_buffer()
  {
   	return _multibuffer.get_body_buffer();
  }


  /**
  	Gibt die IP-Adresse des Verbindungspartners zurück.
  */

	inline const ddstring& get_host_ip() const
	{
		return _multibuffer.get_host_ip();		
	}	
	
protected:

	int 					_contentlength;
	ddwebbuffer	 	_multibuffer;  

};


/// ddwebconnection: Behandelt die Verbindung zum Client-Browser.
/**
	Eine Webconnection enthält request und response und behandelt die Verbindung zum Client-Browser
	als eine Art state-machine. Je nach Status (warten, lesen, antwort erzeugen, schreiben) werden 
	verschiedene Handler-Funktionen aufgerufen.
	@see ddwebserver
	@see ddwebrequest
	@see ddwebresponse
*/

class ddwebconnection : public ddbaseobject, public ddwebiohandler
{

public:

	enum write_mode
	{
		write_wait = 0,
		write_header,
		write_buffer,
		write_sendfile,
		write_mmap_cache,
		write_not_modified
	};	
		
	ddwebconnection( ddwebserver* server, int connectionid );
	virtual ~ddwebconnection();
		

  /**
  	Gibt den Zeitpunkt der letzten Aktivität dieser Connection
  	zurück. Wird zum Time-Out handling benutzt.
  */

  inline time_t get_last_action()
  {
  	return _lastaction;
  }
  
  
  /**
  	Gibt den "request" zurück
  	@see ddwebrequest
  */

  inline ddwebrequest& get_request()
  {
  	return _request;
  }


  /**
  	Gibt die "response" zurück.
  	@see ddwebresponse
  */

  inline ddwebresponse& get_response()
  {
  	return _response;
  }
		
  
  /**
  	Gibt die IP-Adresse des Verbindungspartners zurück.
  */

	inline const ddstring& get_log_entry() const
	{
		return _logentry;		
	}
	
	
	/**
		Fehlermeldung und Fehlercode setzen
	*/
	
	inline int connection_create_error( const ddstring& error, int errorcode=ddwebresponse::ret_400_bad_request )
	{
		_errormessage = error;
		_errorcode    = errorcode;
		return -1;
	}
	
	int 					connection_handle_accept( int masterfd );
	
	int 					connection_handle_state();
	int 					connection_handle_read();
	int						connection_handle_test_buffer();
	int 					connection_handle_read_post();
	int 					connection_handle_test_post();
	int 					connection_handle_request();
	int  					connection_handle_static_response();
	int       		connection_handle_response( int retcode, const ddstring& type="text/html", bool writenow=true );
	int 					connection_handle_write();
	int 					connection_handle_error( const ddstring& error, int errorcode=ddwebresponse::ret_400_bad_request, bool writenow=true );
	int 					connection_handle_close();
	void					create_log_entry();
	
	ddstring 			to_string() const;
	
protected:

	ddwebserver* 	_server;
 	time_t				_lastaction;	
  ddwebresponse _response;      
  ddwebrequest 	_request;      
	ddstring			_logentry;
	ddstring		 	_errormessage;
	int					 	_errorcode;
	ddstringrow 	_errortemplate;
	
	// debug
	ddbasetime 		_timer;
	ddstring 			_firstpath;
	ddstring			_connectionid;
	
private:

	ddwebconnection( const ddwebconnection& src );
	ddwebconnection& operator=( const ddwebconnection& src );

};





#endif
