//
// Copyright (C) 1999-2003 Toshikaz Hirabayashi
//
// 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
// TOSHIKAZ HIRABAYASHI 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.
//
// Except as contained in this notice, the name of Toshikaz Hirabayashi shall
// not be used in advertising or otherwise to promote the sale, use or other
// dealings in this Software without prior written authorization from
// Toshikaz Hirabayashi.

#include <basic.h>
#include <btron/hmi.h>
#include <btron/tip.h>
#include <btron/WSDbtronKeyboard.h>
#include <btron/WSDbtronAppDev.h>
#include <btron/WSDbtronFormDev.h>
#include <WSCdevice.h>
#include <WSDcolor.h>
#include <WSDmouse.h>
#include <WSCbase.h>
#include <WSCcolorSet.h>
#include <WSCfontSet.h>
#include <WSClocaleSet.h>

WSMFclassInit(WSDbtronKeyboard,WSDkeyboard);

WSDbtronKeyboard* WSGIbtronKeyboard(){
  WSDkeyboard* keybd = WSGIappKeyboard();
  if (keybd == NULL){
    return NULL;
  }
  WSDbtronKeyboard* btronKeybd =(WSDbtronKeyboard*)keybd->cast("WSDbtronKeyboard");
  return btronKeybd;
}

WSDkeyboard* _btronKeyboard_create_handler(){
  WSDkeyboard* keybd =  new WSDbtronKeyboard();
  keybd->initialize();
  return keybd;
}
#if 0 //move to WSGFdeviceInitialize..
class _btronKeyboard_init{
  public: _btronKeyboard_init(){
    WSDkeyboard::setCreateInstanceHandler(_btronKeyboard_create_handler);
  };
};
_btronKeyboard_init _btronKeyboard_init_execute;
#endif

TIPREC tip;
WSCbool _tip_initialized = False;
W tipid;

WSDbtronKeyboard::WSDbtronKeyboard(){
  _dev = NULL;
  _focused = False;
  _wait_for_receive_data = False;
  if (_tip_initialized == False){
    _tip_initialized = True;
    tipid = iopn_tip(&tip,TIP_AUTO);    
  }
}

WSDbtronKeyboard::~WSDbtronKeyboard(){}


long xim_lang = WS_EN_NONE;
long WSDbtronKeyboard::initialize(){
  if (getenv("WS_XIM_LANG")){
extern long WSGFgetLocaleValue(char*);
    xim_lang = WSGFgetLocaleValue(getenv("WS_XIM_LANG"));
  }
  //ISO8859..
  if (WSGIappCodeConvert()->getSystemLocale() > WS_EN_NONE &&
      WSGIappCodeConvert()->getSystemLocale() < WS_EN_UTF8){
    return WS_NO_ERR;
  }
  return WS_NO_ERR;
}

long WSDbtronKeyboard::startKanji(WSDdev* dev,short x,short y,short fontno,short fgno,short bgno){
  _dev = dev;
  _x = x;  
  _y = y;  
  _fno = fontno;
  _fg = fgno;
  _bg = bgno;
  _fep_on = True;

  return WS_NO_ERR;
}
long WSDbtronKeyboard::startAscii(WSDdev* dev,short ,short ,short ,short ,short ){
  _fep_on = False;
  return WS_NO_ERR;
}

long WSDbtronKeyboard::resetFep(WSDdev* dev){
  return WS_NO_ERR;
}

long WSDbtronKeyboard::setFepPos(WSDdev* dev,short x,short y,short fontno,short fgno,short bgno){
  _dev = dev;
  _x = x;
  _y = y;
  _fno = fontno;
  _fg = fgno;
  _bg = bgno;

  return WS_NO_ERR;
}

void WSDbtronKeyboard::setModeWindowPos(short x,short y,WSDdev* dev){
  WSCushort h = 0;
  WSCbase* client = dev->getAttachedClient();
  if (client != NULL){
    if (client->existProperty(WSNheight) != False){
       client->getPropertyV(WSNheight,&h);
    }
  }
  short dx = x;
  short dy = y + h + 10;
  if ((long)(y + h + 40) > (long)WSGIappDev()->getHeight()){
    dy = y - 50;
  }
  setPositionModeWindow(dx,dy);
}


#if 0
void WSDbtronKeyboard::setEnableFep(WSDdev* dev,WSCbool fl){
  WSDkeyboard::setEnableFep(dev,fl);
  return;
}
#endif

