/*
  Video.c, Copyright  (c) by Lukas Ruf, lr@lpr.ch,
  Swiss Federal Institute of Technology,
  Computer Engineering and Networks Laboratory.
 
  TOPSY -- A Teachable Operating System.
           Implementation of a tiny and simple
           micro kernel for teaching purposes.
 
  For further information, please visit http://www.tik.ee.ethz.ch/~topsy
 
  This software is provided under the terms of the GNU General Public Licence.
 
  A full copy of the GNU GPL is provided in the file COPYING found in the 
  development root of Topsy.
*/
/*
	File:                  $Source: /home/ruf/cvs_Topsy/cvs/Topsy/IO/ia32/Drivers/Video.c,v $
	Author(s):             Lukas Ruf, lr@lpr.ch
	Affiliation:           ETH Zuerich, TIK
	Version:               $Revision: 3048 $
	Creation Date:         
	Last Date of Change:   $Date: 2007-07-20 18:11:54 +0200 (Fre, 20 Jul 2007) $      by: $Author: sryffel $
*/

//-CJ #include "Tools.h"
#include "Lock.h"
#include "Video.h"
#include "video.h"
#include "SupportAsm.h"

/* This needs being included for resolving the "variable argument list" */
#include <stdarg.h>

#include "tm-include.h"
#include "Support.h"

#define   KILO  1024

static VideoT AtCursor;
static WindowT vWindow;

#define V_IOBUFFERSIZE KILO
#define DEBUG_W_VIDEO
#define DEBUG_W_CONTEXT

//-CJ static char vIOBuffer[V_IOBUFFERSIZE];
//-CJ static char vIODebugBuffer[V_IOBUFFERSIZE];
static long vMutex;

#define PRINTLOCK 0
#define DEBUGLOCK 1
#define OUTPUTLOCK 2
#define KPRINTLOCK 3

//-LR asm(".section .bincat");

void VideoInit()
{
  vWindow.X1 = 0;
  vWindow.Y1 =  0;
  vWindow.X2 = 79;
  vWindow.Y2 = 23; // preserve space for status line
  AtCursor.X = vWindow.X1;
  AtCursor.Y = vWindow.Y1;
  AtCursor.TextAttr = 0x1F;
  vMutex = 0;
  return;
}

void Printstr(long pY, long pX, char pTextAttr, char *ps)
{
  long lXY = pY*80*2 + pX*2;
  if (ps)
    for (;(*ps && (lXY < 3999));ps++)
    {
      __printchar(lXY,pTextAttr,(char)*ps);
      lXY+=2;
    }
  return;
}

unsigned char TextAttr(unsigned char pNewAttr)
{
  char xold = AtCursor.TextAttr;
  AtCursor.TextAttr = pNewAttr;
  return xold;
}

void GotoYX(char pY, char pX)
{
  pY += vWindow.Y1;
  pX += vWindow.X1;
  AtCursor.Y = pY % (vWindow.Y2+1);
  AtCursor.X = pX % (vWindow.X2+1);
  return;
}

unsigned char GetTextAttr()
{
  return AtCursor.TextAttr;
}

void WhereYX(char *pY, char *pX)
{
  *pY = AtCursor.Y;
  *pX = AtCursor.X;
  return;
}

void WindowState(char *pY1, char *pX1, char *pY2, char *pX2, char *pAttr)
{
  *pY1 = vWindow.Y1;
  *pX1 = vWindow.X1;
  *pY2 = vWindow.Y2;
  *pX2 = vWindow.X2;
  *pAttr = AtCursor.TextAttr;
  return;
}

void Window(char pY1, char pX1, char pY2, char pX2)
{
  pY1 %= 24;
  pX1 %= 80;
  pY2 %= 24;
  pX2 %= 80;
  if ((pY2 > pY1) && (pX2 > pX1))
  {
    vWindow.Y1 = pY1;
    vWindow.X1 = pX1;
    vWindow.Y2 = pY2;
    vWindow.X2 = pX2;
    AtCursor.X = vWindow.X1;
    AtCursor.Y = vWindow.Y1;
  }
  return;
}

void ClearScreen()
{
  long y;
  for (y = vWindow.Y1; (y <= vWindow.Y2); y++)
    __clearLine((y*80+vWindow.X1) << 1, vWindow.X2-vWindow.X1 + 1,
                AtCursor.TextAttr);
  AtCursor.X = vWindow.X1;
  AtCursor.Y = vWindow.Y1;
  return;
}

