
/*
  *  constream.cc , v 0.4 1996/05/02
  *
  * 
  *  o  based on NCurses
  *  o  OO - Designed and Implemented
  *  o  redirects the outputstream to the screen using the
  *     ostream interface  
  *  o  compatible with the constream interface of Borlands 
  *     C++ DOS package 
  *
  *
  *  Copyright (c) 1996 Dipl.-Ing.,Dipl.-Ing.(FH)  Jurgen Eidt
  *  All rights reserved.  
  *  GPL-Copying-policy.
  *  
  *  Redistribution and use in source and binary forms are permitted
  *  provided that the above copyright notice and this paragraph are
  *  duplicated in all such forms and that any documentation,
  *  advertising materials, and other materials related to such
  *  distribution and use acknowledge that the software was developed
  *  by Jurgen Eidt.  The name may not be used to endorse or promote 
  *  products derived from this software without specific prior written 
  *  permission.
  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  *  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  *  WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
  * 
  *  	Jurgen Eidt
  *  	Dromersheimer Str. 2
  *  	D-55411 Bingen am Rhein
  *     Germany
  * 
  *  	E-Mail: jurgen@tap.de 
  *  	FidoNet: 2:2455/240.25
  * 
*/

#include"constream.h"


// the variable is used to determine
// if color is available or not
int ncc, cpairs;         

// If this Counter is 0 when the Destructor is called,
// it's time to clean up NCurses
int noCleanUp = 0;
unsigned long CtorCnt = 0;


inline int conbuf::overflow(int ch)
{
  // flush conbuf to the target
  int n = pptr() - pbase();
  if(n)
    return EOF;

  // now print the stream
  if(ch != EOF)
  {
    if(ncc && !(ch == '\n'))
      waddch(Fenster, ((chtype)ch) | mask | COLOR_PAIR( ( (chtype)(bg<<3) | fg) ));
    else
      waddch(Fenster, ((chtype)ch) | mask);     // no use of actual colorpair

    // for performance reason, no refresh is done         
    return 0;
  }
  pbump(-n);	// resize the Buffer
  return 0;
}


void conbuf::clrscr(chtype ch)
{
  mask = A_NORMAL;

  if(isInit)
  {
    wfg = fg;	        // the first assigned colors will be used
    wbg = bg;	        // for future clrscr's
    isInit = 0;	        // ok, don't run into this the next time :-)
  }
  if(ncc)
    // sets the background character
    wbkgd(Fenster, ch | COLOR_PAIR(((wbg << 3) | wfg)));

  werase(Fenster);
  wrefresh(Fenster);
  wmove(Fenster, 0, 0);
}


void conbuf::reset()
{
  // restore the color and resets the attributes 
  mask = A_NORMAL;

  fg = wfg;	
  bg = wbg;

  wrefresh(Fenster);
}


void conbuf::window(int x_1, int y_1, int x_2, int y_2)
{
  // if not in range, use defaults (1, 1, COLS, LINES) 
  if(x_2<=x_1 || y_2<=y_1)
    return;
  if(x_1<1) x1 = 1; else if(x_1>COLS) return; else x1 = x_1; 
  if(x_2<1) return; else if(x_2>COLS) x2 = COLS; else x2 = x_2; 
  if(y_1<1) y1 = 1; else if(y_1>LINES) return; else y1 = y_1; 
  if(y_2<1) return; else if(y_2>LINES) y2 = LINES; else y2 = y_2; 
    
  delwin(Fenster);
  Fenster = newwin(h = (y2-y1+1), b = (x2-x1+1), y1-1, x1-1);
  scrollok(Fenster, TRUE);	// '\n' scrolls up a line
  wrefresh(Fenster);
}


void conbuf::NCursesInit()
{
  // check for NCurses, if the Statics LINES and COLS are 0,
  // NCurses is not initalized
  if(!(LINES || COLS))
  {
    initscr();

    if(!has_colors())   // ncc stands for  N_Curses_Color  :-)
      ncc = 0;          // 1: color available
    else                // 0: no colors
    {
      ncc = 1;    
      start_color();       
    }

    // normal setup procedure for the curses ...     
    keypad(stdscr, TRUE);
    nocbreak();
    noecho();
    erase();
  }
  else
    if(!CtorCnt)
      noCleanUp = 1;      // Another Program initialized NCurses

  // Init of the colorpairs, even when another program initialize
  // NCurses
  // we have 64 Colorpairs and 8 Colors (3 bit)
  if(!cpairs)
  {
    if(COLOR_PAIRS < 64)        // 8x8 = 2^3 x 2~3 = 2^6 = 64
      ncc = 0;
    else
      for(unsigned int b = 0; b < 8; b++)
        for(unsigned int f = 0; f < 8; f++)
          if(f != 7  ||  b != 0)
            init_pair(((b << 3) | f), f, b);

    cpairs = 1; // the first constructor call initialize the colormap
  }
}  


conbuf::conbuf()
{ 
  NCursesInit();
  CtorCnt++;

  Fenster = NULL;
  isInit = 1;
  wbg = bg = BLACK;	// defaultcolor: white on black
  wfg = fg = WHITE; 
  mask = A_NORMAL;      // reset all Attributes
  doallocate(); 	// allocate mem for streambuf
}


