// Window Lib
#include <dos.h>
#include <conio.h>
#include <mem.h>
#include "types.h"
#include "develop.h"
#include "util_lib.h"
#include "_wndolib.h"
#include "wndo_lib.h"
#include "text_lib.h"

static TextWindowType Windows[MAXWINDOWS];
static boolean MenusStarted = false;
static NumOpenWindows=0;


//******************************************************************************
//
// StartWindows ()
//
//******************************************************************************

void StartWindows (void)
   {
   int32 i;

   if (MenusStarted == true)
      return;

   MenusStarted = true;
   NumOpenWindows = 0;

   for (i=0; i<MAXWINDOWS; i++)
      {
      Windows[i].inuse = false;
      }
   }

//******************************************************************************
//
// ShutdownWindows ()
//
//******************************************************************************

void ShutdownWindows (void)
   {
   int32 i;

   if (MenusStarted == false)
      return;

   MenusStarted = false;

   for (i=0; i<MAXWINDOWS; i++)
      {
      FreeUpWindow(i);
      }
   }

//******************************************************************************
//
// CheckWindowHandle ()
//
//******************************************************************************
void CheckWindowHandle ( int32 windowhandle )
   {
   if ( (windowhandle < 0) || (windowhandle >= MAXWINDOWS) )
      {
      Error ("Illegal Window handle = %ld\n",windowhandle);
      }
   if ( Windows[windowhandle].inuse == false )
      {
      Error ("Window is not active Window handle = %ld\n",windowhandle);
      }
   }

//******************************************************************************
//
// CheckWindowBounds ()
//
//******************************************************************************
void CheckWindowBounds ( int32 windowhandle )
   {
   TextWindowType * window;
   int32 temp;

   CheckWindowHandle ( windowhandle );
   window = &Windows[windowhandle];

   temp = window->x;
   if ( temp < 0 )
      {
      Error ("Window %ld X value min is out of range = %ld\n",windowhandle, temp);
      }
   temp = window->x + window->width + (WINDOWBORDERSIZE*2);
   if ( temp >= MAXTEXTWIDTH )
      {
      Error ("Window %ld X value max is out of range = %ld\n",windowhandle, temp);
      }

   temp = window->y;
   if ( temp < 0 )
      {
      Error ("Window %ld Y value min is out of range = %ld\n",windowhandle, temp);
      }
   temp = window->y + window->height + (WINDOWBORDERSIZE*2);
   if ( temp >= MAXTEXTHEIGHT )
      {
      Error ("Window %ld Y value max is out of range = %ld\n",windowhandle, temp);
      }
   }

//******************************************************************************
//
// FreeUpWindow ()
//
//******************************************************************************
void FreeUpWindow( int32 windowhandle )
   {
   if (Windows[windowhandle].inuse == true)
      {
      SafeFree( Windows[windowhandle].saved_background );
      Windows[windowhandle].inuse = false;
      }
   }

//******************************************************************************
//
// GetWindow ()
//
// returns handle to first available window
//
//******************************************************************************

int32 GetWindow( void )
   {
   int32 i;

   for (i=0; i<MAXWINDOWS; i++)
      {
      if (Windows[i].inuse == false)
         return i;
      }
   return -1;
   }

//******************************************************************************
//
// SaveWindowBackground ()
//
//******************************************************************************

void SaveWindowBackground( int32 windowhandle )
   {
   int32 w,h;
   TextWindowType * window;

   CheckWindowHandle ( windowhandle );
   window = &Windows[windowhandle];
   w = (WINDOWBORDERSIZE * 2) + window->width + WINDOWDROPSHADOWSIZEX + 1;
   if (window->x+w > MAXTEXTWIDTH)
      {
      w = MAXTEXTWIDTH - window->x;
      }
   h = (WINDOWBORDERSIZE * 2) + window->height + WINDOWDROPSHADOWSIZEY + 1;
   if (window->y+h > MAXTEXTHEIGHT)
      {
      h = MAXTEXTHEIGHT - window->y;
      }
   window->saved_background = SafeMalloc ( (w * h) << 1 );
   SaveTextBackground( window->x,
                       window->y,
                       w,
                       h,
                       window->saved_background
                     );
   }

//******************************************************************************
//
// RestoreWindowBackground ()
//
//******************************************************************************

void RestoreWindowBackground( int32 windowhandle )
   {
   int32 w,h;
   TextWindowType * window;

   CheckWindowHandle ( windowhandle );
   window = &Windows[windowhandle];
   w = (WINDOWBORDERSIZE * 2) + window->width + WINDOWDROPSHADOWSIZEX + 1;
   if (window->x+w > MAXTEXTWIDTH)
      {
      w = MAXTEXTWIDTH - window->x;
      }
   h = (WINDOWBORDERSIZE * 2) + window->height + WINDOWDROPSHADOWSIZEY + 1;
   if (window->y+h > MAXTEXTHEIGHT)
      {
      h = MAXTEXTHEIGHT - window->y;
      }
   RestoreTextBackground( window->x,
                          window->y,
                          w,
                          h,
                          window->saved_background
                        );
   }