extern TC begin_ascii[];
extern char* WSGFbtronTcToString(TC* src);
W _fep_popup = 0;
WSCbool WSDbtronKeyboard::deliverKeyEvent(WEVENT* ev,WSCbool fl){
  WSCbool press = fl;
  setIsPressed(press);

  long key = ev->s.wid;
  setKey(key);

  W ret = 0;
  if (ev->s.type == EV_KEYDWN && fl == True){
    ret = iput_key(tipid,(EVENT*)ev);
  }else
  if (ev->s.type == EV_AUTKEY && fl == True){
    ret = iput_key(tipid,(EVENT*)ev);
  }
dbprintf("iput_key ret=0x%x n_cl=%x cl_in[n_cl]=%d\n",ret,tip.n_cl,tip.cl_in[tip.n_cl]);
  if (ret < 0 && tip.n_cl != 0){
    return True;
  }
  if (ret < 0){
    ret = TIP_OUT;
  }

  short ox,oy;
  WSCushort ow,oh;
  WSDbtronFormDev::getGlobalRegion(&ox,&oy,&ow,&oh);
  if (ret > 0){
    if ((ret & TIP_PUPREQ) && ((ret & TIP_PUPOPN) == 0)){
      WSDfont* fn = WSGIappFontSet()->getFont(_fno);
      long fh = 14;
      if (fn == NULL){
        fh = fn->getFontHeight();
      }
      if (_dev != NULL){
        WSDbtronFormDev* fdev = (WSDbtronFormDev*)_dev->cast("WSDbtronFormDev");
        if (fdev != NULL){
          short dx,dy;
          fdev->getAbstPos(&dx,&dy);
          RECT r;
          r.c.left = dx + _x;
          r.c.top = dy + _y;
          r.c.right = dx + _x + 10;
          r.c.bottom = dy + _y + fh;
          _fep_popup = ipup_sel(tipid,fdev->getParentWindow(),&r);
        }else{
          WSDdev* pdev = _dev->getParentDev();
          if (pdev != NULL){
            WSDbtronFormDev* fdev = (WSDbtronFormDev*)pdev->cast("WSDbtronFormDev");
            if (fdev != NULL){
              short dx,dy;
              fdev->getAbstPos(&dx,&dy);
              RECT r;
              r.c.left = dx + _x;
              r.c.top = dy + _y;
              r.c.right = dx + _x + 10;
              r.c.bottom = dy + _y + fh;
              _fep_popup = ipup_sel(tipid,fdev->getParentWindow(),&r);
            }
          }
        }
      }
//printf("popup _fep_popup=0x%x\n",_fep_popup);
    }else if (ret & TIP_PUPOPN){
//printf("keep _fep_popup=0x%x\n",_fep_popup);
    }else{
//printf("down _fep_popup=0\n");
      _fep_popup = 0;
    }
    if (ret != 0){
      WSDbtronFormDev::setGlobalRegion(0,0,0,0);
    }
dbprintf("WSDbtronKeyboard::deliverKey key=0x%x pressed=%d n_out=%d\n",key,fl,tip.n_out);
    if ((ret & TIP_OUT) == 0){
      if (_dev != NULL){
        WSDfont* fn = WSGIappFontSet()->getFont(_fno);
dbprintf("draw string!!! caret=%d x,y=%d,%d _fg=%d _bg=%d\n",tip.caret,_x,_y,_fg,_bg);
        WSDbtronFormDev* fdev = (WSDbtronFormDev*)_dev->cast("WSDbtronFormDev");
        short ax = 0;
        short ay = 0;
        if (fdev == NULL){
          WSDdev* pdev = _dev->getParentDev();
          if (pdev != NULL){
            fdev = (WSDbtronFormDev*)pdev->cast("WSDbtronFormDev");
          }
          if (fdev != NULL){
            fdev->getAbstPos(&ax,&ay);
            short dx,dy;
            WSCushort dw,dh;
            _dev->getGeom(&dx,&dy,&dw,&dh);
            ax += dx;
            ay += dy;
          }
        }else{
          fdev->getAbstPos(&ax,&ay);
        }
        if (fdev != NULL){
          short scur1 = 0;
          short scur2 = 0;
          long tlen = tip.cl_cnv[tip.n_cl];
          if (tip.n_cl > 1){
            scur2 = tip.caret;
            long i;
            for(i=0; i<tip.n_cl+1; i++){
              if (tip.caret == tip.cl_cnv[i]){
                if (i>0){
                  scur1 = tip.cl_cnv[i-1];
                  scur2 = tip.cl_cnv[i];
                  break;
                }
              }
            }
          }

          WSDcolor* fgc = WSGIappColorSet()->getColor(_fg);
          WSDcolor* bgc = WSGIappColorSet()->getColor(_bg);
          W fgv = 0x10000000;
          W bgv = 0x10ffffff;
          if (fgc != NULL){
            fgv = fgc->getValue1();
          }
          if (bgc != NULL){
            bgv = bgc->getValue1();
          }
//printf("draw string!!! fgcol=0x%x bgcol=0x%x\n",fgv,bgv);
extern short WSGFbtronGetStringWidth(TC*,WSDfont*,long);
extern void WSGFbtronDrawString(TC* str,WSDfont* fn,GID gid,W fg,W bg,long len,short,short,long,WSCbool,long,long,long);
          W sw = WSGFbtronGetStringWidth(tip.cnv,fn,tlen);
          W sh = fn->getFontHeight();

          PAT pat;
          pat.spat.kind = 0;
          pat.spat.hsize = 16;
          pat.spat.vsize = 16;
          pat.spat.fgcol = bgv;
          pat.spat.bgcol = bgv;
          pat.spat.mask = FILL100;
          long i;
          RECT r;
          r.c.left = ax + _x;
          r.c.top = ay + _y;
          r.c.right = ax + _x + sw;
          r.c.bottom = ay + _y + sh+2;

          if (sw+1 < ow ){
//printf("ox=%d oy=%d ow=%d oh=%d\n",ox,oy,ow,oh);
//printf("sw+1=%d ow=%d\n",sw+1,ow);
//printf("x,y,w,h=%d,%d,%d,%d clear!!!\n",ox+sw+1,oy,ow - (sw+1),oh);
            r.c.right = ox+ow;
          }
          WSDbtronFormDev::setGlobalRegion(ax+_x,ay+_y,sw+1,sh+2);
          gset_for(_dev->getDeviceResource(),NULL);

          gfil_rec(_dev->getDeviceResource(),r,&pat,0,G_STORE);


          WSGFbtronDrawString(tip.cnv,fn,_dev->getDeviceResource(),fgv,bgv,tlen,ax+_x,ay+_y+sh,-1,0,0,scur1,scur2);

          pat.spat.fgcol = fgv;
          pat.spat.bgcol = fgv;
          PNT pt1;
          PNT pt2;
          pt1.x = ax + _x;
          pt1.y = ay + _y + sh;
          pt2.x = ax + _x + sw;
          pt2.y = ay + _y + sh;
          gdra_lin(_dev->getDeviceResource(),pt1,pt2,
                       (LN_SOLID<<8)+2,&pat,G_STORE);

        }

      }
      return True;
    }
  }

//  if (ret == 0){
//    return True;
//  }

  if (ev->s.stat & 0x10){
    _with_shift = 1;
  }else{
    _with_shift = 0;
  }
  if (ev->s.stat & 0x08){
    _with_lock = 1;
  }else{
    _with_lock = 0;
  }
  if (ev->s.stat & 0x80){
    _with_cntl = 1;
  }else{
    _with_cntl = 0;
  }
  if (ev->s.stat & 0x40){
    _with_alt = 1;
  }else{
    _with_alt = 0;
  }
  if ( key == KC_PG_U ){
    key = WSK_Page_Up;
  }
  if ( key == KC_PG_D ){
    key = WSK_Page_Down;
  }

  if ( key == KC_PG_R ||
       key == KC_SS_R ){
    key = WSK_Right;
  }
  if ( key == KC_PG_L ||
       key == KC_SS_L ){
    key = WSK_Left;
  }
  if ( key == KC_SS_U ){
    key = WSK_Up;
  }
  if ( key == KC_SS_D ){
    key = WSK_Down;
  }

  if ( //tip.n_out ==0 &&
      tip.n_cl == 0 &&
      (key == WSK_BackSpace ||
       key == WSK_Tab ||
       key == WSK_Clear ||
       key == WSK_Linefeed ||
       key == WSK_Return ||
       key == WSK_KP_Enter ||
       key == WSK_Pause ||
       key == WSK_Scroll_Lock ||
       key == WSK_Kanji ||
       key == WSK_Muhenkan ||
       key == WSK_Henkan_Mode ||
       key == WSK_Henkan ||
       key == WSK_Romaji ||
       key == WSK_Hiragana ||
       key == WSK_Katakana ||
       key == WSK_Hiragana_Katakana ||
       key == WSK_Zenkaku ||
       key == WSK_Hankaku ||
       key == WSK_Zenkaku_Hankaku ||
       key == WSK_Touroku ||
       key == WSK_Massyo ||
       key == WSK_Kana_Lock ||
       key == WSK_Kana_Shift ||
       key == WSK_Eisu_Shift ||
       key == WSK_Eisu_toggle ||
       key == WSK_Home ||
       key == WSK_Left ||
       key == WSK_Up ||
       key == WSK_Right ||
       key == WSK_Down ||
       key == WSK_Prior ||
       key == WSK_Page_Up ||
       key == WSK_Page_Down ||
       key == WSK_End ||
       key == WSK_Print ||
       key == WSK_Execute ||
       key == WSK_Insert ||
       key == WSK_Cancel ||
       key == WSK_Help ||
       key == WSK_Break ||
       key == WSK_Num_Lock ||
       key == WSK_KP_Tab ||
       key == WSK_KP_F1 ||
       key == WSK_KP_F2 ||
       key == WSK_KP_F3 ||
       key == WSK_KP_F4 ||
       key == WSK_KP_Home ||
       key == WSK_KP_Left ||
       key == WSK_KP_Up ||
       key == WSK_KP_Right ||
       key == WSK_KP_Down ||
       key == WSK_KP_Prior ||
       key == WSK_KP_Page_Up ||
       key == WSK_KP_Next ||
       key == WSK_KP_Page_Down ||
       key == WSK_KP_End ||
       key == WSK_KP_Begin ||
       key == WSK_KP_Insert ||
       key == WSK_KP_Delete ||
       key == WSK_F1 ||
       key == WSK_F2 ||
       key == WSK_F3 ||
       key == WSK_F4 ||
       key == WSK_F5 ||
       key == WSK_F6 ||
       key == WSK_F7 ||
       key == WSK_F8 ||
       key == WSK_F9 ||
       key == WSK_F10 ||
       key == WSK_F11 ||
       key == WSK_L1 ||
       key == WSK_F12 ||
       key == WSK_L2 ||
       key == WSK_Shift_L ||
       key == WSK_Shift_R ||
       key == WSK_Control_L ||
       key == WSK_Control_R ||
       key == WSK_Caps_Lock ||
       key == WSK_Shift_Lock ||
       key == WSK_Meta_L ||
       key == WSK_Meta_R ||
       key == WSK_Alt_L ||
       key == WSK_Alt_R ||
       key == WSK_Super_L ||
       key == WSK_Super_R ||
       key == WSK_Hyper_L ||
       key == WSK_Hyper_R ||
       _with_alt == True ||
       _with_cntl == True )){
dbprintf("one key notext alt=%d cntl=%d\n",_with_alt,_with_cntl);
    setText("");
    tip.n_cl = 0;
  }else{
    char* buffer = NULL;
    if ((ret == TIP_OUT || ret == (TIP_OUT | TIP_CL))
       && tip.n_out == 1){
      TC buf[7];
      buf[0] = begin_ascii[0];
      buf[1] = begin_ascii[1];
      buf[2] = begin_ascii[2];
      buf[3] = begin_ascii[3];
      buf[4] = begin_ascii[4];
      buf[5] = ev->s.wid;
      buf[6] = TNULL;

      buffer = WSGFbtronTcToString(buf);
dbprintf("one key buffer=0x%x\n",buffer);
    }else if (ret & TIP_OUT && tip.n_out > 0){
      setKey(WSK_A);
      buffer = WSGFbtronTcToString(tip.cnv);
      WSCstring str(buffer,WS_EN_UTF8);
      str.replaceString("\r\n","",1);
      delete buffer;
      buffer = WSGFstrdup(str.getString(WS_EN_UTF8));
dbprintf("kanji fixed buffer=#%s# len=%d %d\n",str.getString(WS_EN_EUCJP), strlen(str.getString(WS_EN_EUCJP)),str.getString(WS_EN_EUCJP)[strlen(str.getString(WS_EN_EUCJP))-1]);
      tip.n_out = 0;
    }
//printf("buffer=0x%x\n",buffer);
    if (buffer != NULL){
//printf("buffer=#%s#\n",buffer);
      setText(buffer,WS_EN_UTF8);
      delete buffer;
    }else{
      setText("");
    }
    tip.n_cl = 0;
  }
  if (key == WSK_Home ||
      key == WSK_End ||
      key == WSK_Up ||
      key == WSK_Left ||
      key == WSK_Right ||
      key == WSK_Down ||
      key == WSK_Page_Up ||
      key == WSK_Page_Down ){
    _is_cursor = 1;
  }else{
    _is_cursor = 0;
  }
  if (key == WSK_F1 ||
      key == WSK_F2 ||
      key == WSK_F3 ||
      key == WSK_F4 ||
      key == WSK_F5 ||
      key == WSK_F6 ||
      key == WSK_F7 ||
      key == WSK_F8 ||
      key == WSK_F9 ||
      key == WSK_F10 ||
      key == WSK_F11 ||
      key == WSK_F12 ){
    _is_function = 1;
  }else{
    _is_function = 0;
  }
  if (key == WSK_Delete || key == WSK_Insert){
    _is_tty_function = 1;
  }else{
    _is_tty_function = 0;
  }
  WSCbool executed = executeHandler(press);
  if (executed == True){
    return False;
  }else{
    return True;
  }
}

void WSDbtronKeyboard::setSelectedString(char* str,long encode){
  _selected_string.setString(str);
}

char* WSDbtronKeyboard::getSelectedString(long encoding){
  return _selected_string.getString();
}

void WSDbtronKeyboard::selectionDataAvailable(){
  _wait_for_receive_data = 0;
}

