#include <config.h>
#include <stdio.h>
#include "ICState.hh"
#include "IMLog.hh"

bool
ICState::deliver(
    void *message
)
{
    ICState *p;
    bool result = true;

    if (pproc_state) p = pproc_state;
    else p = this;

    if (!p->message_proc(message)) return false;

    if (send_avail_p() && get_imlexec()) {
	result = get_imlexec()->execute();
    }

    if (terminatingp()) {
	LOG_DEBUG("Try to terminate IC(%d).", get_ic_id());
	if (pproc_state) {
	    LOG_DEBUG("Right now, the current state in IC(%d) may be "
		      "waiting for client responce.",
		      get_ic_id());
	} else if (!(get_imlexec()->empty())){
	    LOG_DEBUG("Pending IML instruction(s) still remain in IC(%d), "
		      "wait for the next chance.",
		      get_ic_id());
	} else {
	    int id = get_ic_id();
	    destroy();
	    LOG_DEBUG("Successfully IC(%d) is terminated.", id);
	}
    }

    return result;
}

int
ICState::invalid_operation(
    const char *opstr
)
{
    LOG_ERROR("Current IC state cannot deal with %s.", opstr);
    abort();
    return 0;
}

int
ICState::toggle_client_convmode(
    bool flag
)
{
    return invalid_operation("toggle_client_convmode");
}

int
ICState::forward_keyevent(
    IMKeyEventStruct *pkeyevent
)
{
    return invalid_operation("forward_keyevent");
}

int
ICState::commit_string(
    IMText *pimtext
)
{
    return invalid_operation("commit_string");
}

int
ICState::preedit_start()
{
    return invalid_operation("preedit_start");
}

int
ICState::draw_preedit(
    IMPreeditDrawCallbackStruct *pimpdraw
)
{
    return invalid_operation("draw_preedit");
}

int
ICState::preedit_done()
{
    return invalid_operation("preedit_done");
}

int
ICState::status_start()
{
    return invalid_operation("status_start");
}

int
ICState::draw_status(
    IMStatusDrawCallbackStruct *pimsdraw
)
{
    return invalid_operation("draw_status");
}

int
ICState::status_done()
{
    return invalid_operation("status_done");
}

int
ICState::lookup_start(
    IMLookupStartCallbackStruct *pimls
)
{
    return invalid_operation("lookup_start");
}

int
ICState::draw_lookup(
    IMLookupDrawCallbackStruct *pimld
)
{
    return invalid_operation("draw_lookup");
}

int
ICState::lookup_process(
    IMLookupProcessCallbackStruct *pimlp
)
{
    return invalid_operation("lookup_process");
}

int
ICState::lookup_done()
{
    return invalid_operation("lookup_done");
}

int
ICState::aux_start(
    IMAuxStartCallbackStruct *pimauxstart
)
{
    return invalid_operation("aux_start");
}

int
ICState::draw_aux(
    IMAuxDrawCallbackStruct *pimauxstart
)
{
    return invalid_operation("draw_aux");
}

int
ICState::aux_done(
    IMAuxDoneCallbackStruct *pimauxstart
)
{
    return invalid_operation("aux_done");
}

int
ICState::ns_listener(
    IMNSListenerStruct *prns
)
{
    return invalid_operation("ns_listener");
}

/*******************************************************************************
                       IMLExec_ICState
*******************************************************************************/

/***************************************
      execution handlers
***************************************/
int
IMLExec_ICState::imli_nop(
    iml_inst *rv
)
{
    return 0;
}

#define IML_STATUS_HENKAN_MODE_P(s) (s & IMLSTATUS_Henkan_Mode)

int 
IMLExec_ICState::imli_set_status(
    iml_inst *rv
)
{
    iml_status_t status = *(iml_status_t *) & (rv->operand);
    return pics->toggle_client_convmode(IML_STATUS_HENKAN_MODE_P(status));
} 

