
/*
  Meanwhile - Unofficial Lotus Sametime Community Client Library
  Copyright (C) 2004  Christopher (siege) O'Brien
  
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.
  
  This library 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
  Library General Public License for more details.
  
  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#ifndef _MW_SERVICE_H
#define _MW_SERVICE_H


#include "mw_common.h"


/* place-holders */
struct mwChannel;
struct mwService;
struct mwSession;
struct mwMsgChannelCreate;
struct mwMsgChannelAccept;
struct mwMsgChannelDestroy;


/** State-tracking for a service */
enum mwServiceState {
  mwServiceState_STOPPED,   /**< the service is not active */
  mwServiceState_STOPPING,  /**< the service is shutting down */
  mwServiceState_STARTED,   /**< the service is active */
  mwServiceState_STARTING,  /**< the service is starting up */
  mwServiceState_ERROR,     /**< error in service, shutting down */
  mwServiceState_UNKNOWN,   /**< error determining state */
};


/** Casts a concrete service (such as mwServiceAware) into a mwService */
#define MW_SERVICE(srv) ((struct mwService *) srv)


#define MW_SERVICE_IS_STATE(srvc, state) \
  (mwService_getState(MW_SERVICE(srvc)) == (state))

#define MW_SERVICE_IS_STOPPED(srvc)  \
  MW_SERVICE_IS_STATE(srvc, mwServiceState_STOPPED)

#define MW_SERVICE_IS_STOPPING(srvc) \
  MW_SERVICE_IS_STATE(srvc, mwServiceState_STOPPING)

#define MW_SERVICE_IS_STARTED(srvc)  \
  MW_SERVICE_IS_STATE(srvc, mwServiceState_STARTED)

#define MW_SERVICE_IS_STARTING(srvc) \
  MW_SERVICE_IS_STATE(srvc, mwServiceState_STARTING)


/** If a service is STARTING or STARTED, it's considered LIVE */
#define MW_SERVICE_IS_LIVE(srvc) \
  (MW_SERVICE_IS_STARTING(srvc) || MW_SERVICE_IS_STARTED(srvc))

/** If a service is STOPPING or STOPPED, it's considered DEAD */
#define MW_SERVICE_IS_DEAD(srvc) \
  (MW_SERVICE_IS_STOPPING(srvc) || MW_SERVICE_IS_STOPPED(srvc))


typedef void (*mwService_funcStart)(struct mwService *service);

typedef void (*mwService_funcStop)(struct mwService *service);

typedef void (*mwService_funcClear)(struct mwService *service);

typedef const char *(*mwService_funcGetName)(struct mwService *service);

typedef const char *(*mwService_funcGetDesc)(struct mwService *service);

/** @todo remove msg and replace with appropriate additional parameters */
typedef void (*mwService_funcRecvCreate)
     (struct mwService *service,
      struct mwChannel *channel,
      struct mwMsgChannelCreate *msg);

/** @todo remove msg and replace with appropriate additional parameters */
typedef void (*mwService_funcRecvAccept)
     (struct mwService *service,
      struct mwChannel *channel,
      struct mwMsgChannelAccept *msg);

/** @todo remove msg and replace with appropriate additional parameters */
typedef void (*mwService_funcRecvDestroy)
     (struct mwService *service,
      struct mwChannel *channel,
      struct mwMsgChannelDestroy *msg);

typedef void (*mwService_funcRecv)
     (struct mwService *service,
      struct mwChannel *channel,
      guint16 msg_type,
      struct mwOpaque *data);


/** A service is the recipient of sendOnCnl messages sent over
    channels marked with the corresponding service id. Services
    provide functionality such as IM relaying, Awareness tracking and
    notification, and Conference handling.  It is a service's
    responsibility to accept or destroy channels, and to process data
    sent over those channels */
struct mwService {

  /** the unique identifier by which this service is registered. The
      type value also relates to those channels which will be directed
      to this service */
  guint32 type;

  /** the state of this service. Determines whether or not the session
      should call the start function upon receipt of a service
      available message. Should not be set or checked by hand.

      @relates mwService_getState */
  enum mwServiceState state;

  /** session this service is attached to.
      @relates mwService_getSession */
  struct mwSession *session;

  /** @return string short name of the service
      @relates mwService_getName */
  mwService_funcGetName get_name;

  /** @return string short description of the service
      @relates mwService_getDesc */
  mwService_funcGetDesc get_desc;

  /** The service's channel create handler. Called when the session
      receives a channel create message with a service matching this
      service's type.

      @relates mwService_recvCreate */
  mwService_funcRecvCreate recv_create;

  /** The service's channel accept handler. Called when the session
      receives a channel accept message for a channel with a service
      matching this service's type.

      @relates mwService_recvAccept */
  mwService_funcRecvAccept recv_accept;

  /** The service's channel destroy handler. Called when the session
      receives a channel destroy message for a channel with a service
      matching this service's type.

      @relates mwService_recvDestroy */
  mwService_funcRecvDestroy recv_destroy;

