/*
Copyright 1990-2001 Sun Microsystems, Inc. All Rights Reserved.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions: The above copyright notice and this
permission notice shall be included in all copies or substantial
portions of the Software.


THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE OPEN GROUP OR SUN MICROSYSTEMS, INC. BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE EVEN IF
ADVISED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGES.


Except as contained in this notice, the names of The Open Group and/or
Sun Microsystems, Inc. shall not be used in advertising or otherwise to
promote the sale, use or other dealings in this Software without prior
written authorization from The Open Group and/or Sun Microsystems,
Inc., as applicable.


X Window System is a trademark of The Open Group

OSF/1, OSF/Motif and Motif are registered trademarks, and OSF, the OSF
logo, LBX, X Window System, and Xinerama are trademarks of the Open
Group. All other trademarks and registered trademarks mentioned herein
are the property of their respective owners. No right, title or
interest in or to any trademark, service mark, logo or trade name of
Sun Microsystems, Inc. or its licensors is granted.

*/
#if !defined(USE_FRAMEMGR_ALWAYS)
#else /* USE_FRAMEMGR_ALWAYS */
#include "FrameMgr.h"
#endif /* USE_FRAMEMGR_ALWAYS */
#include "IIIMPClient.hh"
#include "IMProtocolStruct.h"
#include "IMProtocolStructP.hh"
#include "IMTrans.hh"

#if !defined(USE_FRAMEMGR_ALWAYS)
int
IIIMPClient::imtext_size(IMText *text) {
  IMFeedbackList *feedback;
  IMAnnotation *ann;
  int size;
  int i;

  if (NULL == text) {
    return (4 + 4);
  }
  size = 0;
  size += 4;	/* byte length of list of char_with_feedback */
  for (i = 0; i < text->char_length; i++) {
    feedback = (text->feedback + i);
    size += 2;	/* character element */
    size += 2;	/* byte length of Feedback attribute array */
    size += (8 * feedback->count_feedbacks);	/* feedback */
  }
  size += 4;	/* byte length of list of annotation */
  for (i = 0; i < text->count_annotations; i++) {
    ann = (text->annotations + i);
    size += 4;	/* attribute ID */
    size += 4;	/* byte length of list of annotation value */
    size += 4;	/* start index */
    size += 4;	/* byte length of value */
    if (ann->value.len & 0x03) {
      size += ((ann->value.len & (~0x03)) + 4);
    } else {
      size += ann->value.len;
    }
  }
  return size;
}

char *
IIIMPClient::req_put_imtext(char * ptr, IMText * text) {
  IMFeedbackList *feedback;
  IMAnnotation *ann;
  int size;
  int i;
  int j;
  char *ptr_hold;

  if (NULL == text) {
    req_put32(ptr, 0);	/* byte length of list of char_with_feedback */
    req_put32(ptr, 0);	/* byte length of list of annotation */
    return ptr;
  }

  ptr_hold = ptr;
  req_put32(ptr, 0);	/* dummy */
  size = 0;
  for (i = 0; i < text->char_length; i++) {
    feedback = (text->feedback + i);
    req_put16(ptr, *(text->text.utf_chars + i));
    req_put16(ptr, (8 * feedback->count_feedbacks));
    size += 4;
    for (j = 0; j < feedback->count_feedbacks; j++) {
      req_put32(ptr, (feedback->feedbacks + j)->type);
      req_put32(ptr, (feedback->feedbacks + j)->value);
      size += 8;
    }
  }
  req_put32(ptr_hold, size);

  ptr_hold = ptr;
  req_put32(ptr, 0);	/* dummy */
  size = 0;
  for (i = 0; i < text->count_annotations; i++) {
    ann = (text->annotations + i);
    req_put32(ptr, ann->type);		/* attribute ID */
    req_put32(ptr, ann->value.len);	/* byte length of list of annotation value */
    req_put32(ptr, ann->value.start_pos);	/* start index */
    req_put32(ptr, ann->value.end_pos);	/* byte length of value */
    size += (4 * 4);
    for (j = 0; j < ann->value.len; j++) {
      req_put8(ptr, *(((char *)(ann->value.value)) + j));
    }
    for (i = (ann->value.len & 0x03); 0 < i; i++) {
      req_put8(ptr, 0);
    }
    if (ann->value.len & 0x03) {
      size += ((ann->value.len & (~0x03)) + 4);
    } else {
      size += ann->value.len;
    }
  }
  req_put32(ptr_hold, size);

  return ptr;
}

char *
IIIMPClient::req_put_imtext_s(char * ptr, IMText * text) {
  IMFeedbackList *feedback;
  IMAnnotation *ann;
  int size;
  int i;
  int j;
  char *ptr_hold;

  if (NULL == text) {
    req_put32s(ptr, 0);	/* byte length of list of char_with_feedback */
    req_put32s(ptr, 0);	/* byte length of list of annotation */
    return ptr;
  }

  ptr_hold = ptr;
  req_put32s(ptr, 0);	/* dummy */
  size = 0;
  for (i = 0; i < text->char_length; i++) {
    feedback = (text->feedback + i);
    req_put16s(ptr, *(text->text.utf_chars + i));
    req_put16s(ptr, (8 * feedback->count_feedbacks));
    size += 4;
    for (j = 0; j < feedback->count_feedbacks; j++) {
      req_put32s(ptr, (feedback->feedbacks + j)->type);
      req_put32s(ptr, (feedback->feedbacks + j)->value);
      size += 8;
    }
  }
  req_put32s(ptr_hold, size);

  ptr_hold = ptr;
  req_put32s(ptr, 0);	/* dummy */
  size = 0;
  for (i = 0; i < text->count_annotations; i++) {
    ann = (text->annotations + i);
    req_put32s(ptr, ann->type);		/* attribute ID */
    req_put32s(ptr, ann->value.len);	/* byte length of list of annotation value */
    req_put32s(ptr, ann->value.start_pos);	/* start index */
    req_put32s(ptr, ann->value.end_pos);	/* byte length of value */
    size += (4 * 4);
    for (j = 0; j < ann->value.len; j++) {
      req_put8s(ptr, *(((char *)(ann->value.value)) + j));
    }
    for (i = (ann->value.len & 0x03); 0 < i; i++) {
      req_put8s(ptr, 0);
    }
    if (ann->value.len & 0x03) {
      size += ((ann->value.len & (~0x03)) + 4);
    } else {
      size += ann->value.len;
    }
  }
  req_put32s(ptr_hold, size);

  return ptr;
}

int
IIIMPClient::utf16_string_size(int len) {
  int size;
  size = 2;		/* byte length of LISTofCHAR */
  size += (2 * len);	/* string */
  if (size & 0x02) {	/* padding */
    size += 2;
  }

  return size;
}

char *
IIIMPClient::req_put_utf16_string(char * ptr, UTFCHAR * string, int length) {
  int i;
  int j;
  char *ptr_hold;

  req_put16(ptr, (2 * length));
  for (i = 0; i < length; i++) {
    req_put16(ptr, *(string + i));
  }
  if (0 == (length & 0x01)) {
    req_put16(ptr, 0);		/* padding */
  }
  return ptr;
}

char *
IIIMPClient::req_put_utf16_string_s(char * ptr, UTFCHAR * string, int length) {
  int i;
  int j;
  char *ptr_hold;

  req_put16s(ptr, (2 * length));
  for (i = 0; i < length; i++) {
    req_put16s(ptr, *(string + i));
  }
  if (0 == (length & 0x01)) {
    req_put16s(ptr, 0);		/* padding */
  }
  return ptr;
}

int
IIIMPClient::ascii_string_size(char * string) {
  int size;

  size = 2;		/* byte length of LISTofCHAR */
  if (NULL != string) {	/* string */
    size += (2 * strlen(string));
  }
  if (size & 0x02) {	/* padding */
    size += 2;
  }
  return size;
}

char *
IIIMPClient::req_put_ascii_string(char * ptr, char * string) {
  int length;
  int i;
  int j;
  char *ptr_hold;

  if (NULL == string) {
    length = 0;
  } else {
    length = strlen(string);
  }
  req_put16(ptr, (2 * length));
  for (i = 0; i < length; i++) {
    req_put16(ptr, *(string + i));
  }
  if (0 == (length & 0x01)) {
    req_put16(ptr, 0);		/* padding */
  }
  return ptr;
}

