/*
 *  $Id: jishosub.c,v 1.3 2001/06/14 18:16:02 ura Exp $
 */

/*
 * FreeWnn is a network-extensible Kana-to-Kanji conversion system.
 * This file is part of FreeWnn.
 * 
 * Copyright Kyoto University Research Institute for Mathematical Sciences
 *                 1987, 1988, 1989, 1990, 1991, 1992
 * Copyright OMRON Corporation. 1987, 1988, 1989, 1990, 1991, 1992, 1999
 * Copyright ASTEC, Inc. 1987, 1988, 1989, 1990, 1991, 1992
 * Copyright FreeWnn Project 1999, 2000
 *
 * Maintainer:  FreeWnn Project   <freewnn@tomo.gr.jp>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <stdio.h>
#include "commonhd.h"
#include "de_header.h"
#include "jdata.h"

static int inspect_sd (), get_fst_serial (), inspect_ud ();

int
inspect (dic_no, serial, yomi, jd)
     int dic_no;
     int serial;
     w_char *yomi;
     struct jdata *jd;
{
  struct JT *jtl;

  if (dic_no >= MAX_DIC || dic_no < 0 || dic_table[dic_no].body == -1)
    {
      wnn_errorno = WNN_DICT_NOT_IN_ENV;
      return (-1);
    }
  jtl = (struct JT *) (files[dic_table[dic_no].body].area);
  if (jtl->syurui == WNN_UD_DICT)
    {
      if (inspect_ud (dic_no, serial, yomi, jd) == -1)
        return (-1);
#if     defined(CONVERT_by_STROKE) || defined(CONVERT_with_SiSheng)
    }
  else if ((jtl->syurui & 0xff) == WNN_REV_DICT)
    {
#else
    }
  else if (jtl->syurui == WNN_REV_DICT)
    {
#endif /* CONVERT_by_STROKE || CONVERT_with_SiSheng */
      if (inspect_rd (dic_no, serial, yomi, jd) == -1)
        return (-1);
    }
  else
    {
      if (inspect_sd (dic_no, serial, yomi, jd) == -1)
        return (-1);
    }
  return (0);
}



int
get_yomi_from_serial (dic_no, serial, yomi)
     int dic_no;
     int serial;
     w_char *yomi;
{
  int k;
  struct jdata jdata;
  struct JT *jtl;

  jtl = (struct JT *) (files[dic_table[dic_no].body].area);
  for (k = 0; k < LENGTHYOMI; k++)
    {
      yomi[k] = 0;
    }

  if (jtl->syurui == WNN_UD_DICT)
    {
      if (inspect_ud (dic_no, serial, yomi, &jdata) == -1)
        return (-1);
#if     defined(CONVERT_by_STROKE) || defined(CONVERT_with_SiSheng)
    }
  else if ((jtl->syurui & 0xff) == WNN_REV_DICT)
    {
#else
    }
  else if (jtl->syurui == WNN_REV_DICT)
    {
#endif /* CONVERT_by_STROKE || CONVERT_with_SiSheng */
      if (inspect_rd (dic_no, serial, yomi, &jdata) == -1)
        return (-1);
    }
  else
    {
      if (inspect_sd (dic_no, serial, yomi, &jdata) == -1)
        return (-1);
    }
  return (0);
}


static int
inspect_sd (dic_no, serial, yomi, jd)
     int dic_no;
     int serial;
     w_char *yomi;
     struct jdata *jd;
{
  int len;
  struct JT *jtl;
  struct HJT *hjtl;
  UCHAR *hontaistart;
  UCHAR *hopter;
  int key;
  int tsize;
  w_char *charst;
  w_char *sumst;
  int *ptrst;
  int state;
  int sdiff;
  int last;
  int serialst;
  UCHAR *kanji1;


  yomi[0] = 0;
  jtl = (struct JT *) (files[dic_table[dic_no].body].area);
  if (dic_table[dic_no].hindo >= 0)
    hjtl = (struct HJT *) (files[dic_table[dic_no].hindo].area);
  else
    hjtl = NULL;
  hontaistart = jtl->hontai;
  hopter = hontaistart;
  if (serial >= jtl->maxserial)
    {
      wnn_errorno = WNN_WORD_NO_EXIST;
      return (-1);
    }
  if (jtl->hinsi[serial] == SAKUJO_HINSI)
    return (-1);

