#include <iiimp.h>

#include "input-method.h"
#include "input-context.h"
#include "sequence.h"
#include "opcode-reply.h"


#define	ATTR_NONE		IIIMF_MESSAGE_ATTR_NONE
#define	ROLE_CLIENT		IIIMF_MESSAGE_ATTR_ROLE_CLIENT
#define	ROLE_SERVER		IIIMF_MESSAGE_ATTR_ROLE_SERVER
#define	ROLE_BOTH		IIIMF_MESSAGE_ATTR_ROLE_BOTH
#define REQUEST			IIIMF_MESSAGE_ATTR_REQUEST
#define REPLY			IIIMF_MESSAGE_ATTR_REPLY
#define NO_REPLY		IIIMF_MESSAGE_ATTR_NO_REPLY
#define IM_ACTIVE		IIIMF_MESSAGE_ATTR_IM_ACTIVE
#define IC_ACTIVE		IIIMF_MESSAGE_ATTR_IC_ACTIVE
#define STATUS_ACTIVE		IIIMF_MESSAGE_ATTR_STATUS_ACTIVE
#define PREEDIT_ACTIVE		IIIMF_MESSAGE_ATTR_PREEDIT_ACTIVE
#define LUC_ACTIVE		IIIMF_MESSAGE_ATTR_LOOKUP_CHOICE_ACTIVE
#define AUX_ACTIVE		IIIMF_MESSAGE_ATTR_AUX_ACTIVE