char *
IIIMPClient::req_put_ascii_string_s(char * ptr, char * string) {
  int length;
  int i;
  int j;
  char *ptr_hold;

  if (NULL == string) {
    length = 0;
  } else {
    length = strlen(string);
  }
  req_put16s(ptr, (2 * length));
  for (i = 0; i < length; i++) {
    req_put16s(ptr, *(string + i));
  }
  if (0 == (length & 0x01)) {
    req_put16s(ptr, 0);		/* padding */
  }
  return ptr;
}

#else /* USE_FRAMEMGR_ALWAYS */
#endif /* USE_FRAMEMGR_ALWAYS */

int
IIIMPClient::commit_string(IMCommitCBStruct *commit_CB) {
#if !defined(USE_FRAMEMGR_ALWAYS)
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_commit_string_string_fr[];
#endif /* USE_FRAMEMGR_ALWAYS */
  IMText *text = commit_CB->text;

  if (!text || text->char_length == 0) {
    return True;	// no string to commit
  }

  int text_length = text->char_length;
  UTFCHAR *utf_chars;

  if (text->encoding == UTF16_CODESET) {
    utf_chars = text->text.utf_chars;
    if (*utf_chars == 0xfffe || *utf_chars == 0xfeff) {
      utf_chars++;
      text_length -= 1;
    }
  } else {
    utf_chars = 0;
  }

  /* without FrameMgr */
  int		total_length;
  int		str_len;
  int		contents_type;
  UTFCHAR *	ut;
  int		i;

  total_length = 0;
  contents_type = 0;		/* STRING */

  total_length += 2;		/* im_id */
  total_length += 2;		/* ic_id */

  total_length += 4;		/* contents type */
  total_length += 2;		/* byte length of string */
  str_len = (2 * text_length);	/* unicode code element */
  total_length += str_len;
  if (0 == (text_length % 2)) {
    total_length += 2; /* padding */
  }

  CompoundString request = CompoundString(total_length, 0);
  unsigned char * p;

  p = request.toUchar();

  if (False == need_swap) {
    req_put16(p, im_id);
    req_put16(p, commit_CB->icid);
    req_put32(p, contents_type);
    req_put16(p, str_len);
    for (i = 0, ut = utf_chars; i < text_length; i++, ut++) {
      req_put16(p, *ut);
    }
  } else {
    req_put16s(p, im_id);
    req_put16s(p, commit_CB->icid);
    req_put32s(p, contents_type);
    req_put16s(p, str_len);
    for (i = 0, ut = utf_chars; i < text_length; i++, ut++) {
      req_put16s(p, *ut);
    }
  }

  send_message(IM_COMMIT_STRING, request, total_length);
  return True;

#if 0
  fm = FrameMgrInit(im_commit_string_string_fr, NULL, need_swap);
		    
  int text_length = text->char_length;
  UTFCHAR *utf_chars;

  if (text->encoding == UTF16_CODESET) {
    utf_chars = text->text.utf_chars;
    if (*utf_chars == 0xfffe || *utf_chars == 0xfeff) {
      utf_chars++;
      text_length -= 1;
    }
  } else {
#ifdef DEBUG
    // cerr << "need to do convertion" << endl;
#endif
    utf_chars = 0;
  }
  FrameMgrSetIterCount(fm, text_length);
  const int total_size = FrameMgrGetTotalSize(fm);
  CompoundString reply = CompoundString(total_size);
  memset(reply, 0, total_size);
  FrameMgrSetBuffer(fm, reply);

  int flag = 0;	/* #0 for STRING */
  FrameMgrPutToken(fm, im_id);
  FrameMgrPutToken(fm, commit_CB->icid);
  FrameMgrPutToken(fm, flag);

  SetStringToFrame(fm, utf_chars, text_length);

  send_message(IM_COMMIT_STRING, reply, total_size);
  /* free FrameMgr */
  FrameMgrFree(fm);
  return True;
#endif /* 0 */
}

int
IIIMPClient::forward_event(IMForwardEventCBStruct *event_CB) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  const int total_size = (4 + 2 + 2 + 4 + 4 + ((4 * 4) * 1));
  char data[total_size];
  char *ptr;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_forward_event_keyevent_fr[];
#endif /* USE_FRAMEMGR_ALWAYS */

#if !defined(USE_FRAMEMGR_ALWAYS)
  ptr = (data + 4);
  if (False == need_swap) {
    req_put16(ptr, im_id); 
    req_put16(ptr, event_CB->icid);
    req_put32(ptr, 2);		/* KEYEVENT type = #02 */
    req_put32(ptr, 16);		/* one KEYEVENT */
    req_put32(ptr, event_CB->event->keyCode);
    req_put32(ptr, event_CB->event->keyChar);
    req_put32(ptr, event_CB->event->modifier);
    req_put32(ptr, event_CB->event->time_stamp);
  } else {
    req_put16s(ptr, im_id); 
    req_put16s(ptr, event_CB->icid);
    req_put32s(ptr, 2);		/* KEYEVENT type = #02 */
    req_put32s(ptr, 16);	/* one KEYEVENT */
    req_put32s(ptr, event_CB->event->keyCode);
    req_put32s(ptr, event_CB->event->keyChar);
    req_put32s(ptr, event_CB->event->modifier);
    req_put32s(ptr, event_CB->event->time_stamp);
  }
  send_message(IM_FORWARD_EVENT, data, (sizeof (data)));
#else /* USE_FRAMEMGR_ALWAYS */
  fm = FrameMgrInit(im_forward_event_keyevent_fr, NULL, need_swap);

  int iter_count = 1;
  FrameMgrSetIterCount(fm, iter_count);

  const int total_size = FrameMgrGetTotalSize(fm);
  CompoundString reply = CompoundString(total_size);
  memset(reply, 0, total_size);
  FrameMgrSetBuffer(fm, reply);

  FrameMgrPutToken(fm, im_id);
  FrameMgrPutToken(fm, event_CB->icid);
  int type = 2; /* KEYEVENT type = #02 */
  FrameMgrPutToken(fm, type);

  IMKeyEventStruct *key = event_CB->event;
  FrameMgrPutToken(fm, key->keyCode);
  FrameMgrPutToken(fm, key->keyChar);
  FrameMgrPutToken(fm, key->modifier);
  FrameMgrPutToken(fm, key->time_stamp);

  send_message(IM_FORWARD_EVENT, reply, total_size);

  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */

  return True;
}

int IIIMPClient::preedit_start(IMPreeditCBStruct *preedit_CB) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  send_message(im_id, preedit_CB->icid, IM_PREEDIT_START);
#else /* USE_FRAMEMGR_ALWAYS */
  extern XimFrameRec im_preedit_start_fr[];
  send_message(im_id, preedit_CB->icid,
	       im_preedit_start_fr, IM_PREEDIT_START);
#endif /* USE_FRAMEMGR_ALWAYS */
  return True;
}

int IIIMPClient::preedit_erase_text(IMPreeditCBStruct *preedit_CB) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  char data[4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4];
  char *ptr;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_preedit_draw_string_fr[];
#endif /* USE_FRAMEMGR_ALWAYS */
  IMPreeditDrawCallbackStruct *draw =
    (IMPreeditDrawCallbackStruct *)&preedit_CB->preedit->todo.draw;
  IMText *text = draw->text;

#if !defined(USE_FRAMEMGR_ALWAYS)
  ptr = (data + 4);
  if (False == need_swap) {
    req_put16(ptr, im_id);
    req_put16(ptr, preedit_CB->icid);
    req_put32(ptr, draw->caret);
    req_put32(ptr, draw->chg_first);
    req_put32(ptr, draw->chg_length);
    req_put32(ptr, 1);	/* #1 for TEXT */
    req_put32(ptr, 0);	/* byte length of list of char_with_feedbac */
    req_put32(ptr, 0);	/* byte length of list of annotatio */
  } else {
    req_put16s(ptr, im_id);
    req_put16s(ptr, preedit_CB->icid);
    req_put32s(ptr, draw->caret);
    req_put32s(ptr, draw->chg_first);
    req_put32s(ptr, draw->chg_length);
    req_put32s(ptr, 1);	/* #1 for TEXT */
    req_put32s(ptr, 0);	/* byte length of list of char_with_feedbac */
    req_put32s(ptr, 0);	/* byte length of list of annotatio */
  }
  send_message(IM_PREEDIT_DRAW, data, (sizeof (data)));

