//
// Copyright (C) 1999-2004 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 <x11/WSxcom.h>
#include <x11/WSDxappDev.h>
#include <WScom.h>
#include <WSCstring.h>
#include <WSClistData.h>
#include <WSClocaleSet.h>
#include <WSDcolor.h>

#if 1 //UNICODE
#include <xunicode.h>
#endif //UNICODE

//#define DBG

extern int WSGFpickupString(unsigned char *dest,unsigned  char *src, int *n);
extern char *EUCToJIS(char *input);

extern "C" {
void libwsx11_func();
};
void libwsx11_func(){
}


static WSClistData* _pix_list = NULL;
static WSClistData* _pix_ws = NULL;
static WSClistData* _pix_hs = NULL;
static WSClistData* _used_pix_list = NULL;
static WSClistData* _used_pix_ws = NULL;
static WSClistData* _used_pix_hs = NULL;

static void _init_plist(){
  _pix_list = new WSClistData();
  _pix_ws = new WSClistData();
  _pix_hs = new WSClistData();
  _used_pix_list = new WSClistData();
  _used_pix_ws = new WSClistData();
  _used_pix_hs = new WSClistData();
}


Pixmap WSGFxGetPixmap(WSCushort w,WSCushort h){
  if (_pix_list == NULL){
    _init_plist();
  }
  long pw = (long)w;
  long ph = (long)h;
  long iw = 0;
  long ih = 0;
  long i = 0;
  long num = _pix_list->getNum();
  for(i=0; i<num; i++){
    iw = (long)_pix_ws->getData(i);
    ih = (long)_pix_hs->getData(i);

    if (pw <= iw && ph <= ih && pw > iw/2 && ph > ih/2){
      Pixmap pix = (Pixmap)_pix_list->getData(i);
      _pix_list->delPos(i);
      _pix_ws->delPos(i);
      _pix_hs->delPos(i);
      _used_pix_list->add((void*)pix);
      _used_pix_ws->add((void*)iw);
      _used_pix_hs->add((void*)ih);
      return pix;
    }
  }
  WSDxappDev* app   = WSGIxwinAppDev();
  Pixmap pix = XCreatePixmap(XtDisplay(app->appWidget()),
                             XtWindow(app->appWidget()), w,h,
                             DefaultDepth(XtDisplay(app->appWidget()),
                             DefaultScreen(XtDisplay(app->appWidget()))));
  _used_pix_list->add((void*)pix);
  _used_pix_ws->add((void*)pw);
  _used_pix_hs->add((void*)ph);

  return pix;
}

void WSGFxReleasePixmap(Pixmap pix){
  if (_pix_list == NULL){
    _init_plist();
  }
  long i,w,h;
  long num = _used_pix_list->getNum();
  long pnum = _pix_list->getNum();
  for(i=0; i<num; i++){
    Pixmap item = (Pixmap)_used_pix_list->getData(i);
    if (item == pix){
      w = (long)_used_pix_ws->getData(i);
      h = (long)_used_pix_hs->getData(i);
      _used_pix_list->delPos(i);
      _used_pix_ws->delPos(i);
      _used_pix_hs->delPos(i);
      if (pnum < 16 && w < 512 && h < 512){
        _pix_list->add((void*)pix);
        _pix_ws->add((void*)w);
        _pix_hs->add((void*)h);
      }else{
        WSDxappDev* app   = WSGIxwinAppDev();
        XFreePixmap(XtDisplay(app->appWidget()),item);
      }
      break;
    }
  }
}

static void draw_cur(Display* disp,Window win,GC gc,int linew,int x,int y,int width){
#ifdef DBG
  printf("xcom::draw_cur %d %d\n",x,y);
#endif
  if (linew != 3){
    XSetLineAttributes(disp,gc,3, LineSolid,CapButt,WS_JOIN);
  }
  XDrawLine(disp,win,gc,x,y - width +1, x, y +3);
  if (linew != 3){
    if (linew == 1){
      XSetLineAttributes(disp,gc,0, LineSolid,CapButt,WS_JOIN);
    }else{
      XSetLineAttributes(disp,gc,linew, LineSolid,CapButt,WS_JOIN);
    }
  }
}

char *EUCToJIS(char *input){
  static char* output = NULL;
  if(output != NULL){
    delete output;
  }
  long len = strlen(input);
  output = new char[len + 32];
  len++;

  int i,p=0;
  for (i = 0; i < len; i++){

    if (input[i] == (char )0x8e){
      i++;
      output[p] = input[i];
      p++;

    }else if (input[i] == (char )0x8f){
      i++;
      output[p] = (char )0x7f & input[i];
      i++;
      p++;
      output[p] = (char )0x7f & input[i];
      p++;

    }else if (input[i] & (char )0x80){
      output[p] = (char )0x7f & input[i];
      i++;
      p++;
      output[p] = (char )0x7f & input[i];
      p++;
    }else if (input[i] == (char )0){
      output[p] = 0;
      return output;
    }else{
      output[p] = input[i];
      p++;
    }

  }
  return output;
}
//#define WS_LANG_C 1
//#define WS_LANG_JAPANESE 2
//static long _lang_inited = False;
//static long _lang = 0;

