#include <stdio.h>
#include "buffer.h"  
#include "display.h"  
#include "sysdep.h"  

int SCREEN_WIDTH = 80;
int SCREEN_WIDTH_M1 = 79;
int SCREEN_HEIGHT = 24;
int SCREEN_ROWS = 23; /* height - 1 */

extern int MOST_L_OPT;

char *INS_MODE_STR = "\033[4h";   /* ins mode (im) */
char *EINS_MODE_STR = "\033[4l";  /* end ins mode (ei) */
char *SCROLL_R_STR = "\033[%d;%dr"; /* scroll region */
char *CLS_STR = "\033[2J\033[H";  /* cl termcap STR  for ansi terminals */
char *CLR_BOS_STR = "\033[1J";   /* erase to beg of screen */
char *REV_INDEX_STR = "\033M";     /* sr termcap string */
char *REV_VID_STR = "\033[7m";    /* mr,so termcap string */
char *BOLD_VID_STR = "\033[1m";    /**/
char *UNDL_VID_STR = "\033[4m";    /**/
char *NORM_VID_STR = "\033[m";   /* me,se termcap string */
char *DEL_BOL_STR = "\033[1K\r";  /* cb termcap entry */
char *DEL_EOL_STR = "\033[K"; 
char *HOME_CURS_STR = "\033[H";   /* ho termcap string */
char *DEL_LINE_STR = "\r\033[K";   /* dl termcap string except cursor at bol */
char *DEL_CHAR_STR = "\033[P";   /* dc */
char *DEL_N_LINES_STR = "\033[%dM";  /* DL */
char *ADD_N_LINES_STR = "\033[%dL";  /* AL */
char *CURS_F_STR = "\033[%dC";    /* RI termcap string */
char *CURS_B_STR = "\033[%dD";    /* RI termcap string */
char *CURS_U_STR = "\033[%dA";    /* RI termcap string */
char *CURS_D_STR = "\033[%dB";    /* RI termcap string */
/* cm string has %i%d since termcap numbers columns from 0 */
/* char *CURS_POS_STR = "\033[%d;%df";  ansi-- hor and vert pos */
char *CURS_POS_STR = "\033[%d;%dH";   /* cm termcap string */


void set_scroll_region(int r1, int r2)
{
    fprintf(stdout,SCROLL_R_STR,r1,r2);
}

void goto_rc(int r, int c)
{
    fprintf(stdout,CURS_POS_STR,r,c);
}
void curs_bol()
{
    fputc('\015',stdout);
}

void cursor_forward(int n)
{
    fprintf(stdout,CURS_F_STR,n);
}

void cursor_backward(int n)
{
    fprintf(stdout,CURS_B_STR,n);
}

void cursor_up(int n)
{
    fprintf(stdout,CURS_U_STR,n);
}

void cursor_down(int n)
{
    fprintf(stdout,CURS_D_STR,n);
}

void begin_insert()
{
    fputs(INS_MODE_STR,stdout);
}

void end_insert()
{
    fputs(EINS_MODE_STR,stdout);
}

void delete_char()
{
    fputs(DEL_CHAR_STR,stdout);
}

void delete_line(int n)
{
      fprintf(stdout,DEL_LINE_STR);
}

void delete_nlines(int n)
{
    if (n) fprintf(stdout,DEL_N_LINES_STR,n);
}

void clr_bos()   /* delete to beg of screen */
{
    fputs(CLR_BOS_STR,stdout);
}

void set_attribute(int attr)
{
    fprintf(stdout,"\033[%dm",attr);
}

void cls()
{
    fputs(CLS_STR,stdout);
}

void reverse_index(int n)
{
    while(n--)
      fputs(REV_INDEX_STR,stdout);
}

/* assumes both old and new are the same length */
smart_puts(char *new,char *old,FILE *fp)
{
    char out[250], ch, ch1;
    int ii,max_len,i,mark;

    i = 0;
    ii = 0;
    while(ch = *new++, ch1 = *old++, (ch == ch1) && (ch != '\0')) i++;
    if (ch == '\0') return;

    max_len = strlen(CURS_F_STR);
    if (i) fprintf(fp, CURS_F_STR, i);

    while(1)
      {
          i = 1; ii = 0;
          out[ii++] = ch;
          while (ch = *new++, ch1 = *old++, ch != ch1 && ch != '\0') out[ii++] = ch;
          mark = ii;
          out[ii++] = ch;
          while (ch = *new++, ch1 = *old++, ch == ch1 && ch != '\0')
            {
                i++;
                out[ii++] = ch;
            }
          out[ii] = '\0';
          if (ii > max_len)
            {
                out[mark] = '\0';
                fputs(out,fp);
                if (ch == '\0') return;
                if (i) fprintf(fp, CURS_F_STR, i);
            }
          else
            {
                fputs(out,fp);
                if (ch == '\0') return;
            }          
      }    
}    
    