#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(im_preedit_draw_string_fr, NULL, need_swap);

  const int text_length = 0;
  FrameMgrSetIterCount(fm, text_length);

  const int total_size = FrameMgrGetTotalSize(fm);
  CompoundString reply = CompoundString(total_size);
  memset(reply, 0, total_size);
  FrameMgrSetBuffer(fm, reply);

  FrameMgrPutToken(fm, im_id);
  FrameMgrPutToken(fm, preedit_CB->icid);
  FrameMgrPutToken(fm, draw->caret);
  FrameMgrPutToken(fm, draw->chg_first);
  FrameMgrPutToken(fm, draw->chg_length);
  int flag = 1;	/* #1 for TEXT */
  FrameMgrPutToken(fm, flag);

  int annotation_len = 0;	/* annotation is not used */
  FrameMgrPutToken(fm, annotation_len); /* annotation_len = 0 */

  send_message(IM_PREEDIT_DRAW, reply, total_size);
  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */
  return True;
}

int IIIMPClient::preedit_draw_text(IMPreeditCBStruct *preedit_CB) {
#if !defined(USE_FRAMEMGR_ALWAYS)
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_preedit_draw_text_fr[];
#endif /* USE_FRAMEMGR_ALWAYS */
  IMPreeditDrawCallbackStruct *draw =
    (IMPreeditDrawCallbackStruct *)&preedit_CB->preedit->todo.draw;
  IMText *text = draw->text;
  int i, j;

  if (text->char_length == 0) {
    return True;	/* no string to draw */
  }

#if !defined(USE_FRAMEMGR_ALWAYS)
  int text_length = text->char_length;
  UTFCHAR *utf_chars;

  if (text->encoding == UTF16_CODESET) {
    utf_chars = text->text.utf_chars;
    if (*utf_chars == 0xfffe || *utf_chars == 0xfeff) {
      utf_chars++;
      text_length -= 1;
    }
  } else {
    utf_chars = 0;
  }

  /* without FrameMgr */
  int		total_length;
  int		fa_len;
  int		cwf_len;
  int		annotation_len;
  int		contents_type;
  UTFCHAR *	ut;

  total_length = 0;
  fa_len = 0;
  cwf_len = 0;
  annotation_len = 0;
  contents_type = 1;		/* contents type #1 : TEXT */

  total_length += 4;		/* request header */

  total_length += 2;		/* im_id */
  total_length += 2;		/* ic_id */
  total_length += 4;		/* caret */
  total_length += 4;		/* change_first */
  total_length += 4;		/* change_length */

  total_length += 4;		/* contents type */
  total_length += 4;		/* byte length of list of char_with_feedback */
  cwf_len += (2 * text_length);	/* unicode code element */
  cwf_len += (2 * text_length);	/* byte length of Feedback attribute */
					/* array */
  for (i = 0; i < text_length; i++) {	/* feedback_attr */
    fa_len += (8 * (text->feedback + i)->count_feedbacks);
  }
  cwf_len += fa_len;

  total_length += cwf_len;

  total_length += 4;		/* byte length of list of annotation */
  total_length += 0;		/* annotation is not supported yet */

  char * request = new char[total_length];
  char * p;

  p = (request + 4);

  if (False == need_swap) {
    req_put16(p, im_id);
    req_put16(p, preedit_CB->icid);
    req_put32(p, draw->caret);
    req_put32(p, draw->chg_first);
    req_put32(p, draw->chg_length);
    req_put32(p, contents_type);
    req_put32(p, cwf_len);
    for (i = 0, ut = utf_chars; i < text_length; i++, ut++) {
      int cf;
      req_put16(p, *ut);
      cf = (text->feedback + i)->count_feedbacks;
      req_put16(p, (8 * cf));
      for (j = 0; j < cf; j++) {
	req_put32(p, ((text->feedback + i)->feedbacks + j)->type);
	req_put32(p, ((text->feedback + i)->feedbacks + j)->value);
      }
    }
    req_put32(p, annotation_len);	/* annotation is not supported yet */
  } else {
    req_put16s(p, im_id);
    req_put16s(p, preedit_CB->icid);
    req_put32s(p, draw->caret);
    req_put32s(p, draw->chg_first);
    req_put32s(p, draw->chg_length);
    req_put32s(p, contents_type);
    req_put32s(p, cwf_len);
    for (i = 0, ut = utf_chars; i < text_length; i++, ut++) {
      int cf;
      req_put16s(p, *ut);
      cf = (text->feedback + i)->count_feedbacks;
      req_put16s(p, (8 * cf));
      for (j = 0; j < cf; j++) {
	req_put32s(p, ((text->feedback + i)->feedbacks + j)->type);
	req_put32s(p, ((text->feedback + i)->feedbacks + j)->value);
      }
    }
    req_put32s(p, annotation_len);	/* annotation is not supported yet */
  }

  send_message(IM_PREEDIT_DRAW, request, total_length);

  delete [] request;

  return True;

#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(im_preedit_draw_text_fr, NULL, need_swap);
	
  int text_length = text->char_length;
  UTFCHAR *utf_chars;

  if (text->encoding == UTF16_CODESET) {
    utf_chars = text->text.utf_chars;
    if (*utf_chars == 0xfffe || *utf_chars == 0xfeff) {
      utf_chars++;
      text_length -= 1;
    }
  } else {
#ifdef DEBUG
    // cerr << "need to do convertion" << endl;
#endif
    utf_chars = 0;
  }
  FrameMgrSetIterCount(fm, text_length);

  if (text != NULL) {
    for (i = 0; i < text_length; i++) {
      IMFeedbackList *fbl = &(text->feedback[i]);
      // set iteration count for list of feedback
      FrameMgrSetIterCount(fm, fbl->count_feedbacks);
    }
  }

  const int total_size = FrameMgrGetTotalSize(fm);
  CompoundString reply = CompoundString(total_size);
  memset(reply, 0, total_size);
  FrameMgrSetBuffer(fm, reply);
    
  FrameMgrPutToken(fm, im_id);
  FrameMgrPutToken(fm, preedit_CB->icid);
  FrameMgrPutToken(fm, draw->caret);
  FrameMgrPutToken(fm, draw->chg_first);
  FrameMgrPutToken(fm, draw->chg_length);
  int flag = 1;			/* #1 for TEXT */
  FrameMgrPutToken(fm, flag);

  CARD8 *utf_str = (CARD8*)utf_chars;
  CARD8 *strp = utf_str;

  const int one_unit = sizeof(UTFCHAR)/sizeof(char);
  for (i = 0; i < text_length, strp < &utf_str[text_length * one_unit];
       i++) {
    CARD8 first_byte, second_byte;
    if (need_swap) {
      second_byte = *strp++;
      first_byte = *strp++;
    } else {
      first_byte = *strp++;
      second_byte = *strp++;
    }
    FrameMgrPutToken(fm, first_byte);
    FrameMgrPutToken(fm, second_byte);

    if (text != NULL) {
	IMFeedbackList *fbl = &(text->feedback[i]);
        for (j = 0; j < fbl->count_feedbacks; j++){
	  IMFeedback *fb = &(fbl->feedbacks[j]);
	  FrameMgrPutToken(fm, fb->type);
	  FrameMgrPutToken(fm, fb->value);
	}
    }
  }
  int annotation_len = 0;	/* annotation is not used */
  FrameMgrPutToken(fm, annotation_len); /* annotation_len = 0 */

  send_message(IM_PREEDIT_DRAW, reply, total_size);
  /* free FrameMgr */
  FrameMgrFree(fm);

  return True;
#endif /* USE_FRAMEMGR_ALWAYS */
}

int IIIMPClient::preedit_draw(IMPreeditCBStruct *preedit_CB) {
  IMPreeditDrawCallbackStruct *draw =
    (IMPreeditDrawCallbackStruct *)&preedit_CB->preedit->todo.draw;
  int ret;

  if (draw->text == NULL || draw->text->char_length == 0) {
    ret = preedit_erase_text(preedit_CB);
  } else {
    ret = preedit_draw_text(preedit_CB);
  }
  return ret;
}

int IIIMPClient::preedit_caret(IMPreeditCBStruct *preedit_CB) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  char data[4 + 2 + 2 + 4 + 4 + 4];
  char *ptr;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_preedit_caret_fr[];
#endif /* USE_FRAMEMGR_ALWAYS */
  IMPreeditCaretCallbackStruct *caret =
    (IMPreeditCaretCallbackStruct *)&preedit_CB->preedit->todo.caret;

#if !defined(USE_FRAMEMGR_ALWAYS)
  ptr = (data + 4);
  if (False == need_swap) {
    req_put16(ptr, im_id);
    req_put16(ptr, preedit_CB->icid);
    req_put32(ptr, caret->position);
    req_put32(ptr, caret->direction);
    req_put32(ptr, caret->style);
  } else {
    req_put16s(ptr, im_id);
    req_put16s(ptr, preedit_CB->icid);
    req_put32s(ptr, caret->position);
    req_put32s(ptr, caret->direction);
    req_put32s(ptr, caret->style);
  }
  send_message(IM_PREEDIT_CARET, data, (sizeof (data)));
