/* (I think this was originally by Pinkfish)
   Mods by Hamlet, Aug 1997.
     * Fixed screen-size issues.
     * fixed odd bug with finish_func
     * removed annoying end-of-doc [more] thing.
     * Added quite a few commands.
     * Wrote /doc/more.help
*/
/* Notes:  Should probably change searches to regexp 
           Terrible hack in string_display_file() needs fixed...
              format now and send raw to player at the end, instead
              of double-formatting.
           Add a 'raw' variable that keeps system from converting colors.
              Convert more_file.c to inherit this to do the brunt of the
              work, probably.
*/
static int fsize,
    topl,
    used;
static string last_search, *the_bit, more_bit, stat_line;
static object finish_ob;
static mixed finish_func;
#define ROWS ((int)this_object()->query_rows() - 1)
#define COLS (int)this_object()->query_cols()
void call_finish_func(string str);
int string_display_file() {
  int botl, i, j, tmp;
  string out = "";
  int cols = COLS;
  botl = topl + ROWS;
  i = topl;
  
  tmp = sizeof(explode(sprintf("%-=*s", cols, the_bit[topl]), "\n")) - 1;
  if(tmp >= 0)
    j = tmp;
  while((i+j)<botl && i<fsize) {
    out += the_bit[i] + "\n";
 
    if((i+1) < fsize) {
      tmp = sizeof(explode(sprintf("%-=*s", cols, the_bit[i+1]), "\n")) - 1;  
                /* ^^^^ Extra lines it's gonna wrap. Terrible hack. */
      if(tmp > 0)
        j += tmp;
    }
    i++;
  }
  if(i == topl) { /* The first line is longer than a screen. */
    out += the_bit[i] + "\n";
    i++;
  }
  write(out);
  return (i - topl);
}
void more_string_status_line() {
  string *frog;
  string s;
  int i, percentage;
  if (!stat_line)
    stat_line = "$N From $T to $B of $S ($%%) - h for help. ";
  s = "";
  frog = explode(stat_line, "$");
  for (i=0;i<sizeof(frog);i++) {
    if (frog[i] == "") {
      s += "$";
      i ++;
    } else switch (frog[i][0]) {
      case 'N' :
          s += more_bit+frog[i][1..];
          break;
      case 'T' :
          s += (topl - used + 1)+frog[i][1..];
          break;
      case 'B' :
          if (topl > fsize)
            s += fsize+frog[i][1..];
          else
            s += topl+frog[i][1..];
          break;
      case '%' : {
          percentage = ((topl)*100)/fsize;
          if(percentage > 100) percentage = 100;
          s += percentage+frog[i][1..];
          break;
      }
      case 'S' :
         s += fsize+frog[i][1..];
         break;
    }
  }
  tell_object(this_object(), s);
  return;
}
void string_next_page(string str) {
  int num,
      noargs,
      i,
      redraw;
  string s1, s4, s5;
  if (!str)
    str = "";
  if (sscanf(str,"%d%s", num, str)!=2)
    noargs = 1;
  s1 = str[1..];
  str = str[0..0];
/* case statements WEEEEEE */
  switch(str) {
    case "" :
    case "f" :
               /* go on a number of pages... */
               if(!noargs)
                 topl += (ROWS * (num - 1));
               redraw = 1;
               break;
    case "b" :
               if(noargs)
                 num = 1;
               topl -= (ROWS * (num + 1)); 
               redraw = 1;
               break;
    case " " :
    case "z" :
               if(noargs)
                 num = 1;
               while(num--) {
                 write(the_bit[topl] + "\n");
                 topl++;
                 if(topl >= fsize)
                   break;
               }
               break;
    case "." :
               topl -= used;
               redraw = 1;
               break;
    case "s" : 
               topl += num;
               redraw = 1;
               break;
    case "q" :
    case "Q" : 
               call_finish_func(str);
               return;
    case "g" :
               topl = num;
               if(topl >= fsize)
                 topl = fsize - 2;
               redraw = 1;
               break;
    case "G" :
               redraw = 1;
               if (noargs)
                 topl = fsize - ROWS;
               else
                 topl = (fsize - num);
               break;
    case "/" :
               if (s1=="")
                 s1 = last_search;
               if (!s1 || s1 == "")
                 s1 = "bing!";
               last_search = s1;
               for (i=topl;i<fsize;i++)
                 if (sscanf(the_bit[i],"%s"+s1+"%s",s4,s5)==2)
                   if (num--<=0)
                     break;
               if (i==fsize)
                 write("Sorry "+s1+" not found.\n");
               else {
                 topl = i-3;
                 redraw = 1;
               }
               break;
    case "-" :
               if (s1=="")
                 s1 = last_search;
               if (!s1 || s1 == "")
                 s1 = "bing!";
               last_search = s1;
               for (i=(topl-ROWS);i>=0;i--)
                 if (sscanf(the_bit[i],"%s"+s1+"%s",s4,s5)==2)
                   if (num--<=0)
                     break;
               if (i<0)
                 write("Sorry "+s1+" not found.\n");
               else {
                 topl = i-3;
                 redraw = 1;
               }
               break;
    case "?" :
    case "h" :
               if(file_size("/doc/more.help") > 0)
                 tell_object(this_object(), read_file("/doc/more.help"));
               else
                 tell_object(this_object(), 
                             "The help document (/doc/more.help) "
                             "is missing.  Get someone to fix it.\n");
               break;
  }
  if(topl < 0)
    topl = 0;
  else if(topl >= fsize)
    topl = fsize - ROWS;
  if (redraw) {
    used = string_display_file();
    topl += used; 
  }
  if (topl<fsize) {
    more_string_status_line();
    input_to("string_next_page");
  } else
    call_finish_func(0);
}
varargs int more_string(mixed str, string bity, string more_fmt) {
  if (bity)
    more_bit = bity;
  else
    more_bit = "--- MORE";
  last_search = "";
 
  if(more_fmt)
    stat_line = more_fmt;
  else
    stat_line = 0;
  if (!pointerp(str)) 
    the_bit = explode(str,"\n");
  fsize = sizeof(the_bit);
  if (fsize == 0) {
    notify_fail("Empty String.\n");
    return 0;
  }
  topl = 0;
  used = string_display_file();
  topl += used;
  if (topl < fsize) {
    more_string_status_line();
    input_to("string_next_page");
  } else 
    call_finish_func(0);
  return 1;
}
int set_finish_func(mixed str, object ob) {
  finish_func = str;
  if (!functionp(str) && !ob)
    finish_ob = previous_object();
  else
    finish_ob = ob;
}
void call_finish_func(string str) {
  mixed f_func;
  if (finish_func) {
    f_func = finish_func;
    finish_func = 0;
    if(functionp(f_func))
// This will have to wait.  requires modifications of mailer.
//      evaluate(f_func, str);
      evaluate(f_func);
    else
//      call_other(finish_ob, f_func, str);
      call_other(finish_ob, f_func);
  }
}