#ifndef IMSTATE_HH_
#define IMSTATE_HH_
#include <config.h>
#include <IMProtocolStruct.h>
#include "basictype.hh"
#include "IMHandler.hh"
#include "IMLog.hh"
#include "IIIMP_hotkey_profile.hh"

class IMAccept;
class IMProtocol;
class ICState;
class IIIMP_hotkey_profile;

class IMState
{
  public:
    typedef map<CARD16BIT, ICState*> ICStateMap;

  private:
    struct IMShared {
	CARD16BIT im_id;
	IMProtocol *pimp;
	IMHandler *pimh;
	ICStateMap icmap;
        IIIMP_hotkey_profile *hkp;
    };
    IMState *pbase_state;
    IMState *pproc_state;
    IMShared *pshared;
    int protocol_version;

  protected:
    void add_icstate(ICState *pics);
    void remove_icstate(ICState *pics);
    void reset_state()
    {
	IMState *p = pbase_state;
	if (p->pproc_state) delete p->pproc_state;
	p->pproc_state = NULL;
    }
    void change_state(IMState &newstate)
    { 
	IMState *p = pbase_state;
	if (p->pproc_state) delete p->pproc_state;
	p->pproc_state = &newstate;
    }

    IMProtocol* get_improtocol()
    { return pshared->pimp; }
    IMHandler* get_imhandler()
    { return pshared->pimh; }
    void set_imhandler(IMHandler *pimh)
    { pshared->pimh = pimh; }
    int get_current_protocol_version()
    {
	if (pproc_state)
	    return pproc_state->protocol_version;
	return protocol_version;
    }
    bool check_protocol_version(int version)
    { return (get_current_protocol_version() >= version); }

    IMAccept* get_imaccept();

    bool new_ic_id(CARD16BIT &newid) const;

    void cleanup_ic();

    virtual bool message_proc(
	void *message
    ) = 0;

    virtual ~IMState()
    {
	if (!substatep()) {
	    cleanup_ic();
	    delete pshared;
	    if (pproc_state) delete pproc_state;
	}
    }

  public:
    bool substatep()
    { return (pbase_state != this); }

    CARD16BIT get_im_id() const
    { return pshared->im_id; }

    IIIMP_hotkey_profile* get_hotkey_profile() const
    { return pshared->hkp; }

    ICState* get_icstate(CARD16BIT ic_id)
    {
	ICStateMap *pmap = &pshared->icmap;
	ICStateMap::iterator it;
	it = pmap->find(ic_id);
	if (it == pmap->end()) return NULL;
	return it->second;
    }

    enum CONTEXT_ID_SPECIAL {
	    INVALID_CONTEXT_ID = -1
    };
    bool dispatch(
	CARD16BIT im_id,
	CARD16BIT ic_id,
	void *message
    );
    bool deliver(
	void *message
    )
    {
	if (pproc_state)
	    return pproc_state->message_proc(message);
	return message_proc(message);
    }

    virtual void destroy();

    IMState(
	IMState &x,
	int x_protocol_version = -1
    )
    {
	pshared = x.pshared;
	pproc_state = NULL;
	pbase_state = &x;
	if ((x_protocol_version > 0)
	    && (x_protocol_version < x.protocol_version)) {
	    protocol_version = x_protocol_version;
	} else {
	    protocol_version = x.protocol_version;
	}
    }
    IMState(
	CARD16BIT x_im_id,
	IMProtocol *x_pimp,
	IMHandler *x_pimh,
	int x_protocol_version
    )
    {
	pshared = new IMShared();
	pshared->im_id = x_im_id;
	pshared->pimp = x_pimp;
	pshared->pimh = x_pimh;
        pshared->hkp = new IIIMP_hotkey_profile();
	protocol_version = x_protocol_version;
	pproc_state = NULL;
	pbase_state = this;
    }

  friend class ICState;
};

#endif /* not IMSTATE_HH_ */

/* Local Variables: */
/* c-file-style: "iiim-project" */
/* End: */