#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(im_preedit_caret_fr, NULL, need_swap);

  const int total_size = FrameMgrGetTotalSize(fm);
  CompoundString reply = CompoundString(total_size);
  memset(reply, 0, total_size);
  FrameMgrSetBuffer(fm, reply);

  FrameMgrPutToken(fm, im_id);
  FrameMgrPutToken(fm, preedit_CB->icid);
  FrameMgrPutToken(fm, caret->position);
  FrameMgrPutToken(fm, caret->direction);
  FrameMgrPutToken(fm, caret->style);

  send_message(IM_PREEDIT_CARET, reply, total_size);
  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */
  return True;
}

int IIIMPClient::preedit_done(IMPreeditCBStruct *preedit_CB) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  send_message(im_id, preedit_CB->icid, IM_PREEDIT_DONE);
#else /* USE_FRAMEMGR_ALWAYS */
  extern XimFrameRec im_preedit_done_fr[];
  send_message(im_id, preedit_CB->icid,
	       im_preedit_done_fr, IM_PREEDIT_DONE);
#endif /* USE_FRAMEMGR_ALWAYS */
  return True;
}

int IIIMPClient::status_start(IMStatusCBStruct *status_CB) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  send_message(im_id, status_CB->icid, IM_STATUS_START);
#else /* USE_FRAMEMGR_ALWAYS */
  extern XimFrameRec im_status_start_fr[];
  send_message(im_id, status_CB->icid,
	       im_status_start_fr, IM_STATUS_START);
#endif /* USE_FRAMEMGR_ALWAYS */
  return True;
}

int IIIMPClient::status_draw_string(IMStatusCBStruct *status_CB) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  char *data;
  char buf[256];
  char *ptr;
  int total_size;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_status_draw_string_fr[];
#endif /* USE_FRAMEMGR_ALWAYS */
  IMStatusDrawCallbackStruct *draw =
    (IMStatusDrawCallbackStruct *)&status_CB->status->todo.draw;
  IMText *text = draw->text;

  if (text->char_length == 0) {
    return True;	/* no string to commit */
  }

#if !defined(USE_FRAMEMGR_ALWAYS)
#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(im_status_draw_string_fr, NULL, need_swap);
#endif /* USE_FRAMEMGR_ALWAYS */
		    
  int text_length = text->char_length;
  UTFCHAR *utf_chars;

  if (text->encoding == UTF16_CODESET) {
    utf_chars = text->text.utf_chars;
    if (*utf_chars == 0xfffe || *utf_chars == 0xfeff) {
      utf_chars++;
      text_length -= 1;
    }
  } else {
#ifdef DEBUG
    // cerr << "need to do convertion" << endl;
#endif
    utf_chars = 0;
  }
#if !defined(USE_FRAMEMGR_ALWAYS)
  total_size = 4;		/* IIIMP header */
  total_size += (2 + 2);	/* imid + icid */
  total_size += 4;		/* type of CONTENTS */
  total_size += 2;		/* byte length of string */
  total_size += (2 * text_length);
  if (total_size & 0x02) {	/* padding */
    total_size += 2;
  }
  if ((sizeof (buf)) < total_size) {
    data = new char[total_size];
  } else {
    data = buf;
  }
  ptr = (data + 4);
  if (False == need_swap) {
    req_put16(ptr, im_id);
    req_put16(ptr, status_CB->icid);
    req_put32(ptr, 0);		/* #0 for STRING */
    for (int i = 0; i < text_length; i++) {
      req_put16(ptr, *(utf_chars + i));
    }
  } else {
    req_put16s(ptr, im_id);
    req_put16s(ptr, status_CB->icid);
    req_put32s(ptr, 0);		/* #0 for STRING */
    for (int i = 0; i < text_length; i++) {
      req_put16s(ptr, *(utf_chars + i));
    }
  }
  if (total_size & 0x02) {	/* padding */
    req_put16(ptr, 0);		/* no need to swap byte */
  }
  send_message(IM_STATUS_DRAW, data, total_size);
  if ((sizeof (buf)) < total_size) {
    delete [] data;
  }
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgrSetIterCount(fm, text_length);

  const int total_size = FrameMgrGetTotalSize(fm);
  CompoundString reply = CompoundString(total_size);
  memset(reply, 0, total_size);
  FrameMgrSetBuffer(fm, reply);

  int flag = 0;	/* #0 for STRING */
  FrameMgrPutToken(fm, im_id);
  FrameMgrPutToken(fm, status_CB->icid);
  FrameMgrPutToken(fm, flag);

  SetStringToFrame(fm, utf_chars, text_length);

  send_message(IM_STATUS_DRAW, reply, total_size);
  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */
  return True;
}
int IIIMPClient::status_draw_text(IMStatusCBStruct *status_CB) {
#if !defined(USE_FRAMEMGR_ALWAYS)
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_status_draw_text_fr[];
#endif /* USE_FRAMEMGR_ALWAYS */
  IMStatusDrawCallbackStruct *draw =
    (IMStatusDrawCallbackStruct *)&status_CB->status->todo.draw;
  IMText *text = draw->text;
  int i, j;

#if !defined(USE_FRAMEMGR_ALWAYS)
  int text_length = text->char_length;
  UTFCHAR *utf_chars;

  if (text->encoding == UTF16_CODESET) {
    utf_chars = text->text.utf_chars;
    if (*utf_chars == 0xfffe || *utf_chars == 0xfeff) {
      utf_chars++;
      text_length -= 1;
    }
  } else {
    utf_chars = 0;
  }

  /* without FrameMgr */
  int		total_length;
  int		fa_len;
  int		cwf_len;
  int		annotation_len;
  int		contents_type;
  UTFCHAR *	ut;


  total_length = 0;
  fa_len = 0;
  cwf_len = 0;
  annotation_len = 0;
  contents_type = 1;		/* contents type #1 : TEXT */

  total_length += 4;		/* request header */

  total_length += 2;		/* im_id */
  total_length += 2;		/* ic_id */

  total_length += 4;		/* contents type */
  total_length += 4;		/* byte length of list of char_with_feedback */
  cwf_len += (2 * text_length);	/* unicode code element */
  cwf_len += (2 * text_length);	/* byte length of Feedback attribute */
					/* array */
  for (i = 0; i < text_length; i++) {	/* feedback_attr */
    fa_len += (8 * (text->feedback + i)->count_feedbacks);
  }
  cwf_len += fa_len;

  total_length += cwf_len;

  total_length += 4;		/* byte length of list of annotation */
  total_length += 0;		/* annotation is not supported yet */

  char * request;
  char * p;

  request = new char[total_length];
  p = (request + 4);

  if (False == need_swap) {
    req_put16(p, im_id);
    req_put16(p, status_CB->icid);
    req_put32(p, contents_type);
    req_put32(p, cwf_len);
    for (i = 0, ut = utf_chars; i < text_length; i++, ut++) {
      int cf;
      req_put16(p, *ut);
      cf = (text->feedback + i)->count_feedbacks;
      req_put16(p, (8 * cf));
      for (j = 0; j < cf; j++) {
	req_put32(p, ((text->feedback + i)->feedbacks + j)->type);
	req_put32(p, ((text->feedback + i)->feedbacks + j)->value);
      }
    }
    req_put32(p, annotation_len);	/* annotation is not supported yet */
  } else {
    req_put16s(p, im_id);
    req_put16s(p, status_CB->icid);
    req_put32s(p, contents_type);
    req_put32s(p, cwf_len);
    for (i = 0, ut = utf_chars; i < text_length; i++, ut++) {
      int cf;
      req_put16s(p, *ut);
      cf = (text->feedback + i)->count_feedbacks;
      req_put16s(p, (8 * cf));
      for (j = 0; j < cf; j++) {
	req_put32s(p, ((text->feedback + i)->feedbacks + j)->type);
	req_put32s(p, ((text->feedback + i)->feedbacks + j)->value);
      }
    }
    req_put32s(p, annotation_len);	/* annotation is not supported yet */
  }

  send_message(IM_STATUS_DRAW, request, total_length);

  delete [] request;

  return True;

#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(im_status_draw_text_fr, NULL, need_swap);

  int text_length = text->char_length;
  UTFCHAR *utf_chars;

  if (text->encoding == UTF16_CODESET) {
    utf_chars = text->text.utf_chars;
    if (*utf_chars == 0xfffe || *utf_chars == 0xfeff) {
      utf_chars++;
      text_length -= 1;
    }
  } else {
#ifdef DEBUG
    // cerr << "need to do convertion" << endl;
#endif
    utf_chars = 0;
  }
  FrameMgrSetIterCount(fm, text_length);

  if (draw->text != NULL) {
    for (i = 0; i < text_length; i++) {
      IMFeedbackList *fbl = &(draw->text->feedback[i]);
      // set iteration count for list of feedback
      FrameMgrSetIterCount(fm, fbl->count_feedbacks);
    }
  }

  const int total_size = FrameMgrGetTotalSize(fm);
  CompoundString reply = CompoundString(total_size);
  memset(reply, 0, total_size);
  FrameMgrSetBuffer(fm, reply);
    
  FrameMgrPutToken(fm, im_id);
  FrameMgrPutToken(fm, status_CB->icid);
  int flag = 1;			/* #1 for TEXT */
  FrameMgrPutToken(fm, flag);

  CARD8 *utf_str = (CARD8*)utf_chars;

  CARD8 *strp = utf_str;
  const int one_unit = sizeof(UTFCHAR)/sizeof(char);
  for (i = 0; i < text_length, strp < &utf_str[text_length * one_unit];
       i++) {
    CARD8 first_byte, second_byte;
    if (need_swap) {
      second_byte = *strp++;
      first_byte  = *strp++;
    } else {
      first_byte  = *strp++;
      second_byte = *strp++;
    }
    FrameMgrPutToken(fm, first_byte);
    FrameMgrPutToken(fm, second_byte);

    if (text != NULL) {
	IMFeedbackList *fbl = &(text->feedback[i]);
        for (j = 0; j < fbl->count_feedbacks; j++){
	  IMFeedback *fb = &(fbl->feedbacks[j]);
	  FrameMgrPutToken(fm, fb->type);
	  FrameMgrPutToken(fm, fb->value);
	}
    }
  }
  int annotation_len = 0; /* annotation is not used */
  FrameMgrPutToken(fm, annotation_len); /* annotation_len = 0 */

  send_message(IM_STATUS_DRAW, reply, total_size);
  /* free FrameMgr */
  FrameMgrFree(fm);

  return True;
#endif /* USE_FRAMEMGR_ALWAYS */
}