int 
IMLExec_ICState::imli_reset(
    iml_inst *rv
)
{
    return 0;
}

int 
IMLExec_ICState::imli_keypress(
    iml_inst *rv
)
{
    IMKeyEventStruct *key = (IMKeyEventStruct*)&rv->operand ;
    return pics->forward_keyevent(key);
}

int 
IMLExec_ICState::imli_commit(
    iml_inst *rv
)
{
    IMText *cs = (IMText*) &rv->operand;
    return pics->commit_string(cs); 
}

int 
IMLExec_ICState::imli_reset_return(
    iml_inst *rv
)
{
    IMText *cs = (IMText*) &rv->operand;
    return pics->commit_string(cs); 
}

int 
IMLExec_ICState::imli_preedit_start(
    iml_inst *rv
)
{
    return pics->preedit_start();
}

int 
IMLExec_ICState::imli_preedit_draw(
    iml_inst *rv
)
{
    IMPreeditDrawCallbackStruct *pimpdraw = (IMPreeditDrawCallbackStruct*) &rv->operand;
    return pics->draw_preedit(pimpdraw);
}

int 
IMLExec_ICState::imli_preedit_done(
    iml_inst *rv
)
{
    return pics->preedit_done();
}

int 
IMLExec_ICState::imli_preedit_caret(
    iml_inst *rv
)
{
#if 0
    IMPreeditCaretCallbackStruct *pimpcaret = (IMPreeditCaretCallbackStruct*) &rv->operand;
#endif
    LOG_ERROR("preedit_caret has already been expired.  Simply ignore it. (%d, %d)",
	      pics->get_im_id(), pics->get_ic_id());

    return 0;
}

int 
IMLExec_ICState::imli_status_start(
    iml_inst *rv
)
{
    return pics->status_start();
}

int 
IMLExec_ICState::imli_status_draw(
    iml_inst *rv
)
{
    IMStatusDrawCallbackStruct *pimsdraw = (IMStatusDrawCallbackStruct*) &rv->operand;
    return pics->draw_status(pimsdraw);
}

int 
IMLExec_ICState::imli_status_done(
    iml_inst *rv
)
{
    return pics->status_done();
}

int 
IMLExec_ICState::imli_lookup_start(
    iml_inst *rv
)
{
    IMLookupStartCallbackStruct *pimls = (IMLookupStartCallbackStruct*) &rv->operand;
    return pics->lookup_start(pimls);
}

int 
IMLExec_ICState::imli_lookup_draw(
    iml_inst *rv
)
{
    IMLookupDrawCallbackStruct *pimld = (IMLookupDrawCallbackStruct*) &rv->operand;
    return pics->draw_lookup(pimld);
}

int 
IMLExec_ICState::imli_lookup_process(
    iml_inst *rv
)
{
#if 0
    IMLookupProcessCallbackStruct *pimlp = (IMLookupProcessCallbackStruct*) &rv->operand;
    return pics->lookup_process(pimlp);
#else
    return 0;
#endif
}

int 
IMLExec_ICState::imli_lookup_done(
    iml_inst *rv
)
{
    return pics->lookup_done();
}

int 
IMLExec_ICState::imli_aux_start(
    iml_inst *rv
)
{
    IMAuxStartCallbackStruct *pimauxstart = (IMAuxStartCallbackStruct*) &rv->operand;
    return pics->aux_start(pimauxstart);
}

int 
IMLExec_ICState::imli_aux_draw(
    iml_inst *rv
)
{
    IMAuxDrawCallbackStruct *pimauxdraw = (IMAuxDrawCallbackStruct*) &rv->operand;
    return pics->draw_aux(pimauxdraw);
}

int 
IMLExec_ICState::imli_aux_done(
    iml_inst *rv
)
{
    IMAuxDoneCallbackStruct *pimauxdone = (IMAuxDoneCallbackStruct*) &rv->operand;
    return pics->aux_done(pimauxdone);
}