void WSGFxdrawTextString(Display* disp,Window win,GC gc,
                        XFontStruct* efs,XFontStruct* kf,XFontStruct* gf,
                        WSCulong fg,WSCulong bg,
                        long x,long y,char *string,
                        WSCushort kwidth,WSCushort ewidth,
                        WSCushort kheight,WSCushort eheight,
                        long cur,WSCbool inter_cur,WSCushort linew,
                        long scur1,long scur2 ){

  y -= 1;

  XUChar work[8192];
  long len = strlen(string);
  if (len > 0){
    int slen = XUutf8Encode(work, 8192, string, -1);
    if (scur1 <= 0 && scur2 >= slen){
      XSetForeground(disp,gc,bg);
      XSetBackground(disp,gc,fg);
      XUDrawString(disp,win, efs,gc, x, y, work, -1, True);
      XSetForeground(disp,gc,fg);
      XSetBackground(disp,gc,bg);
    }else{
      XUDrawString(disp,win, efs,gc, x, y, work, -1, False);
      if (scur1 < 0) scur1 = 0;
      if (scur2 < 0) scur2 = 0;
      if (scur1 > slen) scur1 = slen;
      if (scur2 > slen) scur2 = slen;
      if (scur1 != scur2){
        int x2 = x;
        if (scur1 > 0) x2 += XUTextWidth(disp, efs, work, scur1);
        XSetForeground(disp,gc,bg);
        XSetBackground(disp,gc,fg);
        XUDrawString(disp,win, efs,gc, x2, y, &work[scur1], scur2 - scur1, True);
        XSetForeground(disp,gc,fg);
        XSetBackground(disp,gc,bg);
      }
    }
    if (cur >= 0 && cur < slen + inter_cur ){
      int x2 = x;
      if (cur > 0) x2 += XUTextWidth(disp, efs, work, cur);
      if (inter_cur == False){
        XSetForeground(disp,gc,bg);
        XSetBackground(disp,gc,fg);
        XUDrawString(disp,win, efs,gc, x2, y, &work[cur], 1, True);
        XSetForeground(disp,gc,fg);
        XSetBackground(disp,gc,bg);
      }else{
        if (work[cur] != '\n'){
          draw_cur(disp,win,gc,linew,x2,y,eheight);
        }
      }
    }
  }else if (inter_cur == 1 && cur == 0){
    draw_cur(disp,win,gc,linew,x,y,eheight);
  }

  return;
}


int WSGFpickupString(unsigned char *dest,unsigned char *src, int *n) {
   int jflag;
   
   *n = 0;

   if (src[0] == 0) return 1;

   if (src[0] == 0x8f || src[0] > 0xf4){
     jflag = WS_GAIJI;
   }else if (src[0] == 0x8e){
     jflag = WS_HKANA;
   }else if (src[0] & 0x80){
     jflag = WS_KANJI;
   }else{
     jflag = WS_ASCII;
   }
   *n = 0;

   while(1){ 
     //end of string
     if (src[*n] == 0){
       dest[*n] = 0;
       if (jflag == WS_KANJI || jflag == WS_GAIJI){
         *n = -(*n);
       } 
       if (jflag == WS_GAIJI){
         return -1;
       }else{
         return 0;
       }
     }
     if (src[*n] == 0x8e){ //is hkana?
       if (jflag != WS_HKANA){
         dest[*n] = 0;
         if (jflag == WS_GAIJI || jflag == WS_KANJI){
           *n = -(*n);
         }

         if (jflag == WS_GAIJI){
           return -1;
         }else{
           return 0;
         }
       }else{
         dest[*n] = src[*n];
         *n = *n +1;
       }
     }else if (src[*n] == 0x8f || src[*n] > 0xf4){ //is gaiji?
       if (jflag != WS_GAIJI){
         dest[*n] = 0;
         if (jflag == WS_KANJI){
           *n = -(*n);
         }
         return 0;
       }else{
         if (src[*n] == 0x8f){
           dest[*n] = src[*n];
           *n = *n +1;
         }
         dest[*n] = src[*n];
         *n = *n +1;
       }
 
     }else if (src[*n] & 0x80){ // is kanji?
       if (jflag != WS_KANJI){
         dest[*n] = 0;
         if (jflag == WS_GAIJI){
           *n = -(*n);
           return -1;
         }else{
           return 0;
         }
       }else{
         dest[*n] = src[*n];
         *n = *n +1;
       }
     }else{ //ascii
       if (jflag != WS_ASCII){
         dest[*n] = 0;
         if (jflag == WS_GAIJI || jflag == WS_KANJI){
           *n = -(*n);
         }
         if (jflag == WS_GAIJI){
           return -1;
         }else{
           return 0;
         }
       }
     }
     dest[*n] = src[*n];
     *n = *n +1;
   }
}