int IIIMPClient::status_draw(IMStatusCBStruct *status_CB) {
  IMStatusDrawCallbackStruct *draw =
    (IMStatusDrawCallbackStruct *)&status_CB->status->todo.draw;

  if (draw->text != NULL && draw->text->char_length == 0)
    return status_draw_string(status_CB);
  else
    return status_draw_text(status_CB);

  return False;
}

int IIIMPClient::status_done(IMStatusCBStruct *status_CB) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  send_message(im_id, status_CB->icid, IM_STATUS_DONE);
#else /* USE_FRAMEMGR_ALWAYS */
  extern XimFrameRec im_status_done_fr[];
  send_message(im_id,
	       status_CB->icid,
	       im_status_done_fr, IM_STATUS_DONE);
#endif /* USE_FRAMEMGR_ALWAYS */
  return True;
}

int IIIMPClient::lookup_start(IMLookupCBStruct *lookup_CB) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  char data[4 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2];
  char *ptr;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_lookup_start_fr[];
#endif /* USE_FRAMEMGR_ALWAYS */
  LayoutInfo *layout = (LayoutInfo *)0;
  IMLookupStartCallbackStruct *start =
    (IMLookupStartCallbackStruct*)&lookup_CB->lookup->todo.start;
  if (start->whoIsMaster == IMIsMaster)
     layout = start->IMPreference;
  else if (start->whoIsMaster == CBIsMaster) 
          layout = start->CBPreference;
       else 
	  return False;

#if !defined(USE_FRAMEMGR_ALWAYS)
  ptr = (data + 4);
  if (False == need_swap) {
    req_put16(ptr, im_id);
    req_put16(ptr, lookup_CB->icid);
    req_put16(ptr, start->whoIsMaster);
    req_put16(ptr, layout->choice_per_window);
    req_put16(ptr, layout->nrows);
    req_put16(ptr, layout->ncolumns);
    req_put16(ptr, layout->drawUpDirection);
    req_put16(ptr, layout->whoOwnsLabel);
  } else {
    req_put16s(ptr, im_id);
    req_put16s(ptr, lookup_CB->icid);
    req_put16s(ptr, start->whoIsMaster);
    req_put16s(ptr, layout->choice_per_window);
    req_put16s(ptr, layout->nrows);
    req_put16s(ptr, layout->ncolumns);
    req_put16s(ptr, layout->drawUpDirection);
    req_put16s(ptr, layout->whoOwnsLabel);
  }
  send_message(IM_LOOKUP_START, data, (sizeof (data)));
#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(im_lookup_start_fr, NULL, need_swap);
		
  const int total_size = FrameMgrGetTotalSize(fm);
  CompoundString reply = CompoundString(total_size);
  memset(reply, 0, total_size);
  FrameMgrSetBuffer(fm, reply);

  FrameMgrPutToken(fm, im_id);
  FrameMgrPutToken(fm, lookup_CB->icid);
  FrameMgrPutToken(fm, start->whoIsMaster);
  FrameMgrPutToken(fm, layout->choice_per_window);
  FrameMgrPutToken(fm, layout->nrows);
  FrameMgrPutToken(fm, layout->ncolumns);
  FrameMgrPutToken(fm, layout->drawUpDirection);
  FrameMgrPutToken(fm, layout->whoOwnsLabel);

  send_message(IM_LOOKUP_START, reply, total_size);
  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */

  return True;
}

int IIIMPClient::lookup_draw(IMLookupCBStruct *lookup_CB) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  char *data;
  char *ptr;
  int total_size;
  int choice_list_size;
  int label_list_size;
  int title_size;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_lookup_draw_fr[];
#endif /* USE_FRAMEMGR_ALWAYS */
  IMLookupDrawCallbackStruct *draw =
    (IMLookupDrawCallbackStruct *)&lookup_CB->lookup->todo.draw;
  int i, j;

#if !defined(USE_FRAMEMGR_ALWAYS)
  choice_list_size = 0;
  for (i = 0; i < draw->n_choices; i++) {  /* choice list */
    choice_list_size += imtext_size((draw->choices + i)->value);
  }
  label_list_size = 0;
  if (NULL != draw->choices->label) {	/* index label list */
    for (i = 0; i < draw->n_choices; i++) {
      label_list_size += imtext_size((draw->choices + i)->label);
    }
  }
  title_size = imtext_size(draw->title);	/* title */

  total_size = 4;	/* IIIMP header */
  total_size += (2 + 2);
  total_size += 4;	/* index of first candidate */
  total_size += 4;	/* index of last candidate */
  total_size += 4;	/* index of current candidate */
  total_size += 4;	/* byte length of choice list */
  total_size += choice_list_size;	/* choice list */
  total_size += 4;	/* byte length of index label list */
  total_size += label_list_size;	/* index label list */
  total_size += title_size;		/* title */

  data = new char[total_size];
  ptr = (data + 4);

  if (False == need_swap) {
    req_put16(ptr, im_id);
    req_put16(ptr, lookup_CB->icid);
    req_put32(ptr, draw->index_of_first_candidate);
    req_put32(ptr, draw->index_of_last_candidate);
    req_put32(ptr, draw->index_of_current_candidate);
    req_put32(ptr, choice_list_size);
    for (i = 0; i < draw->n_choices; i++) {  /* choice list */
      ptr = req_put_imtext(ptr, (draw->choices + i)->value);
    }
    req_put32(ptr, label_list_size);
    for (i = 0; i < draw->n_choices; i++) {  /* choice list */
      ptr = req_put_imtext(ptr, (draw->choices + i)->label);
    }
    ptr = req_put_imtext(ptr, draw->title);
  } else {
    req_put16s(ptr, im_id);
    req_put16s(ptr, lookup_CB->icid);
    req_put32s(ptr, draw->index_of_first_candidate);
    req_put32s(ptr, draw->index_of_last_candidate);
    req_put32s(ptr, draw->index_of_current_candidate);
    req_put32s(ptr, choice_list_size);
    for (i = 0; i < draw->n_choices; i++) {  /* choice list */
      ptr = req_put_imtext_s(ptr, (draw->choices + i)->value);
    }
    req_put32s(ptr, label_list_size);
    for (i = 0; i < draw->n_choices; i++) {  /* choice list */
      ptr = req_put_imtext_s(ptr, (draw->choices + i)->label);
    }
    ptr = req_put_imtext_s(ptr, draw->title);
  }

  send_message(IM_LOOKUP_DRAW, data, total_size);

  delete [] data;

