/**
 * @file
 * $Id$
 * $Revision$
 * $Author$
 * $Date$
 *
 * This file is part of The iWear Framework.
 * In particular this file is part of the Framework Core Library
 *
 * The iWear Framework 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 as in version 2 of the License.

 * 
 * The iWear Framework is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * The iWear Framework; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef __IWEAR_SERVICE_H
#define __IWEAR_SERVICE_H

#ifndef __IWEAR_UID_H
#include <iwear/uid.h>
#endif

#include <iwear/iwear.h>
#include <string>
using std::string;

namespace iwear 
{

/**
 * @todo Think about additional service types
 */
enum service_type 
{
    service_generic, /** 
	      * This service is a generic base service and does not offer more
	      * than whats specified by the Service interface.
	      */
    service_ui_application,
    service_ui_daemon,
    service_system,  /**
	      * This is a system service that should normally not be displayed,
	      * and not be stoppped.
	      */
    service_agent,    /**
	      * This is an agent service and should be handled as an Agent 
	      */
    service_daemon,   /**
	       * This is a service representing a daemon (background
	       * app) Therefore the instance HAS to be of type Daemon
	       * because casts to this class must be possible.
	       * Both Applications and Daemons are managed by the 
	       * Application Service.
	       */
    service_application, /**
	       * This is a service representing an application (foreground
	       * app) Therefore the instance HAS to be of type Application
	       * because casts to this class must be possible. 
	       * Both Applications and Daemons are managed by the 
	       * Application Service.
	       */
    num_service_type	
};

enum service_state
{
    sstate_created,
    sstate_started,
    sstate_stopped,
    sstate_suspended,
    sstate_error,
    sstate_paused,
    num_service_state
};

inline const char* to_string( service_state ss )
{
    switch(ss)
    {
	case sstate_created:
	    return "service_state::sstate_created";
	case sstate_started:
	    return "service_state::sstate_started";
	case sstate_stopped:
	    return "service_state::sstate_stopped";
	case sstate_suspended:
	    return "service_state::sstate_suspended";
	case sstate_error:
	    return "service_state::sstate_error";
	case sstate_paused:
	    return "service_state::sstate_paused";
	default:
	    return "service_state::<invalid_value>";
    }
}

inline std::ostream& operator<<(std::ostream& o, service_state st)
{
    o << to_string(st);
    o << "(";
    o << static_cast<uint32_t>(st) << ")";
    return o;
}

class ServiceManager;

/**
 * This is the basic controlling interface for services. The states shall be
 * checked extensively. In case of errors, those functions throw exceptions
 * which explain the error. The state after this error may still be a usable so
 * it should always be checked before accidentaly resetting a well working
 * service.
 */
class IWAPIT Service
{
friend class ServiceManager;
private:
protected:
    uid ID;

    ServiceManager* SerMan;

    service_state actual_state;
public:
IWAPI const uid& get_uid( void ) const { return ID; } 
    
