/*****************************************************************

This is a console implementation of the display class for the 
CES system. This sets up a VIF (Visual interface, 
Verry Important Force, or Verry Important For.us, if you like.

ALL display output should happen from this code.

This uses the conio hack for linux, which uses ncurses. If you have
  another library or protocoll that can be put in the middle, please 
  conatact me.

In order to create a multiple window scenario, this code needs to be 
  re-organized such that multiple instances can happily co-exist.

version III

Class info:

 public:

  long int Height; //  'window' height
  long int Width;   // 'window' width

  void CursorPos ( int64_t X, int64_t Y );            // position the cursor for a writeline
  void VIF::WriteText ( char * text );
  void WriteText ( char * text, char * properties);   // write text. starts from cursorpos

modifications:

  sep 27 2001. removed clearline, adding colour support DW
  oct 17 2001. tested code, added commented out buffering system DW
  dec 20 2001. added version of writeline thats backwards compatible DW
  mar 05 2002. moved class decleration to header file. DW
  jul 04 2002. added buffer system. DW
  Aug 02 2002. new data types. DW
  Apr 08 2003. attempt to optimize coloured redrawing. DW

*****************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include "vif.h"

/*
class VIF {

 public:

  long int Height; //  'window' height
  long int Width;   // 'window' width

  VIF();                                              // constructor
  void CursorPos ( int64_t X, int64_t Y );            // position the cursor for a writeline
  void VIF::WriteText ( char * text );
  void WriteText ( char * text, char * properties);   // write text. starts from cursorpos
  ~VIF();                                             // destructor

};

*/

/***************************************************
*
*  Create a cleared, ready, whole screen window.
*
***************************************************/
 
VIF::VIF ( void ) {
  
  struct text_info info;
  int64_t          i;
  
  initconio ();
  gettextinfo ( &info );
  Height = info.screenheight; 
  Width  = info.screenwidth; 
  clrscr();
  gotoxy( 1, 1 );
  
  // set buffersize
  BUFFLEN = (Height * Width) + 1;
  //printf("buffer size is %ld ", BUFFLEN);
  // allocate memory for character buffer
  if (( BuffText = new char[BUFFLEN]) == NULL ) {
    
    //      !!!???!!! CHANGE THIS
    
    printf("vif cannot allocate text buffer, bailing\n");
    exit(0); // 
  }
  // allocate memory for property buffer
  if ((BuffProp = new char[BUFFLEN]) == NULL ) {
    
    //      !!!???!!! CHANGE THIS
    
    printf("vif cannot allocate property buffer, bailing \n");
    delete[] BuffText;
    exit(0);
  }
  // clear buffers
  for (i=0; i<BUFFLEN; i++) {
    BuffText[i] = ' ';
    BuffProp[i] = 7; // White on Black by default
  }
  BuffText[BUFFLEN] = '\0';
  // preset Buffer Pointer
  BuffPtr = 0;
  
}

// position the cursor. This is used before doing a writetext.
void VIF::CursorPos ( XDim_t X, YDim_t Y ) {
 
   XDim_t x = X;
   YDim_t y = Y;
 
   if ( X > Width ) x = Width;
   if ( X < 1 ) x = 1;
 
   if ( Y > Height ) y = Height;
   if ( Y < 1 ) y = 1;
 
   gotoxy( x, y );
 }


/*********************************************************
 *
 * Backwards compatible WriteText with no attributes.
 *
 ********************************************************/
 void VIF::WriteText ( char * text ) {
   WriteText ( text, NULL);
 }

/*********************************************************
 *
 * Properties are defined as those in textattr() for dos.(
 *  no, I dont know either)
 * Writes the data directly to the screen
 *
 ********************************************************/
void VIF::WriteText ( char * text, char * properties) {
  
  char * character;
  char * property;
  char   curProp; // current property
  
  character = text;
  property  = properties;	
  curProp   = 7;   // white on black by default
  
  if (property != NULL) {	
    while ( *(character) != '\0' ) {
      if (curProp != *(property)) {
	      curProp = *(property);
	      textattr ( curProp );
      }		 
      cprintf ( "%c", *character );	 // needs some optimization right here... 
      character++;
      property++;
    }
  } else {
    cprintf ("%s", character);
    // 
  } 
}