#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(im_lookup_draw_fr, NULL, need_swap);

  FrameMgrSetIterCount(fm, draw->n_choices);

  /* set iteration count for choice list */
  IMChoiceObject *choicep;
  for (choicep = draw->choices;
       choicep < &draw->choices[draw->n_choices]; choicep++) {
    FrameMgrSetIterCount(fm, choicep->value->char_length);
    for (i = 0; i < choicep->value->char_length; i++) {
      IMFeedbackList *fbl = &(choicep->value->feedback[i]);
      // set iteration count for list of feedback
      FrameMgrSetIterCount(fm, fbl->count_feedbacks);
    }
  }

  /* set iteration count for index label list */
  if (draw->choices->label == 0) {
    FrameMgrSetIterCount(fm, 0); /* no label strings */
  } else {
    FrameMgrSetIterCount(fm, draw->n_choices);
    for (choicep = draw->choices;
	 choicep < &draw->choices[draw->n_choices]; choicep++) {
      FrameMgrSetIterCount(fm, choicep->label->char_length);
      for (i = 0; i < choicep->label->char_length; i++) {
	IMFeedbackList *fbl = &(choicep->label->feedback[i]);
	// set iteration count for list of feedback
	FrameMgrSetIterCount(fm, fbl->count_feedbacks);
      }
    }
  }

  if (draw->title == 0) {
    FrameMgrSetIterCount(fm, 0); /* no title */
  } else {
    FrameMgrSetIterCount(fm, draw->title->char_length);
    /* set iteration count for title */
    for (i = 0; i < draw->title->char_length; i++) {
      IMFeedbackList *fbl = &(draw->title->feedback[i]);
      // set iteration count for list of feedback
      FrameMgrSetIterCount(fm, fbl->count_feedbacks);
    }
  }

  /* get total_size */
  const int total_size = FrameMgrGetTotalSize(fm);
  CompoundString reply = CompoundString(total_size);
  memset(reply, 0, total_size);
  FrameMgrSetBuffer(fm, reply);

  FrameMgrPutToken(fm, im_id);
  FrameMgrPutToken(fm, lookup_CB->icid);
  FrameMgrPutToken(fm, draw->index_of_first_candidate);
  FrameMgrPutToken(fm, draw->index_of_last_candidate);
  FrameMgrPutToken(fm, draw->index_of_current_candidate);

  /* choice list */
  UTFCHAR *utf_chars;
  for (choicep = draw->choices;
       choicep < &draw->choices[draw->n_choices]; choicep++) {
    if (choicep->value->encoding == UTF16_CODESET) {
      utf_chars = choicep->value->text.utf_chars;
    } else {
#ifdef DEBUG
      // cerr << "need to do convertion" << endl;
#endif
      utf_chars = 0;
    }
    CARD8 first_byte, second_byte;
    CARD8 *utf_str = (CARD8*)utf_chars;
    CARD8 *strp = utf_str;

    for (i = 0; i < choicep->value->char_length; i++) {
      if (need_swap) {
	second_byte = *strp++;
	first_byte = *strp++;
      } else {
	first_byte = *strp++;
	second_byte = *strp++;
      }
      FrameMgrPutToken(fm, first_byte);
      FrameMgrPutToken(fm, second_byte);

      if (choicep->value != NULL) {
	IMFeedbackList *fbl = &(choicep->value->feedback[i]);
	for (j = 0; j < fbl->count_feedbacks; j++){
	  IMFeedback *fb = &(fbl->feedbacks[j]);
	  FrameMgrPutToken(fm, fb->type);
	  FrameMgrPutToken(fm, fb->value);
	}
      }
    }
    int annotation_len = 0;
    FrameMgrPutToken(fm, annotation_len); /* annotation_len = 0 */
  }

  /* index label list */
  if (draw->choices->label != 0) {
    for (choicep = draw->choices;
	 choicep < &draw->choices[draw->n_choices]; choicep++) {
      if (choicep->label->encoding == UTF16_CODESET) {
	utf_chars = choicep->label->text.utf_chars;
      } else {
#ifdef DEBUG
	// cerr << "need to do convertion" << endl;
#endif
	utf_chars = 0;
      }
      CARD8 first_byte, second_byte;
      CARD8 *utf_str = (CARD8*)utf_chars;
      CARD8 *strp = utf_str;
      for (i = 0; i < choicep->label->char_length; i++) {
	if (need_swap) {
	  second_byte = *strp++;
	  first_byte =  *strp++;
	} else {
	  first_byte = *strp++;
	  second_byte = *strp++;
	}
	FrameMgrPutToken(fm, first_byte);
	FrameMgrPutToken(fm, second_byte);

	if (choicep->label != NULL) {
	  IMFeedbackList *fbl = &(choicep->label->feedback[i]);
	  for (j = 0; j < fbl->count_feedbacks; j++){
	    IMFeedback *fb = &(fbl->feedbacks[j]);
	    FrameMgrPutToken(fm, fb->type);
	    FrameMgrPutToken(fm, fb->value);
	  }
	}
      }
      int annotation_len = 0;
      FrameMgrPutToken(fm, annotation_len); /* annotation_len = 0 */
    }
  }

  /* title */
  if (draw->title != 0) {
    if (draw->title->encoding == UTF16_CODESET) {
      utf_chars = draw->title->text.utf_chars;
    } else {
#ifdef DEBUG
      // cerr << "need to do convertion" << endl;
#endif
      utf_chars = 0;
    }
    CARD8 first_byte, second_byte;
    CARD8 *utf_str = (CARD8*)utf_chars;
    CARD8 *strp = utf_str;
    for (i = 0; i < draw->title->char_length; i++) {
      if (need_swap) {
	second_byte = *strp++;
	first_byte = *strp++;
      } else {
	first_byte = *strp++;
	second_byte = *strp++;
      }
      FrameMgrPutToken(fm, first_byte);
      FrameMgrPutToken(fm, second_byte);
      if (draw->title != NULL) {
	IMFeedbackList *fbl = &(draw->title->feedback[i]);
	for (j = 0; j < fbl->count_feedbacks; j++){
	  IMFeedback *fb = &(fbl->feedbacks[j]);
	  FrameMgrPutToken(fm, fb->type);
	  FrameMgrPutToken(fm, fb->value);
	}
      }
    }
    int annotation_len = 0;
    FrameMgrPutToken(fm, annotation_len); /* annotation_len = 0 */
  }
  send_message(IM_LOOKUP_DRAW, reply, total_size);
  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */

  return True;
}

int IIIMPClient::lookup_process(IMLookupCBStruct *lookup_CB) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  char data[4 + 2 + 2 + 2 + 2];
  char *ptr;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_lookup_process_fr[];
#endif /* USE_FRAMEMGR_ALWAYS */
  IMLookupProcessCallbackStruct *process =
    (IMLookupProcessCallbackStruct *)&lookup_CB->lookup->todo.process;

#if !defined(USE_FRAMEMGR_ALWAYS)
  ptr = (data + 4);
  if (False == need_swap) {
    req_put16(ptr, im_id);
    req_put16(ptr, lookup_CB->icid);
    req_put16(ptr, process->type);
    if (LookupIndex == process->type) {
      req_put16(ptr, process->value.index_of_choice_selected);
    } else {
      req_put16(ptr, process->value.page_operation_id);
    }
  } else {
    req_put16s(ptr, im_id);
    req_put16s(ptr, lookup_CB->icid);
    req_put16s(ptr, process->type);
    if (LookupIndex == process->type) {
      req_put16s(ptr, process->value.index_of_choice_selected);
    } else {
      req_put16s(ptr, process->value.page_operation_id);
    }
  }
  send_message(IM_LOOKUP_PROCESS, data, (sizeof (data)));
#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(im_lookup_process_fr, NULL, need_swap);

  const int total_size = FrameMgrGetTotalSize(fm);
  CompoundString reply = CompoundString(total_size);
  memset(reply, 0, total_size);
  FrameMgrSetBuffer(fm, reply);

  FrameMgrPutToken(fm, im_id);
  FrameMgrPutToken(fm, lookup_CB->icid);
  FrameMgrPutToken(fm, process->type);
  if (process->type == LookupIndex)
    FrameMgrPutToken(fm, process->value.index_of_choice_selected);
  else
    FrameMgrPutToken(fm, process->value.page_operation_id);
  send_message(IM_LOOKUP_PROCESS, reply, total_size);

  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */

  return True;
}

