#ifndef ICSTATE_HH_
#define ICSTATE_HH_
#include <config.h>
#include <IMProtocolStruct.h>
#include "basictype.hh"
#include "ICHandler.hh"
#include "IMState.hh"
#include "IMLog.hh"

class IMProtocol;
class IIIMP_hotkey_profile;
class ICState;
class IMLExec_ICState : public IMLExec
{
    // IMSyncObject so;
    ICState *pics;
    typedef list<iml_inst*> IMLInstList;
    IMLInstList pendinglist;
    void delete_inst(
	iml_inst *pinst
    );

    bool push_back(
	iml_inst *pinst
    );

    int execute_opcode(
	int opcode,
	iml_inst *rv
    );

    // IML instruction execution handlers.
    int imli_nop(
	iml_inst *rv
    );
    int imli_set_status(
	iml_inst *rv
    );
    int imli_reset(
	iml_inst *rv
    );
    int imli_keypress(
	iml_inst *rv
    );
    int imli_commit(
	iml_inst *rv
    );
    int imli_reset_return(
	iml_inst *rv
    );
    int imli_preedit_start(
	iml_inst *rv
    );
    int imli_preedit_draw(
	iml_inst *rv
    );
    int imli_preedit_done(
	iml_inst *rv
    );
    int imli_preedit_caret(
	iml_inst *rv
    );
    int imli_status_start(
	iml_inst *rv
    );
    int imli_status_draw(
	iml_inst *rv
    );
    int imli_status_done(
	iml_inst *rv
    );
    int imli_lookup_start(
	iml_inst *rv
    );
    int imli_lookup_draw(
	iml_inst *rv
    );
    int imli_lookup_process(
	iml_inst *rv
    );
    int imli_lookup_done(
	iml_inst *rv
    );
    int imli_aux_start(
	iml_inst *rv
    );
    int imli_aux_draw(
	iml_inst *rv
    );
    int imli_aux_done(
	iml_inst *rv
    );
    int imli_ns_listener(
	iml_inst *rv
    );
    int imli_key_info(
	iml_inst *rv
    );
    int imli_put_queue(
	iml_inst *rv
    );

  public:
    bool empty()
    { return pendinglist.empty(); }
    void set_icstate(
	ICState *x_pics
    )
    { pics = x_pics; }
    virtual iml_inst* push_insts(
	iml_inst **rrv
    );
    virtual bool execute();
    virtual ~IMLExec_ICState();
    IMLExec_ICState(ICState *x_pics = NULL)
    { pics = x_pics; }
};

class ICState
{
    struct ICShared {
	CARD16BIT ic_id;
	IMState *pims;
	ICHandler *pich;
	IMLExec_ICState *pimlex;
	bool terminating;
    };
    ICState *pproc_state;
    ICState *pbase_state;
    ICShared *pshared;

    bool terminatingp()
    { return pshared->terminating; }

  protected:
    IMLExec_ICState* get_imlexec()
    { return pshared->pimlex; }
    bool mark_terminal()
    { 
	pshared->terminating = true;
	return true;
    }
    virtual bool state_send_available_p() = 0;

    void reset_state()
    { 
	ICState *p = pbase_state;
	if (p->pproc_state) delete p->pproc_state;
	p->pproc_state = NULL;
	p->pshared->pimlex->set_icstate(p);
    }
    void change_state(
	ICState &newstate,
	bool destroyp = true
    )
    {
	ICState *p = pbase_state;
	if (destroyp && p->pproc_state) delete p->pproc_state;
	if (p == &newstate) {
	    p->pproc_state = NULL;
	} else {
	    p->pproc_state = &newstate;
	}
	p->pshared->pimlex->set_icstate(&newstate);
    }

    IMState* get_imstate()
    { return pshared->pims; }
    IMProtocol* get_improtocol()
    { return pshared->pims->get_improtocol(); }
    ICHandler* get_ichandler()
    { return pshared->pich; }
    void invalidate_ichandler()
    { pshared->pich = NULL; }
    bool check_protocol_version(int version)
    { return get_imstate()->check_protocol_version(version); }

    int invalid_operation(
	const char *opstr
    );

    virtual bool message_proc(
	void *message
    ) = 0;

    // base constructors.
    ICState(
	ICState &x
    )
    {
	pshared = x.pshared;
	pbase_state = x.pbase_state;
	pproc_state = NULL;
    }
    virtual ~ICState()
    {
	if (!substatep()) {
	    delete pshared;
	    if (pproc_state) delete pproc_state;
	}
    }

  public:
    bool send_avail_p()
    {
	if (pbase_state->pproc_state)
	    return pbase_state->pproc_state->state_send_available_p();
	else
	    return pbase_state->state_send_available_p();
    }

    CARD16BIT get_im_id()
    { return get_imstate()->get_im_id(); }
    IIIMP_hotkey_profile* get_hotkey_profile()
    { return get_imstate()->get_hotkey_profile(); }
    CARD16BIT get_ic_id() const
    { return pshared->ic_id; }
    bool substatep() const
    { return (pbase_state != this); }

    bool deliver(
	void *message
    );

    virtual void destroy()
    {
	if (!substatep()) {
	    pshared->pims->remove_icstate(this);
	}
	delete this;
    }

    ICState(
	CARD16BIT x_ic_id,
	IMState *x_pims,
	ICHandler *x_pich,
	IMLExec_ICState *x_pimlex
    )
    {
	pshared = new ICShared();
	pshared->ic_id = x_ic_id;
	pshared->pims = x_pims;
	pshared->pich = x_pich;
	pshared->pimlex = x_pimlex;
	pshared->terminating = false;
	x_pimlex->set_icstate(this);
	pproc_state = NULL;
	pbase_state = this;
    }

    // IC execution handlers.
    virtual int toggle_client_convmode(
	bool flag
    );
    virtual int forward_keyevent(
	IMKeyEventStruct *pkeyevent
    );
    virtual int commit_string(
	IMText *pimtext
    );
    virtual int preedit_start();
    virtual int draw_preedit(
	IMPreeditDrawCallbackStruct *pimpdraw
    );
    virtual int preedit_done();
    virtual int status_start();
    virtual int draw_status(
	IMStatusDrawCallbackStruct *pimsdraw
    );
    virtual int status_done();
    virtual int lookup_start(
	IMLookupStartCallbackStruct *pimls
    );
    virtual int draw_lookup(
	IMLookupDrawCallbackStruct *pimld
    );
    virtual int lookup_process(
	IMLookupProcessCallbackStruct *pimlp
    );
    virtual int lookup_done();
    virtual int aux_start(
	IMAuxStartCallbackStruct *pimauxstart
    );
    virtual int draw_aux(
	IMAuxDrawCallbackStruct *pimauxstart
    );
    virtual int aux_done(
	IMAuxDoneCallbackStruct *pimauxstart
    );
    virtual int ns_listener(
	IMNSListenerStruct *pons
    );
};

#endif /* not ICSTATE_HH_ */

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