static const int	message_attribute[128] = {
	ATTR_NONE,	/* 0 */

	ROLE_CLIENT | REQUEST,			/* IM_CONNECT */
	ROLE_SERVER | REPLY,			/* IM_CONNECT_REPLY */
	ROLE_CLIENT | REQUEST	| IM_ACTIVE,	/* IM_DISCONNECT */
	ROLE_SERVER | REPLY	| IM_ACTIVE,	/* IM_DISCONNECT_REPLY */
	ROLE_SERVER | REQUEST,			/* IM_REGISTER_TRIGGER_KEYS */
	ROLE_BOTH   | REQUEST	| IC_ACTIVE,	/* IM_TRIGGER_NOTIFY */
	ROLE_BOTH   | REPLY	| IC_ACTIVE,	/* IM_TRIGGER_NOTIFY_REPLY */
	ROLE_BOTH   | REQUEST	| IM_ACTIVE,	/* IM_SETIMVALUES */
	ROLE_BOTH   | REPLY	| IM_ACTIVE,	/* IM_SETIMVALUES_REPLY */
	ROLE_CLIENT | REQUEST	| IM_ACTIVE,	/* IM_GETIMVALUES */
	ROLE_SERVER | REPLY	| IM_ACTIVE,	/* IM_GETIMVALUES_REPLY */

	ROLE_BOTH   | REQUEST	| IC_ACTIVE,	/* IM_FORWARD_EVENT */
	ROLE_BOTH   | REPLY	| IC_ACTIVE,	/* IM_FORWARD_EVENT_REPLY */
	ROLE_SERVER | NO_REPLY	| IC_ACTIVE,	/* IM_COMMIT_STRING */
	ROLE_BOTH   | REQUEST	| IC_ACTIVE,	/* IM_FORWARD_EVENT_WITH_OPERATIONS */
	ROLE_BOTH   | REPLY	| IC_ACTIVE,	/* IM_FORWARD_EVENT_WITH_OPERATIONS_REPLY */

	ATTR_NONE,	/* 17 */
	ATTR_NONE,	/* 18 */
	ATTR_NONE,	/* 19 */

	ROLE_CLIENT | REQUEST	| IM_ACTIVE,	/* IM_CREATEIC */
	ROLE_SERVER | REPLY	| IM_ACTIVE,	/* IM_CREATEIC_REPLY */
	ROLE_CLIENT | REQUEST	| IC_ACTIVE,	/* IM_DESTROYIC */
	ROLE_SERVER | REPLY	| IC_ACTIVE,	/* IM_DESTROYIC_REPLY */
	ROLE_CLIENT | REQUEST	| IC_ACTIVE,	/* IM_SETICVALUES */
	ROLE_SERVER | REPLY	| IC_ACTIVE,	/* IM_SETICVALUES_REPLY */
	ROLE_CLIENT | REQUEST	| IC_ACTIVE,	/* IM_GETICVALUES */
	ROLE_SERVER | REPLY	| IC_ACTIVE,	/* IM_GETICVALUES_REPLY */
	ROLE_CLIENT | REQUEST	| IC_ACTIVE,	/* IM_SETICFOCUS */
	ROLE_SERVER | REPLY	| IC_ACTIVE,	/* IM_SETICFOCUS_REPLY */
	ROLE_CLIENT | REQUEST	| IC_ACTIVE,	/* IM_UNSETICFOCUS */
	ROLE_SERVER | REPLY	| IC_ACTIVE,	/* IM_UNSETICFOCUS_REPLY */
	ROLE_CLIENT | REQUEST	| IC_ACTIVE,	/* IM_RESETIC */
	ROLE_SERVER | REPLY	| IC_ACTIVE,	/* IM_RESETIC_REPLY */

	ATTR_NONE,	/* 34 */
	ATTR_NONE,	/* 35 */
	ATTR_NONE,	/* 36 */
	ATTR_NONE,	/* 37 */
	ATTR_NONE,	/* 38 */
	ATTR_NONE,	/* 39 */

	ROLE_SERVER | REQUEST	| IC_ACTIVE,			/* IM_PREEDIT_START */
	ROLE_CLIENT | REPLY	| IC_ACTIVE,			/* IM_PREEDIT_START_REPLY */
	ROLE_SERVER | REQUEST	| IC_ACTIVE | PREEDIT_ACTIVE,	/* IM_PREEDIT_DRAW */
	ROLE_CLIENT | REPLY	| IC_ACTIVE | PREEDIT_ACTIVE,	/* IM_PREEDIT_DRAW_REPLY */
	ATTR_NONE,	/* 44 */
	ATTR_NONE,	/* 45 */
	ROLE_SERVER | REQUEST	| IC_ACTIVE,			/* IM_PREEDIT_DONE */
	ROLE_CLIENT | REPLY	| IC_ACTIVE,			/* IM_PREEDIT_DONE_REPLY */

	ATTR_NONE,	/* 48 */
	ATTR_NONE,	/* 49 */

	ROLE_SERVER | REQUEST	| IC_ACTIVE,			/* IM_STATUS_START */
	ROLE_CLIENT | REPLY	| IC_ACTIVE,			/* IM_STATUS_START_REPLY */
	ROLE_SERVER | REQUEST	| IC_ACTIVE | STATUS_ACTIVE,	/* IM_STATUS_DRAW */
	ROLE_CLIENT | REPLY	| IC_ACTIVE | STATUS_ACTIVE,	/* IM_STATUS_DRAW_REPLY */
	ROLE_SERVER | REQUEST	| IC_ACTIVE,			/* IM_STATUS_DONE */
	ROLE_CLIENT | REPLY	| IC_ACTIVE,			/* IM_STATUS_DONE_REPLY */

	ATTR_NONE,	/* 56 */
	ATTR_NONE,	/* 57 */
	ATTR_NONE,	/* 58 */
	ATTR_NONE,	/* 59 */
	ATTR_NONE,	/* 60 */
	ATTR_NONE,	/* 61 */
	ATTR_NONE,	/* 62 */
	ATTR_NONE,	/* 63 */
	ATTR_NONE,	/* 64 */
	ATTR_NONE,	/* 65 */
	ATTR_NONE,	/* 66 */
	ATTR_NONE,	/* 67 */
	ATTR_NONE,	/* 68 */
	ATTR_NONE,	/* 69 */

	ROLE_SERVER | REQUEST	| IC_ACTIVE,			/* IM_LOOKUP_CHOICE_START */
	ROLE_CLIENT | REPLY	| IC_ACTIVE,			/* IM_LOOKUP_CHOICE_START_REPLY */
	ROLE_SERVER | REQUEST	| IC_ACTIVE | LUC_ACTIVE,	/* IM_LOOKUP_CHOICE_DRAW */
	ROLE_CLIENT | REPLY	| IC_ACTIVE | LUC_ACTIVE,	/* IM_LOOKUP_CHOICE_DRAW_REPLY */
	ROLE_SERVER | REQUEST	| IC_ACTIVE,			/* IM_LOOKUP_CHOICE_DONE */
	ROLE_CLIENT | REPLY	| IC_ACTIVE,			/* IM_LOOKUP_CHOICE_DONE_REPLY */
	ROLE_SERVER | REQUEST	| IC_ACTIVE | LUC_ACTIVE,	/* IM_LOOKUP_CHOICE_PROCESS */
	ROLE_CLIENT | REPLY	| IC_ACTIVE | LUC_ACTIVE,	/* IM_LOOKUP_CHOICE_PROCESS_REPLY */

	ATTR_NONE,	/* 78 */
	ATTR_NONE,	/* 79 */
	ATTR_NONE,	/* 80 */
	ATTR_NONE,	/* 81 */
	ATTR_NONE,	/* 82 */
	ATTR_NONE,	/* 83 */
	ATTR_NONE,	/* 84 */
	ATTR_NONE,	/* 85 */
	ATTR_NONE,	/* 86 */
	ATTR_NONE,	/* 87 */
	ATTR_NONE,	/* 88 */
	ATTR_NONE,	/* 89 */

	ROLE_SERVER | REQUEST	| IC_ACTIVE,			/* IM_AUX_START */
	ROLE_CLIENT | REPLY	| IC_ACTIVE,			/* IM_AUX_START_REPLY */
	ROLE_SERVER | REQUEST	| IC_ACTIVE /* | AUX_ACTIVE */,	/* IM_AUX_DRAW */
	ROLE_CLIENT | REPLY	| IC_ACTIVE /* | AUX_ACTIVE */,	/* IM_AUX_DRAW_REPLY */
	ROLE_SERVER | REQUEST	| IC_ACTIVE,			/* IM_AUX_DONE */
	ROLE_CLIENT | REPLY	| IC_ACTIVE,			/* IM_AUX_DONE_REPLY */
	ROLE_CLIENT | REQUEST	| IC_ACTIVE /* | AUX_ACTIVE */,	/* IM_AUX_SETVALUES */
	ROLE_SERVER | REPLY	| IC_ACTIVE /* | AUX_ACTIVE */,	/* IM_AUX_SETVALUES_REPLY */

	ROLE_CLIENT | REQUEST	| IC_ACTIVE /* | AUX_ACTIVE */,	/* IM_AUX_GETVALUES */
	ROLE_SERVER | REPLY	| IC_ACTIVE /* | AUX_ACTIVE */,	/* IM_AUX_GETVALUES_REPLY */
	ATTR_NONE,	/* 100 */
	ATTR_NONE,	/* 101 */
	ATTR_NONE,	/* 102 */
	ATTR_NONE,	/* 103 */
	ATTR_NONE,	/* 104 */
	ATTR_NONE,	/* 105 */
	ATTR_NONE,	/* 106 */
	ATTR_NONE,	/* 107 */
	ATTR_NONE,	/* 108 */
	ATTR_NONE,	/* 109 */
	ATTR_NONE,	/* 110 */
	ATTR_NONE,	/* 111 */
	ATTR_NONE,	/* 112 */
	ATTR_NONE,	/* 113 */
	ATTR_NONE,	/* 114 */
	ATTR_NONE,	/* 115 */
	ATTR_NONE,	/* 116 */
	ATTR_NONE,	/* 117 */
	ATTR_NONE,	/* 118 */
	ATTR_NONE,	/* 119 */
	ATTR_NONE,	/* 120 */
	ATTR_NONE,	/* 121 */
	ATTR_NONE,	/* 122 */
	ATTR_NONE,	/* 123 */
	ATTR_NONE,	/* 124 */
	ATTR_NONE,	/* 125 */
	ATTR_NONE,	/* 126 */
	ATTR_NONE,	/* 127 */
};