  /** The service's input handler. Called when the session receives
      data on a channel belonging to this service

      @relates mwService_recv */
  mwService_funcRecv recv;

  /** The service's start handler. Called upon the receipt of a
      service available message.

      @relates mwService_start */
  mwService_funcStart start;

  /** The service's stop handler. Called when the session is shutting
      down, or when the service is free'd.

      @relates mwService_stop */
  mwService_funcStop stop;
  
  /** The service's cleanup handler. Service implementations should
      presume that mwService::stop will be called first. The clear
      handler is not for shutting down channels or generating
      non-cleanup side-effects, it is only for handling tear-down of
      the service, and will only be called once for any instance.

      @relates mwService_free */
  mwService_funcClear clear;

  /** Optional client data, not for use by service implementations

      @relates mwService_getClientData
      @relates mwService_setClientData */
  gpointer client_data;

  /** Optional client data cleanup function. Called with client_data
      from mwService_free

      @relates mwService_getClientData
      @relates mwService_setClientData */
  GDestroyNotify client_cleanup;
};


/** @name Service Extension API

    These functions are for use by service implementations */
/*@{*/


/** Prepares a newly allocated service for use.
    
    Intended for use by service implementations, rather than by code
    utilizing a service.
    
    The service state will be initialized to STOPPED.
    
    @param service       the service to initialize
    @param session       the service's owning session
    @param service_type  the service ID number */
void mwService_init(struct mwService *service,
		    struct mwSession *session,
		    guint32 service_type);


/** Indicate that a service is started. To be used by service
    implementations when the service is fully started. */
void mwService_started(struct mwService *service);


/** Indicate that a service is stopped. To be used by service
    implementations when the service is fully stopped. */
void mwService_stopped(struct mwService *service);


/*@}*/


/** @name General Services API

    These functions provide unified access to the general functions of
    a client service, with some simple sanity-checking. */
/*@{*/


/** Triggers the recv_create handler on the service.

    @param service  the service to handle the message
    @param channel  the channel being created
    @param msg      the channel create message */
void mwService_recvCreate(struct mwService *service,
			  struct mwChannel *channel,
			  struct mwMsgChannelCreate *msg);


/** Triggers the recv_accept handler on the service.

    @param service  the service to handle the message
    @param channel  the channel being accepted
    @param msg      the channel accept message */
void mwService_recvAccept(struct mwService *service,
			  struct mwChannel *channel,
			  struct mwMsgChannelAccept *msg);


/** Triggers the recv_destroy handler on the service.

    @param service  the service to handle the message
    @param channel  the channel being destroyed
    @param msg      the channel destroy message */
void mwService_recvDestroy(struct mwService *service,
			   struct mwChannel *channel,
			   struct mwMsgChannelDestroy *msg);


/** Triggers the input handler on the service

    @param service   the service to receive the input
    @param channel   the channel the input was received from
    @param msg_type  the service-dependant message type
    @param data      the message data */
void mwService_recv(struct mwService *service,
		    struct mwChannel *channel,
		    guint16 msg_type,
		    struct mwOpaque *data);


/** @return the appropriate type id for the service */
guint32 mwService_getType(struct mwService *);


/** @return string short name of the service */
const char *mwService_getName(struct mwService *);


/** @return string short description of the service */
const char *mwService_getDesc(struct mwService *);


/** @return the service's session */
struct mwSession *mwService_getSession(struct mwService *service);


/** @returns the service's state
    @relates MW_SERVICE_IS_STARTING
    @relates MW_SERVICE_IS_STARTED
    @relates MW_SERVICE_IS_STOPPING
    @relates MW_SERVICE_IS_STOPPED
    @relates MW_SERVICE_IS_LIVE
    @relates MW_SERVICE_IS_DEAD
*/
enum mwServiceState mwService_getState(struct mwService *service);


/** Triggers the start handler for the service. Normally called from
    the session upon receipt of a service available message. Service
    implementations should use this handler to open any necessary
    channels, etc. Checks that the service is STOPPED, or returns.
    
    @param service The service to start
*/
void mwService_start(struct mwService *service);


/** Triggers the stop handler for the service. Normally called from
    the session before closing down the connection. Checks that the
    service is STARTED or STARTING, or returns

    @param service The service to stop
*/
void mwService_stop(struct mwService *service);


/** Frees memory used by a service. Will trigger the stop handler if
    the service is STARTED or STARTING. Triggers clear handler to allow
    cleanup.

    @param service The service to clear and free
*/
void mwService_free(struct mwService *service);


/** Associates client data with service. If there is existing data, it
    will not have its cleanup function called. Client data is not for
    use by service implementations. Rather, it is for use by client
    code which may later make use of those service implementations. */
void mwService_setClientData(struct mwService *service,
			     gpointer data, GDestroyNotify cleanup);


/** Reference associated client data */
gpointer mwService_getClientData(struct mwService *service);


/** Removes client data from service. If there is a cleanup function,
    it will be called. */
void mwService_removeClientData(struct mwService *service);


/*@}*/


#endif