    Service( ServiceManager* ) IWAPI;

IWAPI virtual ~Service();
    /**
     * This will initialize the Service. State should go from sstate_created ->
     * sstate_stopped, otherwise it will throw an exception and stay in
     * sstate_created.
     *
     * Precondition State:
     * - sstate_created
     *
     * Postcondition State:
     * - sstate_stoppped
     *
     * Postcondition Error State:
     * - sstate_created
     */

IWAPI virtual void Init( void ) = 0;
    /**
     * This will start the Service. The service will then be running, and most
     * likely has created a new thread. It must be in sstate_stopped, either
     * because of a previously called Stop() or because it was just created and
     * just Init() was called. It shall then switch to sstate_started. If this
     * is not succesfull, it may throw an exception and internally switch to
     * sstate_error. A caller may then try to call Reset() to get the service
     * to the sstate_stopped again. 
     * Precondition State:
     * - sstate_stopped
     *   
     * Postcondition State:
     * - sstate_started
     * 
     * Postcondition Error State:
     * - sstate_error    
     */

IWAPI virtual void Start( void ) = 0;
    /**
     * This will stop the Service. It shall then report beeing in
     * sstate_stopped. Any extensive allocated resources shall be deallocated.
     * Any open filedescriptors shall be closed. Any started thread should be
     * destroyed. If any of the resource deallocation fails, the state shall be
     * sstate_error. It should then be possible to get the Service to the
     * sstate_stopped again calling Reset() without producing memory leaks,
     * file descriptor leaks or dead threads, deadlocks etc.
     * Precondition State:
     * - sstate_suspended
     * - sstate_paused
     * - sstate_started
     *   
     * Postcondition State:
     * - sstate_stopped
     * 
     * Postcondition Error State:
     * - sstate_error
     */

IWAPI virtual void Stop( void ) = 0;
    /**
     * This shall reset the Service.
     * It should try to deallocate any resources etc. and get the Service
     * running up again. A Start() must be called after a sucessfull call of
     * this function, to get the Service in sstate_started again. In case of an
     * error the error state will remain set.
     *
     * Precondition State:
     * - sstate_error
     *   
     * Postcondition State:
     * - sstate_stopped
     * 
     * Postcondition Error State:
     * - sstate_error
     */

IWAPI virtual void Reset( void ) = 0;
    /**
     * This shall suspend a Service. It shall deallocate as much resources as
     * possible, still guaranteeing a possible Resume(). This can mean it
     * should close unneeded fds, deallocate cache structures, switch off
     * exclusively needed hardware etc.  A running Thread shall be kept in a
     * low resource mode, like sleeping and just checking for flags. 
     * It shall then be in sstate_suspended, which can be left with a call to
     * Resume(). It can presume that it will be waked up after a longer time.
     * If a Service does not support resume state, it will throw an exception
     * but still stay in sstate_started.
     *
     * Precondition State:
     * - sstate_started
     * - sstate_paused  
     *   
     * Postcondition State:
     * - sstate_suspended
     * 
     * Postcondition Error State:
     * - sstate_error
     * - sstate_started
     */

IWAPI virtual void Suspend( void ) = 0;
    /**
     * This will pause a Service. Pausing is similar to suspending, just meant
     * for a shorter period of time. It does not need to deallocate internal
     * structures or close fds, although it is encouraged to do so if possible
     * (for resource saving), and not likely to be the cause of later errors.
     * The main purpose is to stop things like periodic updates of data,
     * polling, displaying cpu intensive data etc. It should reduce the CPU
     * load to a minimum.
     * If a Service does not support pausing, it may throw an exception, but
     * after that staying in sstate_started 
     * Precondition State:
     * - sstate_started
     *   
     * Postcondition State:
     * - sstate_paused
     * 
     * Postcondition Error State:
     * - sstate_error
     * - sstate_started
     */

IWAPI virtual void Pause( void ) = 0;
    /**
     * This will Resume a previously Paused or Suspended Service. It will
     * resume operations, and may allocate additional resources. It may fail,
     * in which either it indicates that the Service is no longer usable and is
     * in sstate_error or that for other reasons the Service is still usable
     * and can be Resumed with a later call again. Then it should stay in its
     * previous state.
     *
     * Precondition State:
     * - sstate_paused
     * - sstate_suspended
     *   
     * Postcondition State:
     * - sstate_started
     * 
     * Postcondition Error State:
     * - sstate_error
     * - sstate_paused
     * - sstate_suspended
     */
IWAPI virtual void Resume( void ) = 0;

    /**
     * @return the actual state
     */
IWAPI virtual service_state get_state( void ) { return actual_state; }

    /**
     * Short Name of the service.
     */
IWAPI virtual const string get_name( void ) = 0;

IWAPI virtual service_type get_type( void ) = 0;

    inline bool operator==( const Service& s ) { return ID == s.ID; }
    inline bool operator!=( const Service& s ) { return ID != s.ID; }
};

} // of namespace iwear

#endif