//// experimental
// the idea is to buffer up all characters witht eh same properties and 
// print them all at once. its a weak optimization to a bad process.
/*
void VIF::WriteBlock ( char * text, char  property) {
  
  if (properties != NULL) {
     textattr (property);
	  cprintf ( "%s", text );
   
  } else {
    cprintf ("%s", text);
    // 
  } 
}
*/

/*****************************************************************
 *
 * Should be a equiv of WriteText accept for being to a buffer.
 * In theroy, there should be no linefeeds (or for that matter
 *  tabs) in the text.
 *
 ****************************************************************/
 void VIF::BufferText (char * text, char * properties) {
	
	strncpy( BuffText + BuffPtr, text, MIN (strlen(text), (BUFFLEN - BuffPtr)));
	// printf("copying %ld bytes\n", MIN (strlen(text), BUFFLEN));
	if ( properties != NULL) {
	    memcpy( BuffProp + BuffPtr, properties, MIN (strlen(text), (BUFFLEN - BuffPtr)));
	}
	
	BuffPtr = BuffPtr + strlen(text);
	
 }

/**************************************************************
 *
 * Get text/attribute from the buffer. Start loc is cursor pos,
 *  does not modify cursor position.
 * 
 *************************************************************/
void VIF::GetBuffer (char * text, char * properties, long int N) {

  strncpy (text, BuffText + BuffPtr, MIN( N, (BUFFLEN - BuffPtr)));
  memcpy  (properties, BuffProp + BuffPtr, MIN( N, (BUFFLEN - BuffPtr)));

}


/**************************************************************
 *
 * Position the buffer cursor. This should act like a 
 *  regular cursor.
 *
 *************************************************************/
 void VIF::BufferPos ( XDim_t X, YDim_t Y ) {
 
   XDim_t x = X;
   YDim_t y = Y;
 
   if ( X > Width ) x = Width;
   if ( X < 1 ) x = 1;
 
   if ( Y > Height ) y = Height;
   if ( Y < 1 ) y = 1;
 
   BuffPtr = ((y - 1) * Width) + (x - 1);
	
 }
 
/***************************************************************
 *
 * Update the screen with whatever is in BuffText.
 * Lines are writen individually because of issues with window
 * compatibility and ... (its 2am...)
 *
 *
 **************************************************************/
 void VIF::ReDraw ( void ) {

   long int x, y;
   char* ttext; // move these to main dec...
   char* tprop;
 
   if ((ttext = new char[Width+2]) == NULL) {

     //          !!!???!!! CHANGE THIS

     printf ("vif.draw cannot allocate character buffer, bailing\n");
     exit(0);
   }
   if ((tprop = new char[Width+2]) == NULL) {
 
     //          !!!???!!! CHANGE THIS

     printf ("vif.draw cannot allocate property buffer, bailing\n");
     delete[] ttext;
     exit(0);
   }

   x=0;
   for (y=1; y<Height; y++) {
     gotoxy(1, y);
     strncpy(ttext, BuffText+x, Width);
     ttext[Width] = '\0';
     memcpy(tprop, BuffProp+x, Width);
     tprop[Width] = '\0';
     WriteText (ttext, tprop );
     x+=Width;
   }
   
   /*
   //experimental {
   for (y=1; y<Height; y++) {
     gotoxy(1, y);
     
     loup {
     end = strrchr(BuffProp+x, currprop);
     
  //   strncpy(ttext, BuffText+x, Width);
   //  ttext[Width] = '\0';
   //  memcpy(tprop, BuffProp+x, Width);
   //  tprop[Width] = '\0';
     
     WriteText (ttext, tprop );
     x+=Width;     
     }
     
   }
   
   // experimental }
  */ 
   
   
   //   WriteText ( BuffText, BuffProp );
	
   delete[] ttext;
   delete[] tprop;
 }
 
 
 //clean up
 VIF::~VIF() {
   delete[] BuffText;
   delete[] BuffProp;
   doneconio();
 } 
  