  for (;;)
    {
      switch ((state = *(w_char *) hopter))
        {
        case ST_NORMAL:
        case ST_NOPTER:
          tsize = *(w_char *) (hopter + 2);
          serialst = *(int *) (hopter + 4);
          kanji1 = (UCHAR *) (hopter + 8);
          charst = (w_char *) (hopter + 12);
          sumst = ((w_char *) charst + tsize + 2);
          /* + 2 keeps two zero words */
          ptrst = (int *) ((w_char *) sumst + tsize);
          sdiff = serial - *(int *) (hopter + 4);

          /* May be a little late, but enough */
          if ((int) sdiff < (int) sumst[tsize - 1])
            {
              for (key = 0; key < tsize; key++)
                {
                  if ((int) sdiff < (int) sumst[key])
                    {
                      break;
                    }
                }
              len = Strlen (yomi);
              yomi[len] = charst[key];
              yomi[len + 1] = 0;

              jd->kanji1 = (int)kanji1; // xxx this may result in failure --yaz
              jd->kanji2 = serial - serialst;
              jd->serial = serial;
              jd->kosuu = 1;
              jd->jishono = dic_no;
              jd->jptr = NULL;
              jd->hinsi = jtl->hinsi + serial;
              if (hjtl)
                {
                  jd->hindo = hjtl->hindo + serial;
                  jd->hindo_in = jtl->hindo + serial;
                }
              else
                {
                  jd->hindo = jtl->hindo + serial;
                  jd->hindo_in = NULL;
                }
              return (0);
            }
          else
            {
              if (state == ST_NOPTER)
                {
                  wnn_errorno = WNN_WORD_NO_EXIST;
                  return (-1);
                }
              last = 0;
              for (key = 0; key < tsize; key++)
                {
                  if (ptrst[key])
                    {
                      if (serial < get_fst_serial (hontaistart + ptrst[key], hontaistart))
                        break;
                      last = key;
                    }
                }
              len = Strlen (yomi);
              yomi[len] = charst[last];
              yomi[len + 1] = 0;
              hopter = hontaistart + ptrst[last];
            }
          break;
        case ST_NOENT:
          tsize = *(w_char *) (hopter + 2);
          charst = (w_char *) (hopter + 4);
          ptrst = (int *) AL_INT ((w_char *) charst + tsize);
          last = 0;
          for (key = 0; key < tsize; key++)
            {
              if (ptrst[key])
                {
                  if (serial < get_fst_serial (hontaistart + ptrst[key], hontaistart))
                    break;
                  last = key;
                }
            }
          len = Strlen (yomi);
          yomi[len] = charst[last];
          yomi[len + 1] = 0;
          hopter = hontaistart + ptrst[last];
          break;
        case ST_SMALL:
          len = Strlen (yomi);
          yomi[len] = *(w_char *) (hopter + 2);
          yomi[len + 1] = 0;
          hopter = hopter + 4;
          break;
        default:
          error1 ("inspect_sd:Error 2\n");
        }
    }
}

static int
get_fst_serial (hopter, hontaistart)
     UCHAR *hontaistart;
     char *hopter;
{
  int tsize;
  int k;
  int *ptrst;
  w_char *charst;

  switch (*(w_char *) hopter)
    {
    case ST_NORMAL:
    case ST_NOPTER:
      return (*(int *) (hopter + 4));
    case ST_NOENT:
      tsize = *(w_char *) (hopter + 2);
      charst = (w_char *) (hopter + 4);
      ptrst = (int *) AL_INT ((w_char *) charst + tsize);
      for (k = 0; k < tsize; k++)
        {
          if (ptrst[k])
            {
              return (get_fst_serial (hontaistart + ptrst[k], hontaistart));
            }
        }
      break;
    case ST_SMALL:
      return (get_fst_serial (hopter + 4, hontaistart));
    default:
      error1 ("get_fst_serial:Error 1\n");
    }
  return (-1);
}


static int
inspect_ud (dic_no, serial, yomi, jd)
     int dic_no;
     int serial;
     w_char *yomi;
     struct jdata *jd;
{
  struct JT *jtl;
  struct HJT *hjtl;
  struct uind1 *tary;
  struct uind2 *p;
  int k;
  int len;

  jtl = (struct JT *) (files[dic_table[dic_no].body].area);
  tary = jtl->table;
  if (dic_table[dic_no].hindo >= 0)
    hjtl = (struct HJT *) (files[dic_table[dic_no].hindo].area);
  else
    hjtl = NULL;

  if (serial >= jtl->maxserial)
    {
      wnn_errorno = WNN_WORD_NO_EXIST;
      return (-1);
    }
  if (jtl->hinsi[serial] == SAKUJO_HINSI)
    return (-1);

  for (k = 0; k < jtl->maxtable; k++)
    {
      for (p = ((struct uind2 *) ((tary[k].pter) + jtl->hontai));; p = ((struct uind2 *) ((p->next) + jtl->hontai)))
        {
          if ((int) p->serial <= (int) serial && (int) (p->serial + p->kosuu) > (int) serial)
            goto found_it;
          if (p->next == ENDPTR)
            break;
        }
    }
  wnn_errorno = WNN_WORD_NO_EXIST;
  return (-1);

found_it:
  yomi[0] = tary[k].yomi1 >> 16;
  yomi[1] = tary[k].yomi1 & 0xffff;
  if (yomi[1])
    {
      yomi[2] = tary[k].yomi2 >> 16;
      if (yomi[2])
        {
          yomi[3] = tary[k].yomi2 & 0xffff;
        }
    }
  len = p->yomi[0];
  Strncpy (yomi + 4, (p->yomi) + 1, len - 4);
  yomi[len] = 0;

  jd->kanji1 = p->kanjipter; // xxx this may result in failure --yaz
  jd->kanji2 = serial - p->serial;
  jd->serial = serial;
  jd->kosuu = 1;
  jd->jishono = dic_no;
  jd->jptr = NULL;
  jd->hinsi = jtl->hinsi + serial;
  if (hjtl)
    {
      jd->hindo = hjtl->hindo + serial;
      jd->hindo_in = jtl->hindo + serial;
    }
  else
    {
      jd->hindo = jtl->hindo + serial;
      jd->hindo_in = NULL;
    }

  return (0);
}