//******************************************************************************
//
// DrawWindow ()
//
//******************************************************************************

void DrawWindow( int32 windowhandle )
   {
   TextWindowType * window;

   CheckWindowHandle ( windowhandle );
   window = &Windows[windowhandle];

   AttributeBox(
               window->x+WINDOWDROPSHADOWSIZEX,
               window->y+WINDOWDROPSHADOWSIZEY,
               window->x+window->width+WINDOWDROPSHADOWSIZEX+(WINDOWBORDERSIZE*2),
               window->y+window->height+WINDOWDROPSHADOWSIZEY+(WINDOWBORDERSIZE*2),
               COLOR_DARKGRAY,
               COLOR_BLACK
               );
   TextFrame(
              window->x,
              window->y,
              window->x+window->width+(WINDOWBORDERSIZE*2),
              window->y+window->height+(WINDOWBORDERSIZE*2),
              SINGLE_FRAME,
              window->foreground,
              window->background
            );
   TextBox  (
              window->x+WINDOWBORDERSIZE,
              window->y+WINDOWBORDERSIZE,
              window->x+window->width+WINDOWBORDERSIZE,
              window->y+window->height+WINDOWBORDERSIZE,
              ' ',
              window->foreground,
              window->background
            );
   }

//******************************************************************************
//
// OpenWindow ()
//
// returns handle to open window
//
//******************************************************************************

int32 OpenWindow
   (
   int32 x,
   int32 y,
   int32 width,
   int32 height,
   int32 foreground,
   int32 background
   )

   {
   int32 windowhandle;
   TextWindowType * window;

   windowhandle = GetWindow();
   if (windowhandle == -1)
      {
      Error ("Too many open windows, cannot allocate new window");
      }

   NumOpenWindows++;
   window = &Windows[windowhandle];

   //
   // initialize window vars
   //

   window->x = x;
   window->y = y;
   window->width = width;
   window->height = height;
   window->foreground = foreground;
   window->background = background;
   window->inuse = true;

   if (width > MAXMENUWIDTH)
      Error("Menu too wide width = %ld\n",width);

   if (height > MAXMENUHEIGHT)
      Error("Menu too tall height = %ld\n",height);

   CheckWindowBounds ( windowhandle );

   SaveWindowBackground( windowhandle );
   DrawWindow( windowhandle );

   return windowhandle;
   }

//******************************************************************************
//
// OpenCenteredWindow ()
//
// returns handle to open window
//
//******************************************************************************

int32 OpenCenteredWindow
   (
   int32 width,
   int32 height,
   int32 foreground,
   int32 background
   )

   {
   return OpenWindow(
             (MAXTEXTWIDTH-width-(2*WINDOWBORDERSIZE))>>1,
             (MAXTEXTHEIGHT-height-(2*WINDOWBORDERSIZE))>>1,
             width,
             height,
             foreground,
             background);
   }

//******************************************************************************
//
// CloseWindow ()
//
//******************************************************************************

void CloseWindow( int32 windowhandle )
   {
   CheckWindowHandle ( windowhandle );
   RestoreWindowBackground( windowhandle );
   FreeUpWindow( windowhandle );
   NumOpenWindows--;
   }

//******************************************************************************
//
// WindowsOpen ()
//
//******************************************************************************

int32 WindowsOpen( void )
   {
   return NumOpenWindows;
   }


//******************************************************************************
//
// DrawWindowDivider ()
//
//******************************************************************************

void DrawWindowDivider( int32 windowhandle, int32 yoffset )
   {
   TextWindowType * window;

   CheckWindowHandle ( windowhandle );
   window = &Windows[windowhandle];

   if ( yoffset > window->height )
      {
      Error("Attempt to draw divider outside of window\n");
      }

   TextBox  (
              window->x+WINDOWBORDERSIZE,
              window->y+yoffset+WINDOWBORDERSIZE,
              window->x+WINDOWBORDERSIZE+window->width,
              window->y+yoffset+WINDOWBORDERSIZE,
              'Ä',
              window->foreground,
              window->background
            );
   DrawCharacter(
        window->x,
        window->y+yoffset+WINDOWBORDERSIZE,
        'Ã',
        window->foreground,
        window->background
       );

   DrawCharacter(
        window->x+window->width+(WINDOWBORDERSIZE*2),
        window->y+yoffset+WINDOWBORDERSIZE,
        '´',
        window->foreground,
        window->background
       );

   }

//******************************************************************************
//
// DrawWindowString ()
//
//******************************************************************************

int32 DrawWindowString
   (
   int32 windowhandle,
   int32 xoffset,
   int32 yoffset,
   char * string,
   int32 foreground,
   int32 background
   )
   {
   TextWindowType * window;

   if (string == NULL)
      {
      return 0;
      }

   CheckWindowHandle ( windowhandle );
   window = &Windows[windowhandle];

   return DrawString
      (
      window->x+xoffset+WINDOWBORDERSIZE,
      window->y+yoffset+WINDOWBORDERSIZE,
      string,
      foreground,
      background
      );
   }

