#include <stdio.h>
#include "buffer.h"
#include "externs.h"
#include "display.h"
#include "line.h"
  
extern int COLUMN;

#define MAX_LINE_LEN 500
int MOST_S_OPT = 0;
/* take 16 binary characters and put them in displayable form */
int ascii_format_line(char *buff, char *str)
{
    int i,ii,j,k,ch,di,flag;
    char num_str[4];

    ii = 0;
    di = 40;
    flag = 1;

    for (i = 35;i<=di;i++) str[i] = ' ';  /* a gap */
    
    for (j = 0; j < 4; j++)
      {
          
          for (k = 0; k < 4; k++)
            {
                i = 4 * j + k;
                ch = buff[i];
                if (MOST_V_OPT)
                  {
                      if (((ch < 32) && (ch >= 0)) || (ch == 127))
                        {
                            str[ii++] = '^';
                            if (ch == 127)
                              str[ii++] = '?';
                            else
                              str[ii++] = ch + 'A' - 1;
                            str[i + di] = '.';
                        }
                      else if (ch < 0)
                        {
                            ch = ch + 256; 
                            sprintf(num_str,"%02X", ch);
                            str[ii++] = num_str[0];
                            str[ii++] = num_str[1];
                            str[i + di] = '.';
                        }
                      else
                        {
                            str[ii++] = ' ';
                            str[ii++] = ch;
                            str[i + di] = ch;
                        }
                  }
                else
                  {
                      if (ch < 32)
                        {
                            if (ch < 0) ch = ch + 256;
                            str[i + di] = '.';
                        }
                      else str[i+di] = ch;
                      
                      sprintf(num_str,"%02X", ch);
                      str[ii++] = num_str[0];
                      str[ii++] = num_str[1];
                  }
                
            } /* k */
          str[ii++] = ' ';
      }
    di += 16;
    str[di] = '\0';
    return(di);
}
    

int analyse_line(unsigned char *beg, unsigned char *end, char *out, char *attributes)
{
    int test, ii, fold, ii_max, j, ok;
    unsigned char ch,attr;

    test = 0;
    ii = 0;
    ii_max = 0;
    fold = 0;
    while(ch = *beg, (beg <= end) && (ch != '\n') && (ch != '\0'))
      {
          beg++;
          if (ii > ii_max) fold = 0;  /* beyond previous high */
          attr = ' ';
          if (!MOST_V_OPT && ch == '\015')                   /* ^M */
            {
                if (beg <= end)
                  {
                      fold = 1;
                      if (ii > ii_max) ii_max = ii - 1; /* ^M contributes nil */
                      ii = 0;
                  }
            }
          else if (!MOST_V_OPT && ch == '\b')
            {
                test = 1;
                ii--;
            }
          else if (test || fold)
            {
                test = 0;
                if (ch == out[ii])
                  attr = 'b';
                else if (out[ii] == '_')
                  attr = 'u';

                if (fold && ch == ' ')
                  ii++;
                else
                  {
                      attributes[ii] = attr;
                      out[ii++] = ch;
                  }
                
            }
          else if (!MOST_T_OPT && ch == '\t')
            {
                j = 8 * (ii/8 + 1) - ii;  /* 8 column tabs */
                while(j--)
                  {
                      out[ii] = ' ';
                      attributes[ii++] = attr;
                  }
            }
          else
            {
                out[ii] = ch;
                attributes[ii++] = attr;
            }
      }
    if (fold) ii = ii_max + 1;
    if ((beg > end) && MOST_S_OPT && !MOST_W_OPT)
      {
          ok = 1;
          if (*beg == '\n') beg++;
          while ((*beg <= ' ') && ok)
            {
                if (*beg != '\n') beg++;
                if (beg >= EOB) break;
                if ((*beg == '\n') || (apparant_distance(beg) >= MOST_S_OPT))
                  {
                      ok = 0;
                  }
            }
          if (!ok)
            {
                ok = 3;
                while(ok--)
                  {
                      out[ii] = '.'; 
                      attributes[ii++] = ' ';
                  }
            }
          
      } /* MOST_S_OPT */
    out[ii] = '\0';
    return(ii);
}