int IIIMPClient::lookup_done(IMLookupCBStruct *lookup_CB) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  send_message(im_id, lookup_CB->icid, IM_LOOKUP_DONE);
#else /* USE_FRAMEMGR_ALWAYS */
  extern XimFrameRec im_lookup_done_fr[];
  send_message(im_id, lookup_CB->icid,
	       im_lookup_done_fr, IM_LOOKUP_DONE);
#endif /* USE_FRAMEMGR_ALWAYS */
  return True;
}

int IIIMPClient::preedit_state(IMConvStateCBStruct *state_CB) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  char data[4 + 2 + 2 + 2 + 2];
  char *ptr;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_trigger_notify_fr[];
#endif /* USE_FRAMEMGR_ALWAYS */

#if !defined(USE_FRAMEMGR_ALWAYS)
  ptr = (data + 4);
  if (False == need_swap) {
    req_put16(ptr, im_id);
    req_put16(ptr, state_CB->icid);
    req_put16(ptr, state_CB->conv_state);
    req_put16(ptr, 0);
  } else {
    req_put16s(ptr, im_id);
    req_put16s(ptr, state_CB->icid);
    req_put16s(ptr, state_CB->conv_state);
    req_put16s(ptr, 0);
  }
  send_message(IM_TRIGGER_NOTIFY, data, (sizeof (data)));
#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(im_trigger_notify_fr, (char *)NULL, need_swap);

  const int total_size = FrameMgrGetTotalSize(fm);
  CompoundString reply = CompoundString(total_size);
  memset(reply, 0, total_size);
  FrameMgrSetBuffer(fm, reply);

  FrameMgrPutToken(fm, im_id);
  FrameMgrPutToken(fm, state_CB->icid);
  FrameMgrPutToken(fm, state_CB->conv_state);  // #0::ON #1::OFF

  send_message(IM_TRIGGER_NOTIFY, reply, total_size);
  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */
  return True;
}

int IIIMPClient::auxiliary_start(IMAuxCBStruct *auxiliary_CB) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  char *data;
  char *ptr;
  int total_size;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_aux_start_fr[];
#endif /* USE_FRAMEMGR_ALWAYS */
  IMAuxStartCallbackStruct *call_data =
    (IMAuxStartCallbackStruct*)&auxiliary_CB->aux->todo.start;
  char *enginename = call_data->aux_name;
  int i;

  if (!enginename) return True;	// nothing to do

#if !defined(USE_FRAMEMGR_ALWAYS)
  total_size = 4;
  total_size += (2 + 2);
  total_size += 4;
  total_size += ascii_string_size(enginename);
  data = new char[total_size];
  ptr = (data + 4);
  if (False == need_swap) {
    req_put16(ptr, im_id);
    req_put16(ptr, auxiliary_CB->icid);
    req_put32(ptr, call_data->aux_index);
    ptr = req_put_ascii_string(ptr, enginename);
  } else {
    req_put16s(ptr, im_id);
    req_put16s(ptr, auxiliary_CB->icid);
    req_put32s(ptr, call_data->aux_index);
    ptr = req_put_ascii_string_s(ptr, enginename);
  }
  send_message(IM_AUX_START, data, total_size);
  delete [] data;
#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(im_aux_start_fr, (char*)NULL, need_swap);

  /* set iteration count of engine name */
  int byte_length = strlen(enginename);
  FrameMgrSetIterCount(fm, byte_length);

  const int total_size = FrameMgrGetTotalSize(fm);
  CompoundString reply = CompoundString(total_size);
  memset(reply, 0, total_size);
  FrameMgrSetBuffer(fm, reply);

  FrameMgrPutToken(fm, im_id);
  FrameMgrPutToken(fm, auxiliary_CB->icid); 
  FrameMgrPutToken(fm, call_data->aux_index);

  if (need_swap == True) {
    for (i = 0; i < byte_length; i++) {
      CARD16 c = (CARD16)enginename[i];
      CARD8 byte_data;
      byte_data = *((CARD8 *)(&c) + 1);
      FrameMgrPutToken(fm, byte_data);
      byte_data = *((CARD8 *)(&c) + 0);
      FrameMgrPutToken(fm, byte_data);
    }
  } else {
    for (i = 0; i < byte_length; i++) {
      CARD16 c = (CARD16)enginename[i];
      CARD8 byte_data;
      byte_data = *((CARD8 *)(&c) + 0);
      FrameMgrPutToken(fm, byte_data);
      byte_data = *((CARD8 *)(&c) + 1);
      FrameMgrPutToken(fm, byte_data);
    }
  }

  send_message(IM_AUX_START, reply, total_size);

  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */
  return True;
}

int IIIMPClient::auxiliary_draw(IMAuxCBStruct *auxiliary_CB) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  char *data;
  char *ptr;
  int total_size;
  int string_list_size;
  IMText *string_values;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_aux_draw_fr[];
#endif /* USE_FRAMEMGR_ALWAYS */
  IMAuxDrawCallbackStruct *call_data =
    (IMAuxDrawCallbackStruct*)&auxiliary_CB->aux->todo.draw;
  char *enginename = call_data->aux_name;
  int i;

  if (!enginename) return True;	// nothing to do

#if !defined(USE_FRAMEMGR_ALWAYS)
  total_size = 4;
  total_size += (2 + 2);
  total_size += 4;
  total_size += ascii_string_size(enginename);
  total_size += 4;	/* byte length of integer value list */
  total_size += (4 * call_data->count_integer_values);
			/* integer value list */
  total_size += 4;	/* byte length of string value list */
  string_list_size = 0;
  for (i = 0; i < call_data->count_string_values; i++) {
    string_list_size +=
	    utf16_string_size(call_data->string_values[i].char_length);
  }
  total_size += string_list_size;
  data = new char[total_size];
  ptr = (data + 4);
  string_values = call_data->string_values;

  if (False == need_swap) {
    req_put16(ptr, im_id);
    req_put16(ptr, auxiliary_CB->icid);
    req_put32(ptr, call_data->aux_index);
    ptr = req_put_ascii_string(ptr, enginename);
    req_put32(ptr, (4 * call_data->count_integer_values));
    for (i = 0; i < call_data->count_integer_values; i++) {
      req_put32(ptr, *(call_data->integer_values + i));
    }
    req_put32(ptr, string_list_size);
    for (i = 0; i < call_data->count_string_values; i++, string_values++) {
      ptr = req_put_utf16_string(ptr,
				 string_values->text.utf_chars,
				 string_values->char_length);
    }
  } else {
    req_put16s(ptr, im_id);
    req_put16s(ptr, auxiliary_CB->icid);
    req_put32s(ptr, call_data->aux_index);
    ptr = req_put_ascii_string_s(ptr, enginename);
    req_put32s(ptr, (4 * call_data->count_integer_values));
    for (i = 0; i < call_data->count_integer_values; i++) {
      req_put32s(ptr, *(call_data->integer_values + i));
    }
    req_put32s(ptr, string_list_size);
    for (i = 0; i < call_data->count_string_values; i++, string_values++) {
      ptr = req_put_utf16_string_s(ptr,
				   string_values->text.utf_chars, 
				   string_values->char_length);
    }
  }

  send_message(IM_AUX_DRAW, data, total_size);
  delete [] data;
  return True;