#ifndef VMS
/*  This routine may be problematic when there are more windows than
    the new screen size can support.  Until I think of what to do,
    I  have not touched this routine. */
void resize_display()
{
    char c;

    get_term_dimensions(&SCREEN_WIDTH, &SCREEN_HEIGHT);
    if (SCREEN_WIDTH == 0) SCREEN_WIDTH = 80;
    if (SCREEN_HEIGHT == 0) SCREEN_HEIGHT = 24;
    SCREEN_ROWS = SCREEN_HEIGHT - 1;
    SCREEN_WIDTH_M1 = SCREEN_WIDTH - 1;
    c = 'R';   /* force a redraw of screen */
    ioctl(0,TIOCSTI,&c);
}
#endif

void get_terminfo()
{

#ifndef VMS
    (void) signal(SIGWINCH,resize_display); 
#endif
    
    get_term_dimensions(&SCREEN_WIDTH, &SCREEN_HEIGHT); 
    if (SCREEN_WIDTH == 0) SCREEN_WIDTH = 80;
    if (SCREEN_HEIGHT == 0) SCREEN_HEIGHT = 24;
    SCREEN_ROWS = SCREEN_HEIGHT - 1;
    SCREEN_WIDTH_M1 = SCREEN_WIDTH - 1;

    /* someday I will add something here for non-dec terminals
       perhaps a 'most-cap' terminal entry :^)

       For the time being we do it in this rather primitive manner */

    if (MOST_L_OPT)   /* dumb terminal */
      {
          CLS_STR = "\014";  /* a formfeed */
          REV_INDEX_STR = "";
          REV_VID_STR = "";
          BOLD_VID_STR = "";    /**/
          UNDL_VID_STR = "";    /**/
          NORM_VID_STR = "";
          HOME_CURS_STR = "";
          DEL_LINE_STR = "";
          DEL_BOL_STR = DEL_LINE_STR;  /* for our purposes */
          CURS_F_STR = "";
          CURS_POS_STR = "";
      }
    
}



void narrow_width()
{
    fputs("\033[?3l",stdout);
}

void wide_width()
{
    fputs("\033[?3h",stdout);
}


void set_width(int width, int redraw)
{
#ifdef VMS
    short fd;
    int status;
    iosb iostatus;
    static termchar tc; /* Terminal characteristics   */
    $DESCRIPTOR( devnam, "SYS$ERROR");
#else
    struct winsize wind_struct;
#endif      

    /* Switching physical terminal to narrow/wide mode.*/
          
    if(width<=80)
      {
          width = 80;
          narrow_width();
      }
    else
      {
          width = 132;
          wide_width();
      }
    SCREEN_WIDTH = width;
    SCREEN_WIDTH_M1 = width - 1;
    
#ifdef VMS
    /* Assign input to a channel */
    status = sys$assign(&devnam, &fd, 0, 0);
    if ((status & 1) == 0)
      exit(status);
    /* Get current terminal characteristics */
    status = sys$qiow(          /* Queue and wait   */
                      0,        /* Wait on event flag zero  */
                      fd,       /* Channel to input terminal  */
                      IO$_SENSEMODE, /* Get current characteristic */
                      &iostatus, /* Status after operation */
                      0, 0,     /* No AST service   */
                      &tc,      /* Terminal characteristics buf */
                      sizeof(tc), /* Size of the buffer   */
                      0, 0, 0, 0); /* P3-P6 unused     */
    
    /*set terminal characteristics */
    tc.t_width=width;
    status = sys$qiow(           /* Queue and wait   */
                      0,           /* Wait on event flag zero  */
                      fd,           /* Channel to input terminal  */
                      IO$_SETMODE,   /* Get current characteristic */
                      &iostatus,       /* Status after operation */
                      0, 0,            /* No AST service   */
                      &tc,             /* Terminal characteristics buf */
                      sizeof(tc),      /* Size of the buffer   */
                      0, 0, 0, 0);     /* P3-P6 unused     */
    
    if( (sys$dassgn(fd)  & 1)==0)
      exit(status);

    /* here we redraw the screen, on unix, we assume that the terminal
       driver sends the appropriate signal that most catches to redraw so we
       do not redraw because it is likely that screen will be redrawn twice */

    if (redraw) redraw_display();
#else
    /* this may need work on other unix-- works for sun4 */
    ioctl(2,TIOCGWINSZ,&wind_struct);
    wind_struct.ws_col = width;
    ioctl(2,TIOCSWINSZ,&wind_struct);
    
#endif /* VMS */
}