IIIMF_status
iiimf_message_sequence(
    IIIMF_im *		im,
    IIIMF_ic *		ic,
    IIIMP_message *	message,
    int			direction)
{
    IIIMF_status		status;
    int				attr_cur;
    int				attr;
    int				attr_active;
    int				opcode_reply;
    IIIMF_message_pending *	mp;

    status = IIIMF_STATUS_SUCCESS;

    attr = message_attribute[message->opcode];

    if ((0 == (IIIMF_MESSAGE_ATTR_ROLE_BOTH & attr)) &&
	((IIIMF_MESSAGE_ATTR_ROLE_DIRECTION_MASK & attr) ==
	 (im->role ^ direction))) {
	return IIIMF_STATUS_SEQUENCE_ROLE;
    }

    attr_cur = ((NULL == ic) ? im->state : (im->state | ic->state));

    attr_active = (IIIMF_MESSAGE_ATTR_ACTIVE_MASK & attr);
    if (attr_active != (attr_active & attr_cur)) {
	return IIIMF_STATUS_SEQUENCE_STATE;
    }

    if (0 != (IIIMF_MESSAGE_ATTR_REPLY & attr)) {
	/*
	 * REPLY message must follow REQUEST message
	 */
	if (im->message_depth <= 0) {
	    return IIIMF_STATUS_SEQUENCE_REQUEST;
	}

	im->message_depth -= 1;
	mp = (im->message_pending + im->message_depth);
	opcode_reply = iiimf_opcode_reply_internal(mp->opcode);

	if ((message->opcode != opcode_reply) || (direction == mp->direction)) {
	    return IIIMF_STATUS_SEQUENCE_REQUEST;
	}

    } else {
	opcode_reply = iiimf_opcode_reply_internal(message->opcode);
	if (IM_NOP != opcode_reply) {
	    if (im->message_depth_maximum <= im->message_depth) {
		return IIIMF_STATUS_SEQUENCE_NEST;
	    }
	    mp = (im->message_pending + im->message_depth);
	    mp->opcode = message->opcode;
	    mp->direction = direction;
	    im->message_depth += 1;
	}
    }

    switch (message->opcode) {
    case IM_CONNECT:
	im->state |= IIIMF_MESSAGE_ATTR_IM_IM_CONNECT;
	break;

    case IM_CONNECT_REPLY:
	if (-1 == im->im_id) {
	    im->im_id = message->im_id;
	} else if (message->im_id != im->im_id) {
	    return IIIMF_STATUS_SEQUENCE_STATE;
	}
	im->state &= ~IIIMF_MESSAGE_ATTR_IM_IM_CONNECT;
	im->state |= IIIMF_MESSAGE_ATTR_IM_ACTIVE;
	break;

    case IM_DISCONNECT:
	break;

    case IM_DISCONNECT_REPLY:
	im->state &= IIIMF_MESSAGE_ATTR_NONE;
	break;

    case IM_REGISTER_TRIGGER_KEYS:
	if ((0 != (IIIMF_MESSAGE_ATTR_IM_ACTIVE & im->state)) ||
	    (0 == (IIIMF_MESSAGE_ATTR_IM_IM_CONNECT & im->state))) {
	    return IIIMF_STATUS_SEQUENCE_STATE;
	}
	im->im_id = message->im_id;
	break;

    case IM_TRIGGER_NOTIFY:
    case IM_TRIGGER_NOTIFY_REPLY:
    case IM_SETIMVALUES:
    case IM_SETIMVALUES_REPLY:
    case IM_GETIMVALUES:
    case IM_GETIMVALUES_REPLY:
    case IM_FORWARD_EVENT:
    case IM_FORWARD_EVENT_REPLY:
    case IM_COMMIT_STRING:
    case IM_FORWARD_EVENT_WITH_OPERATIONS:
    case IM_FORWARD_EVENT_WITH_OPERATIONS_REPLY:
    case IM_CREATEIC:
	break;

    case IM_CREATEIC_REPLY:
	im->state |= IIIMF_MESSAGE_ATTR_IC_ACTIVE;
	ic->ic_id = message->ic_id;
	break;

    case IM_DESTROYIC:
	break;

    case IM_DESTROYIC_REPLY:
	im->state &= ~(IIIMF_MESSAGE_ATTR_IC_ACTIVE |
		       IIIMF_MESSAGE_ATTR_STATUS_ACTIVE |
		       IIIMF_MESSAGE_ATTR_PREEDIT_ACTIVE |
		       IIIMF_MESSAGE_ATTR_LOOKUP_CHOICE_ACTIVE |
		       IIIMF_MESSAGE_ATTR_AUX_ACTIVE);
	break;

    case IM_SETICVALUES:
    case IM_SETICVALUES_REPLY:
    case IM_GETICVALUES:
    case IM_GETICVALUES_REPLY:
    case IM_SETICFOCUS:
    case IM_SETICFOCUS_REPLY:
    case IM_UNSETICFOCUS:
    case IM_UNSETICFOCUS_REPLY:
    case IM_RESETIC:
    case IM_RESETIC_REPLY:
    case IM_PREEDIT_START:
	break;

    case IM_PREEDIT_START_REPLY:
	im->state |= IIIMF_MESSAGE_ATTR_PREEDIT_ACTIVE;
	break;

    case IM_PREEDIT_DRAW:
    case IM_PREEDIT_DRAW_REPLY:
    case IM_PREEDIT_DONE:
	break;

    case IM_PREEDIT_DONE_REPLY:

	im->state &= ~IIIMF_MESSAGE_ATTR_PREEDIT_ACTIVE;
	break;

    case IM_STATUS_START:
	break;

    case IM_STATUS_START_REPLY:
	im->state |= IIIMF_MESSAGE_ATTR_STATUS_ACTIVE;
	break;

    case IM_STATUS_DRAW:
    case IM_STATUS_DRAW_REPLY:
    case IM_STATUS_DONE:
	break;

    case IM_STATUS_DONE_REPLY:
	im->state &= ~IIIMF_MESSAGE_ATTR_STATUS_ACTIVE;
	break;

    case IM_LOOKUP_CHOICE_START:
	break;

    case IM_LOOKUP_CHOICE_START_REPLY:
	im->state |= IIIMF_MESSAGE_ATTR_LOOKUP_CHOICE_ACTIVE;
	break;

    case IM_LOOKUP_CHOICE_DRAW:
    case IM_LOOKUP_CHOICE_DRAW_REPLY:
    case IM_LOOKUP_CHOICE_DONE:
	break;

    case IM_LOOKUP_CHOICE_DONE_REPLY:
	im->state &= ~IIIMF_MESSAGE_ATTR_LOOKUP_CHOICE_ACTIVE;
	break;

    case IM_LOOKUP_CHOICE_PROCESS:
    case IM_LOOKUP_CHOICE_PROCESS_REPLY:
    case IM_AUX_START:
	break;

    case IM_AUX_START_REPLY:
	im->state |= IIIMF_MESSAGE_ATTR_AUX_ACTIVE;
	break;

    case IM_AUX_DRAW:
    case IM_AUX_DRAW_REPLY:
    case IM_AUX_DONE:
	break;

    case IM_AUX_DONE_REPLY:
	im->state &= ~IIIMF_MESSAGE_ATTR_AUX_ACTIVE;
	break;

    case IM_AUX_SETVALUES:
    case IM_AUX_SETVALUES_REPLY:
	break;

    case IM_AUX_GETVALUES:
    case IM_AUX_GETVALUES_REPLY:
	break;
    }

    return status;
}


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