#else /* USE_FRAMEMGR_ALWAYS */
  /* without FrameMgr */
  int total_length;
  int string_length;
  int enginename_length;
  IMText *	string_values;
  char *	uc;
  int		j;

  total_length = 2 + 2; /* im_id + ic_id */
  total_length += 4; /* aux_index */
  total_length += 2; /* length of engine name */
  enginename_length = strlen(enginename);
  total_length += (enginename_length * 2);
  if (0 == (enginename_length % 2)) {
    total_length += 2; /* padding */
  }
  total_length += 4; /* byte length of integer value list */
  total_length += (4 * call_data->count_integer_values);
					/* integer value list */
  total_length += 4; /* byte length of string value list */
  string_length = 0;
  for (i = 0; i < call_data->count_string_values; i++) {
    /* string value */
    string_length += (call_data->string_values[i].char_length * 2) + 2;
    if (0 == (call_data->string_values[i].char_length % 2)) {
      string_length += 2; /* padding */
    }
  }
  total_length += string_length;

  CompoundString request = CompoundString(total_length, 0);
  unsigned char * p;

  p = request.toUchar();

  if (False == need_swap) {
    *((CARD16 *)(p + 0)) = im_id;
    *((CARD16 *)(p + 2)) = auxiliary_CB->icid;
    *((CARD32 *)(p + 4)) = call_data->aux_index;
    *((CARD16 *)(p + 8)) = (enginename_length * 2);

    p += 10;

    for (i = 0; i < enginename_length; i++) {
      CARD16 c;
      c = (CARD16)(*(enginename + i));
      *((CARD16 *)p) = c;
      p += 2;
    }
    if (0 == (enginename_length % 2)) {
      *((CARD16 *)p) = 0;
      p += 2;
    }

    *((CARD32 *)p) = (4 * call_data->count_integer_values);
    p += 4;
    for (i = 0; i < call_data->count_integer_values; i++) {
      *((CARD32 *)p) = *(call_data->integer_values + i);
      p += 4;
    }

    *((CARD32 *)p) = string_length;
    p += 4;

    string_values = call_data->string_values;
    for (i = 0; i < call_data->count_string_values; i++) {
      uc = (char *)((string_values + i)->text.utf_chars);
      *((CARD16 *)p) = ((string_values + i)->char_length * 2);
      p += 2;
      for (j = 0; j < (string_values + i)->char_length; j++) {
	*(p++) = *(uc++);
	*(p++) = *(uc++);
      }
      if (0 == ((string_values + i)->char_length % 2)) {
	*(p++) = 0;
	*(p++) = 0;
      }
    }
  } else {
    *((CARD16 *)(p + 0)) = req_swap16(im_id);
    *((CARD16 *)(p + 2)) = req_swap16(auxiliary_CB->icid);
    *((CARD32 *)(p + 4)) = req_swap32(call_data->aux_index);
    *((CARD16 *)(p + 8)) = req_swap16(enginename_length * 2);

    p += 10;

    for (i = 0; i < enginename_length; i++) {
      CARD16 c;
      c = (CARD16)(*(enginename + i));
      *((CARD16 *)p) = req_swap16(c);
      p += 2;
    }
    if (0 == (enginename_length % 2)) {
      *((CARD16 *)p) = 0;
      p += 2;
    }

    *((CARD32 *)p) = req_swap32(4 * call_data->count_integer_values);
    p += 4;
    for (i = 0; i < call_data->count_integer_values; i++) {
      *((CARD32 *)p) = req_swap32(*(call_data->integer_values + i));
      p += 4;
    }

    *((CARD32 *)p) = req_swap32(string_length);
    p += 4;

    string_values = call_data->string_values;
    for (i = 0; i < call_data->count_string_values; i++) {
      uc = (char *)((string_values + i)->text.utf_chars);
      *((CARD16 *)p) = req_swap16((string_values + i)->char_length * 2);
      p += 2;
      for (j = 0; j < (string_values + i)->char_length; j++) {
	*(p++) = *(uc + 1);
	*(p++) = *(uc + 0);
	uc += 2;
      }
      if (0 == ((string_values + i)->char_length % 2)) {
	*(p++) = 0;
	*(p++) = 0;
      }
    }
  }

  send_message(IM_AUX_DRAW, request, total_length);
  return True;

#if 0
  /* create FrameMgr */
  fm = FrameMgrInit(im_aux_draw_fr, (char*)NULL, need_swap);

  /* set iteration count of engine name */
  int byte_length = strlen(enginename);
  FrameMgrSetIterCount(fm, byte_length);

  /* set iteration count of integer list */
  FrameMgrSetIterCount(fm, call_data->count_integer_values);

  /* set iteration count of string list */
  FrameMgrSetIterCount(fm, call_data->count_string_values);

  for (i = 0; i < call_data->count_string_values; i++) {
    FrameMgrSetIterCount(fm, call_data->string_values[i].char_length);
  }

  const int total_size = FrameMgrGetTotalSize(fm);
  CompoundString reply = CompoundString(total_size);
  memset(reply, 0, total_size);
  FrameMgrSetBuffer(fm, reply);

  FrameMgrPutToken(fm, im_id);
  FrameMgrPutToken(fm, auxiliary_CB->icid); 
  FrameMgrPutToken(fm, call_data->aux_index);

  if (need_swap == True) {
    for (i = 0; i < byte_length; i++) {
      CARD16 c = (CARD16)enginename[i];
      CARD8 byte_data;
      byte_data = *((CARD8 *)(&c) + 1);
      FrameMgrPutToken(fm, byte_data);
      byte_data = *((CARD8 *)(&c) + 0);
      FrameMgrPutToken(fm, byte_data);
    }
  } else {
    for (i = 0; i < byte_length; i++) {
      CARD16 c = (CARD16)enginename[i];
      CARD8 byte_data;
      byte_data = *((CARD8 *)(&c) + 0);
      FrameMgrPutToken(fm, byte_data);
      byte_data = *((CARD8 *)(&c) + 1);
      FrameMgrPutToken(fm, byte_data);
    }
  }

  for (i = 0; i < call_data->count_integer_values; i++) {
    FrameMgrPutToken(fm, call_data->integer_values[i]);
  }

  UTFCHAR *utf_chars;
  int text_length;
  for (i = 0; i < call_data->count_string_values; i++) {
    text_length = call_data->string_values[i].char_length;

    if (call_data->string_values[i].encoding == UTF16_CODESET) {
      utf_chars = call_data->string_values[i].text.utf_chars;
    } else {
      utf_chars = 0;
    }
    SetStringToFrame(fm, utf_chars, text_length);
  }
  send_message(IM_AUX_DRAW, reply, total_size);

  /* free FrameMgr */
  FrameMgrFree(fm);
  return True;
#endif
#endif /* USE_FRAMEMGR_ALWAYS */
}

int IIIMPClient::auxiliary_done(IMAuxCBStruct *auxiliary_CB) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  char *data;
  char *ptr;
  int total_size;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_aux_done_fr[];
#endif /* USE_FRAMEMGR_ALWAYS */
  IMAuxDoneCallbackStruct *call_data =
    (IMAuxDoneCallbackStruct*)&auxiliary_CB->aux->todo.done;
  char *enginename = call_data->aux_name;
  int i;

  if (!enginename) return True;	// nothing to do

#if !defined(USE_FRAMEMGR_ALWAYS)
  total_size = 4;
  total_size += (2 + 2);
  total_size += 4;
  total_size += ascii_string_size(enginename);
  data = new char[total_size];
  ptr = (data + 4);
  if (False == need_swap) {
    req_put16(ptr, im_id);
    req_put16(ptr, auxiliary_CB->icid);
    req_put32(ptr, call_data->aux_index);
    ptr = req_put_ascii_string(ptr, enginename);
  } else {
    req_put16s(ptr, im_id);
    req_put16s(ptr, auxiliary_CB->icid);
    req_put32s(ptr, call_data->aux_index);
    ptr = req_put_ascii_string_s(ptr, enginename);
  }
  send_message(IM_AUX_DONE, data, total_size);
  delete [] data;
#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(im_aux_done_fr, (char*)NULL, need_swap);

  /* set iteration count of engine name */
  int byte_length = strlen(enginename);
  FrameMgrSetIterCount(fm, byte_length);

  const int total_size = FrameMgrGetTotalSize(fm);
  CompoundString reply = CompoundString(total_size);
  memset(reply, 0, total_size);
  FrameMgrSetBuffer(fm, reply);

  FrameMgrPutToken(fm, im_id);
  FrameMgrPutToken(fm, auxiliary_CB->icid); 
  FrameMgrPutToken(fm, call_data->aux_index);

  if (need_swap == True) {
    for (i = 0; i < byte_length; i++) {
      CARD16 c = (CARD16)enginename[i];
      CARD8 byte_data;
      byte_data = *((CARD8 *)(&c) + 1);
      FrameMgrPutToken(fm, byte_data);
      byte_data = *((CARD8 *)(&c) + 0);
      FrameMgrPutToken(fm, byte_data);
    }
  } else {
    for (i = 0; i < byte_length; i++) {
      CARD16 c = (CARD16)enginename[i];
      CARD8 byte_data;
      byte_data = *((CARD8 *)(&c) + 0);
      FrameMgrPutToken(fm, byte_data);
      byte_data = *((CARD8 *)(&c) + 1);
      FrameMgrPutToken(fm, byte_data);
    }
  }

  send_message(IM_AUX_DONE, reply, total_size);

  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */
  return True;
}

int IIIMPClient::conversion_start(IMConvStateCBStruct *state_CB) {
  return preedit_state(state_CB);
  return 0;
}

int IIIMPClient::conversion_end(IMConvStateCBStruct *state_CB) {
  return preedit_state(state_CB);
  return 0;
}