void SaveScreen(char *pBuff, char pY1, char pX1, char pY2, char pX2)
{
  long y;
  pX1 %= 80;
  pY1 %= 24;
  pX2 %= 80;
  pY2 %= 24;
  for (y = pY1; (y <= pY2); y++)
    __getWindowLine(&(pBuff[(y-pY1)*(pX2-pX1+1)*2]),(y*80+pX1)<<1, pX2-pX1+1);
  return;
}

void RestoreScreen(char *pBuff, char pY1, char pX1, char pY2, char pX2)
{
  long y;
  pX1 %= 80;
  pY1 %= 24;
  pX2 %= 80;
  pY2 %= 24;
  for (y = pY1; (y <= pY2); y++)
    __setWindowLine(&(pBuff[(y-pY1)*(pX2-pX1+1)*2]),(y*80+pX1)<<1, pX2-pX1+1);
  return;
}

void ScrollWindowUp()
{
  __scrollWindowUp((vWindow.Y1*80 + vWindow.X1)*2, vWindow.Y2-vWindow.Y1,
                   vWindow.X2-vWindow.X1 + 1, AtCursor.TextAttr);
  return;
}

//-LR void kprintc(char pc) {
//-LR   unsigned short lpos;
//-LR   __mutex(&vMutex,KPRINTLOCK);
//-LR   lpos = (AtCursor.Y*80+AtCursor.X) * 2;
//-LR   if (pc == '\n')
//-LR     AtCursor.X=vWindow.X2+1;
//-LR   else {
//-LR     if (lpos < 3999)
//-LR       __printchar(lpos,AtCursor.TextAttr,pc);
//-LR     AtCursor.X++;
//-LR   }
//-LR   if (AtCursor.X > vWindow.X2) {
//-LR     AtCursor.Y++;
//-LR     AtCursor.X=vWindow.X1;
//-LR   }
//-LR   if (AtCursor.Y > vWindow.Y2) {
//-LR     AtCursor.Y=vWindow.Y2;
//-LR     ScrollWindowUp();
//-LR   }
//-LR //-LR 	__setCursor((unsigned long)(AtCursor.X+AtCursor.Y*80));
//-LR   __demutex(&vMutex,KPRINTLOCK);
//-LR   return;
//-LR }
/* LR 000712 */
void kprintc(char pc)
{
  unsigned short lpos;
  int flags;
  ATOMIC_START(flags);
  __mutex(&vMutex,KPRINTLOCK);
  lpos = (AtCursor.Y*80+AtCursor.X) * 2;
  if (pc == '\n')
    AtCursor.X=vWindow.X2+1;
  else
    if (pc != '\r')
    {
      if (lpos < 3999)
        __printchar(lpos,AtCursor.TextAttr,pc);
      AtCursor.X++;
    }
  if (AtCursor.X > vWindow.X2)
  {
    AtCursor.Y++;
    AtCursor.X=vWindow.X1;
  }
  if (AtCursor.Y > vWindow.Y2)
  {
    AtCursor.Y=vWindow.Y2;

    //-LR     __printchar(0,AtCursor.TextAttr,'-');
    ScrollWindowUp();
    //-LR     __printchar(2,AtCursor.TextAttr,'+');
    //-LR     asm("hlt");
  }
  //-LR 	__setCursor((unsigned long)(AtCursor.X+AtCursor.Y*80));
  __demutex(&vMutex,KPRINTLOCK);
  ATOMIC_END(flags);
  return;
}

void kprintf(char *ps)
{
  if (!ps)
    ps = "(null)";
  while (*ps)
  {
    kprintc(*ps);
    ps++;
  }
  return;
}

void MemoryDump(char *ps,unsigned int Addr)
{
  int i, lpos;
  char *c = (char *)Addr;
  printf("Dumping \"%s\" at %p\n",ps,(void *)Addr);
  for (i = 0; (i < 10*80); i++)
  {
    lpos = (AtCursor.Y*80+AtCursor.X) * 2;
    if (lpos < 3999)
      __printchar(lpos,AtCursor.TextAttr,c[i]);
    AtCursor.X++;
    if (AtCursor.X > vWindow.X2)
    {
      AtCursor.Y++;
      AtCursor.X=vWindow.X1;
    }
    if (AtCursor.Y > vWindow.Y2)
    {
      AtCursor.Y=vWindow.Y2;
      ScrollWindowUp();
    }
  }
  printf("\"%s\" successfully dumped :-)\n",ps);
}

