/*--------------------------------------------------------------*
 *                                                              *
 *           = array  - Suffix Array からのテキスト検索 =       *
 *                                                              *
 *  array-show.c - show コマンドハンドラ                        *
 *                 現在の選択範囲を出力                         *
 *                                                              *
 *--------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sufary.h"
#include "array.h"

#include <assert.h>

#define MAX_SHOW_BUFFER_SIZE 400000
static char buffer[MAX_SHOW_BUFFER_SIZE]; /* 汎用バッファ */

static void show_sort(long show_from, long show_to);
static void output(long);
static void output_kwic(long);
static void output_simple(long);
static int long_cmp(const void *, const void *);

SUFARY *cur_ary;

/**********************************************
 *            eresult com_show(char *cmd);
 *
 * purpose
 *   検索結果を表示
 *
 * parameters
 *   cmd : 
 *
 * return value
 *   プログラム継続モード
 *
 * description
 *   現在のソートモードに従って分岐する
 **********************************************/
eresult com_show(char *cmd)
{
  int i;
  char *s, *t;
  long show_from, show_to;

  s = strtok(cmd, ct); /* 1つ目の引数 */
  if (s == NULL) show_from = -1;
  else show_from = atol(s);
  t = strtok(NULL, ct); /* 2つ目の引数 */
  if (t == NULL) show_to = -1;
  else show_to = atol(t);

  if (arrays == 0){
    printf ("specify target files first.\n");
    return CONT;
  }

  for (i = 0; i < arrays; i++){
    cur_ary = sufary[i];
    show_sort(show_from, show_to);
  }

  return CONT;
}


/**********************************************
 *          void output(long idx);
 *
 * purpose
 *   インデクス 1 要素をいろいろなフォーマットで出力
 *
 * parameters
 *   idx : インデクス
 *
 **********************************************/
static void output(long idx)
{
  char *s;
  switch (display_mode){
  case DISP_KWIC:    output_kwic(idx);      break;
  case DISP_INDEX:
    printf("%s:%ld\n", keyword,idx);
    break;
  case DISP_LINE:
    s = sa_getline(cur_ary,idx);
    printf("%s\n",s);
    free(s);
    break;
  case DISP_SIMPLE:
  default:           output_simple(idx);    break;
  }
}


/**********************************************
 * int long_cmp(const void *data1, const void *data2);
 *
 * purpose
 *   文字列の比較
 *
 * parameters
 *   data1 : 文字列1
 *   data2 : 文字列2
 *
 * return value
 *   -1 以下 : *data1 < *data2
 *    0      : *data1 == *data2
 *    1 以上 : *data1 > *data2
 *
 * description
 *   sort 用の比較コールバック関数
 **********************************************/
static int long_cmp(const void *data1, const void *data2)
{
  long *l1, *l2;
  long ret;

  l1 = (long*) data1;
  l2 = (long*) data2;
  ret = *l1 - *l2;
  return (ret>0)? 1: (ret<0)? -1: 0;
}


/**********************************************
 *      int suffix_compare(long *a, long *b)
 *
 * purpose
 *   テキストをコード順にソート
 *
 * parameters
 *   テキスト中のインデクス
 *
 * return value
 *   strcmpと同じ
 *
 * description
 *   show_sortのqsortから呼ばれる。
 *   (near 演算の出力がデフォルトでindex順になるため)
 **********************************************/
static int suffix_compare(long *a, long *b)
{
  return strcmp(cur_ary->txtmap + *a, cur_ary->txtmap + *b);
}


/**********************************************
 *      void show_sort(long show_from, long show_to)
 *
 * purpose
 *   コード順かインデックス順にソートされた出力
 *
 * parameters
 *   showコマンドで指定した、検索結果中の表示する範囲
 *
 * description
 *   show() から呼ばれる。検索結果に対し、順に output() を呼ぶ
 **********************************************/
static void show_sort(long show_from, long show_to)
{
  unsigned char *mapptr;
  static long now;
  long l, bottom, top, tmp, from, to, size;
  long *buf;

  bottom = sa_bottom(cur_ary);
  top    = sa_top(cur_ary);
  size = top - bottom + 1; /* 980327 for NEW sa_sel */

  if(show_from == -1) show_from = 1; /* show 第一引数省略時の処理 */
  if(show_to == -1) show_to = size; /* show 第二引数省略時の処理 */
  printf("from %ld to %ld (%ld)\n", show_from, show_to, size);

  from = bottom + show_from - 1; to = bottom + show_to;

  /* near副作用でインデックス順になってたりしないか？ */
  if (cur_ary->arymap == cur_ary->aryorig){
    /*** 普通の検索 ***/
    if(sort_mode == 1){ /* 辞書順ソート */
      for (tmp = from; tmp < to ; tmp++){
	l = sa_arraytotext(cur_ary, tmp);
	output(l);
      }
    }else{ /* インデックス順ソート  毎回ソートしてしまうのが不経済 */
      buf = (long *)malloc(size * sizeof(long));
      for (tmp = 0; tmp < size ; tmp++)
	buf[tmp] = sa_arraytotext(cur_ary, tmp + bottom);
      qsort(buf, size, sizeof(long), (int(*)(const void*,const void*))(long_cmp)); 
      for (tmp = from; tmp < to; tmp++)	output(buf[tmp-(bottom)]);
      free(buf);
    }
  } else {
    /*** near検索 ***/
    if(sort_mode == 1){ /* 辞書順ソート  毎回ソートしてしまうのが不経済 */
      buf = (long *)malloc(size * sizeof(long));
      for (tmp = 0; tmp < size ; tmp++)
	buf[tmp] = sa_arraytotext(cur_ary, tmp);
      qsort(buf, size, sizeof(long), (int(*)(const void*,const void*))(suffix_compare));
      for (tmp = from; tmp < to; tmp++)	output(buf[tmp-bottom]);
      free(buf);
    }else{ /* インデックス順ソート */
      for (tmp = from; tmp < to ; tmp++){
	l = sa_arraytotext(cur_ary,tmp);
	output(l);
      }
    }
  }
}