//******************************************************************************
//
// DrawWindowBlock ()
//
//******************************************************************************

int32 DrawWindowBlock
   (
   int32 windowhandle,
   int32 xoffset,
   int32 yoffset,
   char * block,
   int32 foreground,
   int32 background
   )
   {
   TextWindowType * window;
   int32 total;
   int32 y;
   int32 length;
   boolean more;
   char string[80];

   if (block == NULL)
      {
      return 0;
      }

   CheckWindowHandle ( windowhandle );
   window = &Windows[windowhandle];

   total = 0;
   y = yoffset;
   more = true;

   while (more == true)
      {
      more = NextStringInBlock( block, &length );
      memset (string,0,80);
      if (length > 80)
         {
         Error("String in block too long\n");
         }
      memcpy(string,block,length);
      total += DrawString
                  (
                  window->x+xoffset+WINDOWBORDERSIZE,
                  window->y+y+WINDOWBORDERSIZE,
                  string,
                  foreground,
                  background
                  );
      if (more == true)
         {
         y++;
         block += (length+1);
         }
      }
   return total;
   }

//******************************************************************************
//
// DrawWindowCharacter ()
//
//******************************************************************************

void DrawWindowCharacter
   (
   int32 windowhandle,
   int32 xoffset,
   int32 yoffset,
   char  ch,
   int32 foreground,
   int32 background
   )
   {
   TextWindowType * window;

   CheckWindowHandle ( windowhandle );
   window = &Windows[windowhandle];
   DrawCharacter
      (
      window->x+xoffset+WINDOWBORDERSIZE,
      window->y+yoffset+WINDOWBORDERSIZE,
      ch,
      foreground,
      background
      );
   }

//******************************************************************************
//
// DrawWindowCenteredString ()
//
//******************************************************************************

int32 DrawWindowCenteredString
   (
   int32 windowhandle,
   int32 yoffset,
   char * string,
   int32 foreground,
   int32 background
   )
   {
   TextWindowType * window;

   CheckWindowHandle ( windowhandle );
   window = &Windows[windowhandle];

   return DrawWindowString
      (
      windowhandle,
      (window->width-strlen(string)+1) >> 1,
      yoffset,
      string,
      foreground,
      background
      );
   }

//******************************************************************************
//
// DrawWindowCenteredBlock ()
//
//******************************************************************************

int32 DrawWindowCenteredBlock
   (
   int32 windowhandle,
   int32 yoffset,
   char * block,
   int32 foreground,
   int32 background
   )
   {
   TextWindowType * window;
   int32 blockwidth;
   int32 blockheight;

   CheckWindowHandle ( windowhandle );
   window = &Windows[windowhandle];
   BlockSize( block, &blockwidth, &blockheight );

   return DrawWindowBlock
      (
      windowhandle,
      (window->width-blockwidth) >> 1,
      yoffset,
      block,
      foreground,
      background
      );
   }


//******************************************************************************
//
// WindowBackgroundColor ()
//
//******************************************************************************

int32 WindowBackgroundColor( int32 windowhandle )
   {
   TextWindowType * window;

   CheckWindowHandle ( windowhandle );
   window = &Windows[windowhandle];

   return ( window->background );
   }

//******************************************************************************
//
// WindowForegroundColor ()
//
//******************************************************************************

int32 WindowForegroundColor( int32 windowhandle )
   {
   TextWindowType * window;

   CheckWindowHandle ( windowhandle );
   window = &Windows[windowhandle];

   return ( window->foreground );
   }

//******************************************************************************
//
// WindowWidth ()
//
//******************************************************************************

int32 WindowWidth( int32 windowhandle )
   {
   TextWindowType * window;

   CheckWindowHandle ( windowhandle );
   window = &Windows[windowhandle];

   return ( window->width );
   }

//******************************************************************************
//
// WindowHeight ()
//
//******************************************************************************

int32 WindowHeight( int32 windowhandle )
   {
   TextWindowType * window;

   CheckWindowHandle ( windowhandle );
   window = &Windows[windowhandle];

   return ( window->height );
   }

/*
===================
=
= ClearWindowLine
=
===================
*/

void ClearWindowLine( int32 windowhandle, int32 y )
   {
   TextWindowType * window;

   CheckWindowHandle ( windowhandle );
   window = &Windows[windowhandle];

   DrawBlankLine
      (
      window->x+WINDOWBORDERSIZE,
      window->y+y+WINDOWBORDERSIZE,
      window->width-1,
      window->foreground,
      window->background
      );
   }


/*
===================
=
= GetWindowCharacter
=
===================
*/

void GetWindowCharacter
   (
   int32 windowhandle,
   int32  x,
   int32  y,
   int32 * ch,
   int32 * foreground,
   int32 * background
   )
   {
   TextWindowType * window;

   CheckWindowHandle ( windowhandle );
   window = &Windows[windowhandle];

   GetCharacter
      (
      window->x+WINDOWBORDERSIZE+x,
      window->y+y+WINDOWBORDERSIZE,
      ch,
      foreground,
      background
      );
   }