conbuf::~conbuf()
{
  CtorCnt--;
  
  // if no conbuf's there and no other Program did the 
  // initialization of NCurses, it's safe to clean up
  if(!CtorCnt && !noCleanUp)
  {
    // clean up NCurses  
    erase();
    refresh();
    endwin();
  }
}


int constream::wherex()
{
  int x, y;
  getyx(Fenster, y, x); 
  return x;
}


int constream::wherey()
{
  int x, y;
  getyx(Fenster, y, x); 
  return y;
}


ostream& flush(ostream& os)
{
  wrefresh(((constream&)os).Fenster);
  return (constream&)os;
}


ostream& endl(ostream& os)
{
  os.put('\n'); os.put('\r');
  flush(os);
  return os;
}


ostream& clreol(ostream& os)
{
  wclrtoeol(((constream&)os).Fenster);
  wrefresh(((constream&)os).Fenster);
  return os;
}


ostream& delline(ostream& os)
{
  wdeleteln(((constream&)os).Fenster);
  wrefresh(((constream&)os).Fenster);
  return os;
}

ostream& highvideo(ostream& os)
{
  ((constream&)os).mask |= A_BOLD;  
  wrefresh(((constream&)os).Fenster);
  return os;
}


ostream& insline(ostream& os)
{
  winsertln(((constream&)os).Fenster);
  wrefresh(((constream&)os).Fenster);
  return os;
}


ostream& lowvideo(ostream& os)
{
  ((constream&)os).mask &= ~(A_DIM | A_BOLD);  
  wrefresh(((constream&)os).Fenster);
  return os;
}


ostream& normvideo(ostream& os)
{
  ((constream&)os).mask &= ~A_BOLD;  
  wrefresh(((constream&)os).Fenster);
  return os;
}


ostream& blinkon(ostream& os)
{
  ((constream&)os).mask |= A_BLINK;  
  wrefresh(((constream&)os).Fenster);
  return os;
}


ostream& blinkoff(ostream& os)
{
  ((constream&)os).mask &= ~A_BLINK;  
  wrefresh(((constream&)os).Fenster);
  return os;
}


ostream& reverseon(ostream& os)
{
  ((constream&)os).mask |= A_REVERSE;  
  wrefresh(((constream&)os).Fenster);
  return os;
}


ostream& reverseoff(ostream& os)
{
  ((constream&)os).mask &= ~A_REVERSE;  
  wrefresh(((constream&)os).Fenster);
  return os;
}


ostream& reset(ostream& os)
{
  // restore the color and resets the attributes 
  ((constream&)os).mask = A_NORMAL;
  ((constream&)os).fg = ((constream&)os).wfg;
  ((constream&)os).bg = ((constream&)os).wbg;

  wrefresh(((constream&)os).Fenster);
  return os;
}


ostream& underlineon(ostream& os)
{
//  ((constream&)os).mask |= A_UNDERLINE;  
//  wrefresh(((constream&)os).Fenster);
  return os;
}


ostream& underlineoff(ostream& os)
{
//  ((constream&)os).mask &= ~A_UNDERLINE;  
//  wrefresh(((constream&)os).Fenster);
  return os;
}


ostream& _setclr(ostream& os, int i)
{
  ((constream&)os).fg = i & 0x07;
  wrefresh(((constream&)os).Fenster);
  return os;
}


CNSTRMmanip_arg<int> setclr(int i)
{
  return CNSTRMmanip_arg<int>(&_setclr, i);
}


ostream& _setbk(ostream& os, int i)
{
  ((constream&)os).bg = i & 0x07;
  wrefresh(((constream&)os).Fenster);
  return os;
}


CNSTRMmanip_arg<int> setbk(int i)
{
  return CNSTRMmanip_arg<int>(&_setbk, i);
}


ostream& _setattr(ostream& os, int i)
{
  ((constream&)os).fg = i & 0x07;
  ((constream&)os).bg = (i & 0x70) >> 4;
  wrefresh(((constream&)os).Fenster);
  return os;
}


CNSTRMmanip_arg<int> setattr(int i)
{
  return CNSTRMmanip_arg<int>(&_setattr, i);
}


ostream& _setcrsrtype(ostream& os, int i)
{
  // i==0 -> curser invisible
  // i==1 -> cursor normal
  // i==2 -> cursor visible
  curs_set(i);
  wrefresh(((constream&)os).Fenster);
  return os;
}


CNSTRMmanip_arg<int> setcrsrtype(int i)
{
  return CNSTRMmanip_arg<int>(&_setcrsrtype, i);
}


ostream& _setxy(ostream& os, int x, int y)
{
  // do a setxy(...) only if it fits in the assigned window
  if(y > 0  &&  y <= ((constream&)os).h  
     &&  x > 0  &&  x <= ((constream&)os).b)  
  {
    wmove(((constream&)os).Fenster, y-1, x-1);
    wrefresh(((constream&)os).Fenster);
  } 
  return os;
}


CNSTRMmanip_arg_arg<int> setxy(int x, int y)
{
  return CNSTRMmanip_arg_arg<int>(&_setxy, x, y);
}