int 
IMLExec_ICState::imli_ns_listener(
    iml_inst *rv
)
{
    IMNSListenerStruct *prns = (IMNSListenerStruct *) &rv->operand;
    return pics->ns_listener(prns);
}

int 
IMLExec_ICState::imli_key_info(
    iml_inst *rv
)
{
    return 0;
}

int 
IMLExec_ICState::imli_put_queue(
    iml_inst *rv
)
{
    return 0;
}


int
IMLExec_ICState::execute_opcode(
    int opcode,
    iml_inst *rv
)
{
    switch (opcode) {
      case IMM_NOP:
       return imli_nop(rv);
      case IMM_SET_STATUS:
       return imli_set_status(rv);
      case IMM_RESET:
       return imli_reset(rv);
      case IMM_KEYPRESS:
       return imli_keypress(rv);
      case IMM_COMMIT:
       return imli_commit(rv);
      case IMM_RESET_RETURN:
       return imli_reset_return(rv);
      case IMM_PREEDIT_START:
       return imli_preedit_start(rv);
      case IMM_PREEDIT_DRAW:
       return imli_preedit_draw(rv);
      case IMM_PREEDIT_DONE:
       return imli_preedit_done(rv);
      case IMM_PREEDIT_CARET: 
       return imli_preedit_caret(rv);
      case IMM_STATUS_START: 
       return imli_status_start(rv);
      case IMM_STATUS_DRAW:
       return imli_status_draw(rv);
      case IMM_STATUS_DONE:
       return imli_status_done(rv);
      case IMM_LOOKUP_START:
       return imli_lookup_start(rv);
      case IMM_LOOKUP_DRAW:
       return imli_lookup_draw(rv);
      case IMM_LOOKUP_PROCESS:
       return imli_lookup_process(rv);
      case IMM_LOOKUP_DONE:
       return imli_lookup_done(rv);
      case IMM_AUX_START_2:
       return imli_aux_start(rv);
      case IMM_AUX_DRAW_2:
       return imli_aux_draw(rv);
      case IMM_AUX_DONE_2:
       return imli_aux_done(rv);
      case IMM_NS_LISTENER:
       return imli_ns_listener(rv);
      case IMM_KEY_INFO:
       return imli_key_info(rv);
      case IMM_PUT_QUEUE:
       return imli_put_queue(rv);
    }
    return imli_nop(rv);
}

bool
IMLExec_ICState::push_back(
    iml_inst *pinst
)
{
    pinst = iml_duplicate_inst(pinst);
    // memory error.
    if (!pinst) return false;
    pendinglist.push_back(pinst);
    return true;
}

iml_inst*
IMLExec_ICState::push_insts(
    iml_inst **rrv
)
{
    iml_inst *pcur;
    iml_inst *result = NULL;
    int op;

    for (pcur = *rrv; pcur != (iml_inst*)0; pcur = pcur->next) {
	op = pcur->opcode & ~IMM_CB_RESULT_REQUIRED;
	if ((op < 0) || (op >= MAX_IMM_OPCODE)) {
	    break;
	}
	push_back(pcur);
	if (pcur->opcode & IMM_CB_RESULT_REQUIRED) {
	    if (!result) result = pcur;
	}
    }
    return result ;
}

bool
IMLExec_ICState::execute()
{
    iml_inst *pinst;
    int op;

    while (pics->send_avail_p() && !pendinglist.empty()) {
	pinst = pendinglist.front();
	op = pinst->opcode & ~IMM_CB_RESULT_REQUIRED;
	execute_opcode(op, pinst);
	pendinglist.pop_front();
	iml_delete_inst(pinst);
    }

    return true;
}

IMLExec_ICState::~IMLExec_ICState()
{
    IMLInstList::iterator it;
    for (it = pendinglist.begin(); it != pendinglist.end(); it++) {
	iml_delete_inst(*it);
    }
}


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