/**********************************************
 * void output_simple(long idx);
 *
 * purpose
 *   index とそこから60文字出力
 *
 * parameters
 *   idx : インデクス
 *
 **********************************************/
static void output_simple(long idx)
{
  strncpy(buffer,cur_ary->txtmap+idx,60);
  if(mojibake_proc_flag){ /* 文字化け防止処理 */
    sa_mojibakebousi(buffer);
    sa_ctrl_code_tubusi(buffer);
  }
  printf("%ld : %s\n", idx, buffer);
}


/****************************************************
 * output_kwic: 検索結果を Key Word in Context で表示
 * 
 * parameters
 *   idx --- キーワードへのインデックス
 * 修正開始 970126
 *  今まではKWIC幅にキーワード長(の半分)も含めていたが、それはやめ。
 *****************************************************/
static void output_kwic(long idx)
{
  long kwic_from,kwic_to;
  char *pos;
  char kwicpre[1500],kwicpost[1500];
  long kwlen = strlen(keyword); /* キーワードの文字列長 */

  if (cur_ary->arymap != cur_ary->aryorig) kwlen = 0; /* near検索のとき */

  /* キーワードより前の部分を取り出す */
/*  kwic_from = idx - kwic_width + kwlen/2;*/
  kwic_from = idx - kwic_width;
  if(kwic_from < 0) kwic_from = 0;

  strncpy(kwicpre,cur_ary->txtmap+kwic_from,idx-kwic_from);
  kwicpre[idx-kwic_from] = '\0';

  /* キーワードより後の部分取り出す */  
  kwic_to = idx + kwic_width + kwlen;
  if(kwic_to > (long)cur_ary->txtsz) kwic_to = (long)cur_ary->txtsz;

  strncpy(kwicpost,cur_ary->txtmap+idx+kwlen,kwic_to-idx);  
  kwicpost[kwic_to-(idx+kwlen)] = '\0';

  if (cur_ary->arymap == cur_ary->aryorig){
    /*** 普通の検索 ***/
    /* タグをつける */
    sprintf(buffer,"%s<SUFARYKEY>%s</SUFARYKEY>%s",kwicpre,keyword,kwicpost);
  }else{
    /*** near検索 ***/

    sprintf(buffer,"%s<SUFARYKEY>%s",kwicpre,kwicpost);
/*    kwic_from = idx - kwic_width;
    if(kwic_width % 2 == 1) kwic_from++;
    if(kwic_from < 0) kwic_from = 0;
    kwic_to = idx + kwic_width;
    if(kwic_to > (long)cur_ary->txtsz) kwic_to = (long)cur_ary->txtsz;

    strncpy(buffer, cur_ary->txtmap+kwic_from, kwic_to-kwic_from);

    buffer[kwic_to-kwic_from] = '\0';
*/
  }
  
  if(mojibake_proc_flag){ /* 文字化け防止処理 */
    sa_mojibakebousi(buffer);
    sa_ctrl_code_tubusi(buffer);
  }

  printf("%s\t%ld\n",buffer,idx); /* 出力 */
}


/**********************************************
 * com_line(char *cmd);
 **********************************************/
eresult com_line(char *cmd){
  long pos;
  char *s;

  pos = atol(cmd);
  s = sa_getline(sufary[0],pos);
  printf("%s\n",s);
/*  if(s[strlen(s)-1] != '\n') printf("\n");*/
  free(s);
  return CONT;
}


/**********************************************
 * com_get(char *cmd);
 **********************************************/
eresult com_get(char *cmd)
{
  long pos;
  char *s,d1[100],d2[100];

  if(sscanf(cmd,"%ld %s %s",&pos,d1,d2) < 3) return ERROR;
  s = sa_getblock(sufary[0],pos,d1,d2);
  printf("%s",s);
  if(s[strlen(s)-1] != '\n') printf("\n");
  free(s);
  return CONT;
}


/**********************************************
 * com_get_str(char *cmd);
 **********************************************/
eresult com_get_str(char *cmd)
{
  long idx;
  int num;
  char buf[1000];
  if(sscanf(cmd,"%ld %d",&idx,&num) < 2) return ERROR;
  strncpy(buf,(sufary[0]->txtmap+idx),num);
  buf[num] = '\0';
  printf("%s\n",buf);
  return CONT;
}