WSCulong WSGFxcolorval(WSDcolor* work,WSCuchar r,WSCuchar g,WSCuchar b){
static WSClistData cval;
static WSClistData clist;
  long num = cval.getNum();
  long val = r << 16 | g << 8 | b;
  long i;
  for(i=0; i<num; i++){
    if (val == (long)cval[i]){
      return (WSCulong)clist[i];
    }
  }
  char buffer[32];
  sprintf(buffer,"#%02x%02x%02x",r,g,b);
  work->setColorName(buffer);
  WSCulong ret  = (WSCulong)work->getValue1();
  cval.add((void*)val);
  clist.add((void*)ret);
  return ret;
}

char* cvt_table[]={
"\xe3\x81\x8b\xe3\x82\x99","\xe3\x81\x8c", //GA
"\xe3\x81\x8d\xe3\x82\x99","\xe3\x81\x8e", //GI
"\xe3\x81\x8f\xe3\x82\x99","\xe3\x81\x90", //GU
"\xe3\x81\x91\xe3\x82\x99","\xe3\x81\x92", //GE
"\xe3\x81\x93\xe3\x82\x99","\xe3\x81\x94", //GO
"\xe3\x81\x95\xe3\x82\x99","\xe3\x81\x96", //ZA
"\xe3\x81\x97\xe3\x82\x99","\xe3\x81\x98", //ZI
"\xe3\x81\x99\xe3\x82\x99","\xe3\x81\x9a", //ZU
"\xe3\x81\x9b\xe3\x82\x99","\xe3\x81\x9c", //ZE
"\xe3\x81\x9d\xe3\x82\x99","\xe3\x81\x9e", //ZO
"\xe3\x81\x9f\xe3\x82\x99","\xe3\x81\xa0", //DA
"\xe3\x81\xa1\xe3\x82\x99","\xe3\x81\xa2", //DI
"\xe3\x81\xa4\xe3\x82\x99","\xe3\x81\xa5", //DU
"\xe3\x81\xa6\xe3\x82\x99","\xe3\x81\xa7", //DE
"\xe3\x81\xa8\xe3\x82\x99","\xe3\x81\xa9", //DO
"\xe3\x81\xaf\xe3\x82\x99","\xe3\x81\xb0", //BA
"\xe3\x81\xaf\xe3\x82\x9a","\xe3\x81\xb1", //PA
"\xe3\x81\xb2\xe3\x82\x99","\xe3\x81\xb3", //BI
"\xe3\x81\xb2\xe3\x82\x9a","\xe3\x81\xb4", //PI
"\xe3\x81\xb5\xe3\x82\x99","\xe3\x81\xb6", //BU
"\xe3\x81\xb5\xe3\x82\x9a","\xe3\x81\xb7", //PU
"\xe3\x81\xb8\xe3\x82\x99","\xe3\x81\xb9", //BE
"\xe3\x81\xb8\xe3\x82\x9a","\xe3\x81\xba", //PE
"\xe3\x81\xbb\xe3\x82\x99","\xe3\x81\xbc", //BO
"\xe3\x81\xbb\xe3\x82\x9a","\xe3\x81\xbd", //PO

"\xe3\x82\xab\xe3\x82\x99","\xe3\x82\xac", //GA
"\xe3\x82\xad\xe3\x82\x99","\xe3\x82\xae", //GI
"\xe3\x82\xaf\xe3\x82\x99","\xe3\x82\xb0", //GU
"\xe3\x82\xb1\xe3\x82\x99","\xe3\x82\xb2", //GE
"\xe3\x82\xb3\xe3\x82\x99","\xe3\x82\xb4", //GO
"\xe3\x82\xb5\xe3\x82\x99","\xe3\x82\xb6", //ZA
"\xe3\x82\xb7\xe3\x82\x99","\xe3\x82\xb8", //ZI
"\xe3\x82\xb9\xe3\x82\x99","\xe3\x82\xba", //ZU
"\xe3\x82\xbb\xe3\x82\x99","\xe3\x82\xbc", //ZE
"\xe3\x82\xbd\xe3\x82\x99","\xe3\x82\xbe", //ZO
"\xe3\x82\xbf\xe3\x82\x99","\xe3\x83\x80", //DA
"\xe3\x83\x81\xe3\x82\x99","\xe3\x83\x82", //DI
"\xe3\x83\x84\xe3\x82\x99","\xe3\x83\xa5", //DU
"\xe3\x83\x86\xe3\x82\x99","\xe3\x83\x87", //DE
"\xe3\x83\x88\xe3\x82\x99","\xe3\x83\x89", //DO
"\xe3\x83\x8f\xe3\x82\x99","\xe3\x83\x90", //BA
"\xe3\x83\x8f\xe3\x82\x9a","\xe3\x83\x91", //PA
"\xe3\x83\x92\xe3\x82\x99","\xe3\x83\x93", //BI
"\xe3\x83\x92\xe3\x82\x9a","\xe3\x83\x94", //PI
"\xe3\x83\x95\xe3\x82\x99","\xe3\x83\x96", //BU
"\xe3\x83\x95\xe3\x82\x9a","\xe3\x83\x97", //PU
"\xe3\x83\x98\xe3\x82\x99","\xe3\x83\x99", //BE
"\xe3\x83\x98\xe3\x82\x9a","\xe3\x83\x9a", //PE
"\xe3\x83\x9b\xe3\x82\x99","\xe3\x83\x9c", //BO
"\xe3\x83\x9b\xe3\x82\x9a","\xe3\x83\x9d", //PO
NULL,NULL,
};

