// -*- C++ -*-
#ifndef _xim_h_included_
#define _xim_h_included_

#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include "jmode.h"
#include "ximpn.h"

extern Display *gDpy;
extern Window gWnd;
extern int dpy_error_count;

//このヘッダには
// XIMの通信、IM,ICの定義が書かれている

typedef unsigned char C8;
typedef unsigned short C16;
typedef unsigned int C32;

//ホストオーダへ変換する。
C16 readC16(unsigned char *val,int byte_order);
C32 readC32(unsigned char *val,int byte_order);

class TxPacket {
public:
    virtual ~TxPacket(){};

    virtual int get_length()=0;
    virtual int write_to_buf(unsigned char *buf,int buflen,int byte_order)=0;

    virtual void dump(int byte_order)=0;
    virtual int get_major()=0;

    virtual int pushC8(unsigned int)=0;
    virtual int pushC16(unsigned int )=0;
    virtual int pushC32(unsigned int )=0;
    virtual int pushSTRING(char *)=0;
    virtual int pushBytes(char *,int)=0;

    virtual int pop_back()=0;
};

class RxPacket {
public:

    virtual void rewind()=0;
    virtual C8 getC8()=0;
    virtual C16 getC16()=0;
    virtual C32 getC32()=0;
    // this Str means STRING in xim.PS
    virtual int getStrLen()=0;
    virtual void getStr(char *buf)=0;
    // STR
    virtual int getStr8Len()=0;
    virtual void getStr8(char *buf)=0;

    virtual int getMajor()=0;

    virtual bool isOverRun()=0;
    virtual void dump()=0;
    static int getPacketLength(unsigned char *, int byte_order);
};

TxPacket *createTxPacket(int major,int minor);
RxPacket *createRxPacket(unsigned char *buf,int byte_order);

class XimIC;
class Connection {
public:
    Connection();
    virtual ~Connection();
    void OnRecv();
    void OnSend();
    void OnClose();
    virtual void OnPushPacket(){};//パケットを送出キューに入れた時に呼ばれる。
    void push_packet(TxPacket *);//返事として即送るパケット
    void push_passive_packet(TxPacket *);//送る機会があれば送られるパケット
    int byte_order(){return mByteorder;};
    void push_error_packet(int imid,int icid,int er,char *str);

    unsigned short to_hs(unsigned short s);
    unsigned int to_hl(unsigned int l);
    void terminate();
protected:
    std::list<RxPacket *>mRxQ;
    std::list<TxPacket *>mTxQ;
    std::list<TxPacket *>mPTxQ;
    int mByteorder;
    bool mIsCloseWait;//最後のパケットをプッシュしてからtrueにする。
private:

    void xim_connect(RxPacket *);
    void xim_disconnect(RxPacket *);
    void xim_open(RxPacket *);
    void xim_query_extension(RxPacket *);
    void xim_encoding_negotiation(RxPacket *);
    void xim_close(RxPacket *);
    void xim_get_im_values(RxPacket *);
    void xim_set_ic_values(RxPacket *);
    void xim_get_ic_values(RxPacket *);

    void xim_create_ic(RxPacket *);
    void xim_destroy_ic(RxPacket *);

    void xim_set_ic_focus(RxPacket *);
    void xim_unset_ic_focus(RxPacket *);
    void xim_reset_ic(RxPacket *);

    void xim_forward_event(RxPacket *);
    void xim_error(RxPacket *);
private:
    XimIC *get_ic(RxPacket *);
    std::list < int > mCreatedIm;
};

//IMの定義
class XimIC;
class XimIM {
public:
    XimIM(Connection *,int id);
    virtual ~XimIM(){};
    
    virtual void create_ic(RxPacket *)=0;
    virtual void destroy_ic(int )=0;
    virtual void set_ic_focus(int icid)=0;
    virtual void set_ic_values(RxPacket *,int icid)=0;
    virtual void get_ic_values(RxPacket *)=0;
    virtual void unset_ic_focus(int icid)=0;
    virtual void forward_event(RxPacket *)=0;
    virtual XimIC *get_ic_by_id(int icid)=0;
    virtual void onSendPacket()=0;

protected:
    Connection *mConn;
    int mID;
};

int unused_im_id();
XimIM *create_im(Connection *,int id);
XimIM *get_im_by_id(int id);
void close_im(int id);


struct keyEventX {
    KeySym key_sym; //Xの方、
    int state;
    bool press;
    int serial;
    XEvent ev;
};

class KKContext;
class Convdisp;

// 実体がXimICの中に置かれる
class icxatr {
public:
    icxatr();
    ~icxatr();
    void set_atr(int id, C8 *v, int len, int byte_order);
    bool has_atr(int id);
    bool is_changed(int id);
    void unset_change_mask(int id);
    void print();
    int getSize(int id);

    unsigned long input_style;
    Window client_window;
    Window focus_window;

    C32 foreground_pixel;//本当はPixel型
    C32 background_pixel;

    XPoint spot_location;
    XRectangle area;

    char *font_set_name;
    XFontSet font_set;
    C16 line_space;

private:
    int atr_mask;
    int change_mask;
};

//ICの定義
class XimIC {
public:
    XimIC(Connection *, int imid, int icid);
    virtual ~XimIC();
    void set_focus();
    void unset_focus();
    int get_icid();
    int get_imid();

    void OnKeyEvent(keyEventX );
    void changeMode(int );
    void set_ic_attrs(void *,int );
    int get_ic_atr(int ,TxPacket *);
    void commit_jstring(jstring_t *t);
    void extra_input(jstring_t *t);
    void reset_ic();
    Convdisp *get_convdisp();
    void onSendPacket();
    bool isActive();
public:
    static XimIC *get_current_ic();
    static bool isAnyActive();
  
private:
    // XimICの生成時、破棄時にそれぞれ生成、破棄される。
    KKContext *m_kkContext;
    icxatr m_xatr;
    void send_key_event(XKeyEvent *k);
    int lookup_style(unsigned long);
    void set_ic_attr(int,C8 *,int );
    
    Connection *m_conn;
    // icxatrが十分にそろうまで0で、m_kkContextにも参照されるので
    // destructor中でm_kkContextより後で破棄する。
    Convdisp *mConvdisp;
    int mICid;
    int mIMid;
    jstring_t mPending;
    bool mIsActive;
private:
    static XimIC *current_ic;
    static int nrActiveIC;
};

struct input_style {
    int x_style;
    int style;
};

XimIC *create_ic(Connection *,RxPacket *,int imid,int id);
void force_event(Window w);

void procXClientMessage(XClientMessageEvent *m);

#endif
/*
 * Local variables:
 *  c-indent-level: 4
 *  c-basic-offset: 4
 * End:
 */