void output(char *line, int len, char *attr, char d_char)
{
    int
      i,ii,k, bold,b_len,n_len, s_len, u_len, work_len, j, mark, ok, quit,
      count, max_col, save, dollar;
    char ch, at, out[500], *n_str, *b_str, *s_str, *u_str, work[20];

    b_str = "\033[1m"; n_str = "\033[0m"; s_str = "\033[%dC"; u_str = "\033[4m";
    b_len = strlen(b_str);
    n_len = strlen(n_str);
    u_len = strlen(u_str);
    s_len = strlen(s_str);
    i = 0;
    ii = 0;
    bold = 0;
    quit = 0;
    ok = 0;  /* 1 if ok to start filling the out line */
    max_col = COLUMN + SCREEN_WIDTH - 1;
    count = 0;
    dollar = 0;
    while (ch = line[i], (i <= len) && ch != '\0' && ch != '\n' && !quit)
      {
          count++;
          if (MOST_V_OPT && ((ch < ' ') || (ch > 126))) count++;
          
          if (count >= COLUMN) ok = 1;
          if (count > max_col) break;
          
          if (!MOST_V_OPT)
            {
                at = attr[i];
                if ((at != ' ') && !bold)
                  {
                      bold = 1;
                      /* u and b have same length */
                      if (ok) for (j = 0; j < b_len; j++)
                        {
                            if (at == 'b') out[ii++] = b_str[j];
                            else out[ii++] = u_str[j];
                        }
                      
                  }
                else if ((at == ' ') && bold)
                  {
                      bold = 0;
                      if (ok) for (j = 0; j < n_len; j++) out[ii++] = n_str[j];
                  }
            }
          
          if (ch == ' ')
            {
                j = 0;
                mark = ii;
                /* we always make this loop once */
                while ((i <= len) && (line[i++] == ' '))
                  {
                      j++;
                      if (ok) out[ii++] = ' ';
                  }
                if (i > len) quit = 1;
                i = i - 2;
                save = count;
                count += j - 1;  /* counted one at top of while */

                if (!ok)
                  {
                      if (count >= COLUMN)
                        {
                            ok = 1;
                            j = count - COLUMN + 1;
                            k = j;
                            while (k--) out[ii++] = ' ';
                        }
                  }
                
                if (count >= max_col)
                  {
                      quit = 1;
                      j = max_col - save;
                  }
                
                if (ok && (j > s_len)) 
                  {
                      ii = mark;
                      sprintf(work,s_str,j);
                      work_len = strlen(work);
                      for (j = 0; j < work_len; j++) out[ii++] = work[j];
                      if (count >= max_col) dollar = ii++;
                  }
                else if (count >= max_col)
                  {
                      dollar = mark + j;
                  }
                
            }
          else if (ok && ((ch == '\014') || ((ch < ' ') && MOST_V_OPT)))
            {
                out[ii++] = '^';
                out[ii++] = ch + 'A' - 1;
            }
          else if (ok) 
            {
                out[ii++] = ch;
            }
          
          i++;
      }
    if (dollar) out[ii = dollar, ii++] = d_char;
    else if (ok && count >= max_col) out[ii - 1] = d_char;
    out[ii] = '\0';
    if (ii) fputs(out,stdout);
    
    if (ok && bold) fputs(n_str,stdout);
}


void display_line()
{
    unsigned char *beg, *end;
    int i, len, v, t;
    char buff[16];
    char the_line[MAX_LINE_LEN],  *p, the_attr[MAX_LINE_LEN], *line,*attr, ch;
    line = the_line;
    attr = the_attr;
    /* This needs fixed for files with really big lines */
    if (!MOST_B_OPT)
      {
          if(extract_line(&beg, &end) && MOST_W_OPT) ch = '\\'; else ch = '$';
          
          len = end - beg + 1;
          if (len > MAX_LINE_LEN)
            {
                v = MOST_V_OPT;
                t = MOST_T_OPT;
                MOST_V_OPT = 1;
                MOST_T_OPT = 1;
                line = (char *) beg;
            }
          else len = analyse_line(beg, end, line, attr);
      }
    else
      {
          ch = '$';
          i = 0;
          beg = C_POS;
          end = C_POS + 16;
          if (end > EOB) end = EOB;
          while(beg < end) buff[i++] = (char) *beg++;
          while(i < 15) buff[i++] = 0;
          len = ascii_format_line(buff,the_line);
          i = 0; while(i<80) attr[i++] = ' ';
      }
    
    
    output(line,len,attr, ch);
    if (len > MAX_LINE_LEN)
      {
          MOST_V_OPT = v;
          MOST_T_OPT = t;
      }
}


/* given a position in a line, return apparant distance from bol
   expanding tabs, etc... up to pos */
int apparant_distance(unsigned char *pos)
{
    int i;
    unsigned char *cur_pos, *save_pos, ch;
    cur_pos = C_POS;
    save_pos = pos;
    C_POS = pos;
    pos = beg_of_line();
    C_POS = cur_pos;

    i = 1;
    while(ch = *pos, pos++ < save_pos)
      {
          if (!MOST_V_OPT && ch == '\b')
            {
                if (i > 1) i--;
            }
          else if (!MOST_V_OPT && ch == '\015') /* ^M */
            {
                if (i != 1) i = 1;
            }
          else if (!MOST_T_OPT && ch == '\t')
            {
                i = 8 * ((i - 1)/8 + 1) + 1;  /* 8 column tabs */
            }
          else if (ch < ' ' || ch > 126)
            {
                if (ch == '\012' || MOST_V_OPT)  /* ^L */
                  {
                      i += 2;
                  }             /* otherwise they have no width */
            }
          else i++;
      }
    return (i);
}