#define UTF8_PREFIX 0xe3
#define UTF8_M_S_T1_FROM 0x80
#define UTF8_M_S_T1_TO   0x84
#define UTF8_M_S_T2_FROM 0x7f
#define UTF8_M_S_T2_TO   0xc0

#define UTF8_S_M_T1_FROM 0x80
#define UTF8_S_M_T1_TO   0x84
#define UTF8_S_M_T2_FROM 0x7f
#define UTF8_S_M_T2_TO   0xc0

char* macutf8_to_utf8(char* src){
  if (src == NULL){
    return 0;
  }
//printf("macutf8_to_utf8 #%s#\n",src);
  long slen = strlen(src)+1;
  char* dest = new char[slen];

  long sptr = 0;
  long dptr = 0;
  while(1){
    if (src[sptr] == 0){
      dest[dptr] = 0;
      return dest;
    }
    if ((unsigned char)src[sptr] == UTF8_PREFIX){
      if ((unsigned char)src[sptr+1] > UTF8_M_S_T1_FROM &&
          (unsigned char)src[sptr+1] < UTF8_M_S_T1_TO){
        if ((unsigned char)src[sptr+2] > UTF8_M_S_T2_FROM &&
            (unsigned char)src[sptr+2] < UTF8_M_S_T2_TO){
          long tblptr = 0;
          long converted = 0;
          while(1){
            if (cvt_table[tblptr*2] == NULL){
              break;
            }
            if (!strncmp(&src[sptr],
                         cvt_table[tblptr*2],
                         strlen(cvt_table[tblptr*2]))){
              converted = 1;
              strcpy(&dest[dptr],cvt_table[tblptr*2+1]);
//printf("macutf8_to_utf8 converted!! #%s#\n",dest);
              sptr += strlen(cvt_table[tblptr*2]);
              dptr += strlen(cvt_table[tblptr*2+1]);
              break;
            }
            tblptr++;
          }
          if(converted == 1){
            continue;
          }
        }
      }
    }
    dest[dptr] = src[sptr];
    sptr++;
    dptr++;
  }
  return dest;
}
char* utf8_to_macutf8(char* src){
  if (src == NULL){
    return 0;
  }
  long slen = strlen(src)+1;
  char* dest = new char[slen*2];

  long sptr = 0;
  long dptr = 0;
  while(1){
    if (src[sptr] == 0){
      dest[dptr] = 0;
      return dest;
    }
    if ((unsigned char)src[sptr] == UTF8_PREFIX){
      if ((unsigned char)src[sptr+1] > UTF8_S_M_T1_FROM &&
          (unsigned char)src[sptr+1] < UTF8_S_M_T1_TO){
        if ((unsigned char)src[sptr+2] > UTF8_S_M_T2_FROM &&
            (unsigned char)src[sptr+2] < UTF8_S_M_T2_TO){
          long tblptr = 0;
          long converted = 0;
          while(1){
            if (cvt_table[tblptr*2+1] == NULL){
              break;
            }
            if (!strncmp(&src[sptr],
                         cvt_table[tblptr*2+1],
                         strlen(cvt_table[tblptr*2+1]))){
              converted = 1;
              strcpy(&dest[dptr],cvt_table[tblptr*2]);
              sptr += strlen(cvt_table[tblptr*2+1]);
              dptr += strlen(cvt_table[tblptr*2]);
              break;
            }
            tblptr++;
          }
          if(converted == 1){
            continue;
          }
        }
      }
    }
    dest[dptr] = src[sptr];
    sptr++;
    dptr++;
  }
  return dest;
}
