#include <conio.h>
#include <dos.h>
#include <malloc.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include "types.h"
#include "develop.h"
#include "text_lib.h"
#include "wndo_lib.h"
#include "file_lib.h"
#include "_menulib.h"
#include "menudefs.h"
#include "menu_lib.h"
#include "mnu_inpt.h"
#include "util_lib.h"
#include "keyboard.h"
#include "common.h"
#include "gamedefs.h"

static int32 ActiveColor;
static int32 InActiveColor;
static int32 DisplayColor;

void DoFromFile( FromFileType * fromfile );
void DoFromFunctions ( FromFunctionsType * fromfunctions );

/*
===================
=
= DrawBorder
=
===================
*/

void DrawBorder( int32 y )
   {
   DrawBlankLine(0,y,MAXTEXTWIDTH-1,MENUBACKBORDER_FOREGROUND,MENUBACKBORDER_BACKGROUND);
   }


/*
===================
=
= DrawHelpString
=
===================
*/

void DrawHelpString( char * helpstring )
   {

   //
   // Erase Help string region
   //

   DrawBorder( MAXTEXTHEIGHT - 1 );
   DrawString
      (
      (MAXTEXTWIDTH-strlen(helpstring))>>1,
      MAXTEXTHEIGHT-1,
      helpstring,
      MENUBACKBORDER_FOREGROUND,
      MENUBACKBORDER_BACKGROUND
      );
   }

/*
===================
=
= GetTranslateFunctionWidth
=
===================
*/
int32 GetTranslateFunctionWidth( void * func )
   {
   int32 i;
   int32 width;
   char * (* TranslateValue)(int32 value);

   TranslateValue = ( char * (*) (int32 value) )func;

   width = 0;
   for (i=0;i<20;i++)
      {
      if (strlen(TranslateValue(i)) > width)
         {
         width = strlen(TranslateValue(i));
         }
      }
   return width;
   }

/*
===================
=
= GetEntryDimensions
=
===================
*/

void GetEntryDimensions( void * ptr, int32 * width, int32 * height )
   {
   MenuLinkType * entry;

   entry = (MenuLinkType * )ptr;

   switch ( entry->type )
      {
      case entrytype_togglebutton:
      case entrytype_value:
         *width = strlen(entry->textstring) + 4;
         *height = 1;
         break;

      case entrytype_choice:
         *width = strlen(entry->textstring);
         *height = 1;
         break;

      case entrytype_entervalue:
         *width = strlen(entry->textstring);
         *height = 1;
         break;

      case entrytype_displayvalue:
         *width = strlen(entry->textstring) + 12;
         *height = 1;
         break;

      case entrytype_menulink:
      case entrytype_functionlink:
      case entrytype_fromfile:
         *width = strlen(entry->textstring);
         *height = 1;
         break;
      case entrytype_fromfunctions:
         *width = strlen(entry->textstring);
         *width += MAXFUNCTIONLENGTH + 6;
         *height = 1;
         break;
      case entrytype_string:
         *width = strlen(entry->textstring);
         *height = 1;
         break;
      case entrytype_dualstring:
         {
         DualStringType * dual;

         dual = (DualStringType *)ptr;
         *width = dual->maxlength1-1;
         *width += dual->maxlength2-1;
         *width += 3;
         *height = 1;
         }
         break;
      case entrytype_displaystring:
         *width = ( (StringType *)ptr )->maxlength-1;
         *width += strlen(entry->textstring) + 6;
         *height = 1;
         break;

      case entrytype_displaymenu:
         {
         MenuSectionType * section;
         int32 w,h;

         section = (MenuSectionType *)((DisplayMenuType *)ptr)->menuptr;
         if (section)
            {
            GetSectionDimensions( section, &w, &h );
            *width = w;
            }
         else
            {
            *width = 0;
            }
         *width += strlen(entry->textstring);
         *height = 1;
         }
         break;
      case entrytype_translatevalue:
         {
         TranslateValueType * translate;

         translate = (TranslateValueType *)ptr;
         if (translate->funcptr)
            {
            *width=GetTranslateFunctionWidth(translate->funcptr);
            }
         else
            {
            *width = 0;
            }
         *width += strlen(entry->textstring) + 5 ;
         *height = 1;
         }
         break;
      }
   }


/*
===================
=
= GetSectionDimensions
=
===================
*/

void GetSectionDimensions( MenuSectionType * section, int32 * width, int32 * height )
   {
   int32 w,h;
   int32 i;

   // initialize variables
   w=0;
   h=0;

   if (section->header != NULL)
      {
      h++;
      if (strlen(section->header) > w)
         {
         w = strlen(section->header);
         }
      }

   for (i=0; i < section->numentries; i++)
      {
      int32 entrywidth;
      int32 entryheight;

      GetEntryDimensions( &section->entries[i], &entrywidth, &entryheight );
      if (entrywidth > w)
         {
         w = entrywidth;
         }
      h += entryheight;
      }
   *width = w;
   *height = h;
   }

/*
===================
=
= GetMenuDimensions
=
===================
*/

void GetMenuDimensions( MenuType * menu, int32 * width, int32 * height )
   {
   int32 w,h;
   int32 i;

   // initialize variables
   w=0;
   h=0;

   for (i=0; i < menu->numsections; i++)
      {
      int32 sectionwidth;
      int32 sectionheight;

      GetSectionDimensions( menu->sections[i], &sectionwidth, &sectionheight );
      if (sectionwidth > w)
         {
         w = sectionwidth;
         }
      h += sectionheight;
      }
   if (menu->header != NULL)
      {
      if (strlen(menu->header) > w)
         {
         w = strlen(menu->header);
         }
      h+=2;
      }

   if (menu->footer != NULL)
      {
      if (strlen(menu->footer) > w)
         {
         w = strlen(menu->footer);
         }
      h+=2;
      }
   *width = w+1;
   *height = h-1;
   }

/*
===================
=
= GetWidestEntryWidthInSection
=
===================
*/

int32 GetWidestEntryWidthInSection( MenuSectionType * section )
   {
   int32 w;
   int32 j;

   // initialize variables
   w=0;

   for (j=0; j < section->numentries; j++)
      {
      int32 entrywidth;
      int32 entryheight;

      GetEntryDimensions( &section->entries[j], &entrywidth, &entryheight );
      if (entrywidth > w)
         {
         w = entrywidth;
         }
      }
   return w;
   }

/*
===================
=
= GetWidestEntryWidth
=
===================
*/

int32 GetWidestEntryWidth( MenuType * menu )
   {
   int32 w, swidth;;
   int32 i;

   // initialize variables
   w=0;

   for (i=0; i < menu->numsections; i++)
      {
      swidth=GetWidestEntryWidthInSection( menu->sections[i] );
      if (swidth > w)
         {
         w = swidth;
         }
      }
   return w;
   }

/*
===================
=
= DrawMenuEntry
=
===================
*/

int32 DrawMenuEntry( int16 handle, int32 xoffset, int32 yoffset, void * ptr, boolean current )
   {
   MenuLinkType * entry;
   int32 yinc;
   int32 foreground;
   int32 background;
   boolean draw;
   char str[80];


   entry = (MenuLinkType * )ptr;

   SetWindowTextColors();
   if (entry->status == status_active)
      {
      foreground = ActiveColor;
      }
   else if (entry->status == status_inactive)
      {
      foreground = InActiveColor;
      }
   else if (entry->status == status_display)
      {
      foreground = DisplayColor;
      }

   background = WindowBackgroundColor( handle );

   yinc = 0;
   draw = true;
   switch ( entry->type )
      {
      case entrytype_menulink:
      case entrytype_functionlink:
      case entrytype_fromfile:
      case entrytype_string:
      case entrytype_choice:
      case entrytype_entervalue:
         break;
      case entrytype_fromfunctions:
         {
         FromFunctionsType * fromfunctions;

         fromfunctions = (FromFunctionsType *)ptr;
         ClearWindowLine(handle,yoffset);
         strcpy(str," ( ");
         strcat(str,fromfunctions->ptr);
         strcat(str," )");
         DrawWindowString
            (
            handle,
            xoffset + strlen(fromfunctions->textstring),
            yoffset,
            str,
            foreground,
            background
            );
         }
         break;
      case entrytype_displaystring:
         {
         StringType * string;

         string = (StringType *)ptr;
         ClearWindowLine(handle,yoffset);
         strcpy(str," ( ");
         strcat(str,string->ptr);
         strcat(str," )");
         DrawWindowString
            (
            handle,
            xoffset + strlen(string->textstring),
            yoffset,
            str,
            foreground,
            background
            );
         }
         break;
      case entrytype_dualstring:
         {
         DualStringType * dual;
         int32 fore;
         char str[80];

         fore = COLOR_DARKGRAY;
         if (current == true)
            {
            fore = COLOR_GRAY;
            }
         dual = (DualStringType *)ptr;
         ClearWindowLine(handle,yoffset);
         memset(str,'°',sizeof(str));
         str[dual->maxlength1-1] = '\0';
         DrawWindowString
            (
            handle,
            xoffset,
            yoffset,
            str,
            fore,
            background
            );
         memset(str,'°',sizeof(str));
         str[dual->maxlength2-1] = '\0';
         DrawWindowString
            (
            handle,
            xoffset + dual->maxlength1 + 2,
            yoffset,
            str,
            fore,
            background
            );
//         background = COLOR_BLUE;
         if (current == true)
            {
            DrawWindowString
               (
               handle,
               xoffset + dual->maxlength1 + 2,
               yoffset,
               dual->string2,
               background,
               foreground
               );
            }
         else
            {
            DrawWindowString
               (
               handle,
               xoffset + dual->maxlength1 + 2,
               yoffset,
               dual->string2,
               foreground,
               background
               );
            }
         }
         break;

      case entrytype_displaymenu:
         {
         DisplayMenuType * display;
         char * string;
         char temp[3] = "\0";
         MenuSectionType * section;

         display = (DisplayMenuType *)ptr;
         ClearWindowLine(handle,yoffset);
         section = (MenuSectionType *)display->menuptr;
         if (section->currententry != -1)
            {
            string = section->entries[section->currententry].textstring;
            }
         else
            {
            string = temp;
            }
         strcpy(str," ( ");
         strcat(str,string);
         strcat(str," )");
         DrawWindowString
            (
            handle,
            xoffset + strlen(display->textstring),
            yoffset,
            str,
            foreground,
            background
            );
         }
         break;
      case entrytype_translatevalue:
         {
         TranslateValueType * translate;
         char * string;
         char * (* TranslateValue)(int32 value);

         translate = (TranslateValueType *)ptr;
         TranslateValue = ( char * (*) (int32 value) )translate->funcptr;
         ClearWindowLine(handle,yoffset);
         string = TranslateValue(*(int32 *)translate->valueptr);

         strcpy(str," ( ");
         strcat(str,string);
         strcat(str," )");
         DrawWindowString
            (
            handle,
            xoffset + strlen(translate->textstring),
            yoffset,
            str,
            foreground,
            background
            );
         }
         break;
      case entrytype_togglebutton:
         {
         BooleanButtonType * button;

         button = (BooleanButtonType *)ptr;
         if ((*(int32 *)button->ptr) == 1)
            {
            DrawWindowString
               (
               handle,
               xoffset,
               yoffset,
               "()",
               foreground,
               background
               );
            }
         else
            {
            DrawWindowString
               (
               handle,
               xoffset,
               yoffset,
               "( )",
               foreground,
               background
               );
            }
         xoffset += 4;
         }
         break;
      case entrytype_value:
         {
         ValueType * value;

         value = (ValueType *)ptr;
         if ((*(int32 *)value->ptr) == value->value)
            {
            DrawWindowString
               (
               handle,
               xoffset,
               yoffset,
               "()",
               foreground,
               background
               );
            }
         else
            {
            DrawWindowString
               (
               handle,
               xoffset,
               yoffset,
               "( )",
               foreground,
               background
               );
            }
         xoffset += 4;
         }
         break;
      case entrytype_displayvalue:
         {
         EnterValueType * value;
         char temp[80];

         value = (EnterValueType *)ptr;
         ClearWindowLine(handle,yoffset);
         if (*(int32 *)value->ptr == -1) // default value
            {
            sprintf(temp,"Default");
            }
         else
            {
            if (value->valuetype == valuetype_hexadecimal)
               {
               sprintf(temp,"0x%x",*((int32 *)value->ptr));
               }
            else
               {
               sprintf(temp,"%ld",*(int32 *)value->ptr);
               }
            }
         strcpy(str," [ ");
         strcat(str,temp);
         strcat(str," ]");
         DrawWindowString
            (
            handle,
            xoffset + strlen(value->textstring),
            yoffset,
            str,
            foreground,
            background
            );
         }
         break;
      }
   if  (current == true)
       {
       DrawWindowString
          (
          handle,
          xoffset,
          yoffset,
          entry->textstring,
          background,
          foreground
          );
       DrawHelpString( entry->helpstring );
       }
   else
       {
       DrawWindowString
           (
           handle,
           xoffset,
           yoffset,
           entry->textstring,
           foreground,
           background
           );
       }
   yinc++;
   return yinc;
   }


/*
===================
=
= DrawMenuSection
=
===================
*/

int32 DrawMenuSection( int16 handle, int32 xoffset, int32 yoffset, MenuSectionType * section, boolean current )
   {
   int32 i;
   int32 totaly;
   int32 yinc;
   boolean currententry;

   totaly = 0;

   if (section->header != NULL)
      {
      DrawWindowDivider( handle, yoffset );
      DrawWindowString
          (
          handle,
          1,
          yoffset,
          section->header,
          MENU_SECTIONHEADER_FOREGROUND,
          WindowBackgroundColor( handle )
          );
      yoffset++;
      totaly++;
      }

   for (i=0; i < section->numentries; i++)
      {
      currententry = current && (section->currententry==i);
      yinc = DrawMenuEntry( handle, xoffset, yoffset, &section->entries[i], currententry );
      yoffset += yinc;
      totaly += yinc;
      }

   return totaly;
   }

/*
===================
=
= DrawMenu
=
===================
*/

void DrawMenu( MenuType * menu )
   {
   int32 i;
   int32 xoffset;
   int32 yoffset;
   int32 totaly;

   yoffset = 0;

   // Draw Header

   if (menu->header != NULL)
      {
      DrawWindowCenteredString
          (
          menu->windowhandle,
          yoffset,
          menu->header,
          WindowForegroundColor( menu->windowhandle ),
          WindowBackgroundColor( menu->windowhandle )
          );
      yoffset++;
      DrawWindowDivider( menu->windowhandle, yoffset );
      yoffset++;
      }

   if (menu->menutype == menutype_leftjustified)
      {
      // Determine widest entry

      xoffset = ( WindowWidth( menu->windowhandle ) -
                  GetWidestEntryWidth( menu ) +
                  1 ) >> 1;
      }

   // Draw Main Body

   for (i=0; i < menu->numsections; i++)
      {
      if (menu->menutype ==  menutype_centered)
         {
         xoffset = ( WindowWidth( menu->windowhandle ) -
                     GetWidestEntryWidthInSection( menu->sections[i] ) +
                     1 ) >> 1;
         }

      totaly = DrawMenuSection ( menu->windowhandle,
                                 xoffset,
                                 yoffset,
                                 menu->sections[i],
                                 (i==menu->currentsection)
                               );
      yoffset += totaly;
      }

   // Draw Footer

   if (menu->footer != NULL)
      {
      DrawWindowDivider( menu->windowhandle, yoffset );
      yoffset++;
      DrawWindowCenteredString
          (
          menu->windowhandle,
          yoffset,
          menu->footer,
          WindowForegroundColor( menu->windowhandle ),
          WindowBackgroundColor( menu->windowhandle )
          );
      yoffset++;
      }
   }

/*
===================
=
= GetWindowColors
=
===================
*/
#define MAXWINDOWCOLORS 2
typedef struct
   {
   int32 foreground;
   int32 background;
   int32 active;
   int32 inactive;
   int32 display;
   } MenuColorType;
MenuColorType WindowColor[ MAXWINDOWCOLORS ] =
   {
   {COLOR_LIGHTCYAN, COLOR_BLUE, COLOR_WHITE, COLOR_GRAY, COLOR_LIGHTGREEN},
   {COLOR_WHITE, COLOR_LIGHTBLUE, COLOR_WHITE, COLOR_CYAN, COLOR_LIGHTCYAN},
//   {COLOR_YELLOW, COLOR_BLACK, COLOR_WHITE, COLOR_GRAY, COLOR_LIGHTGREEN},
//   {COLOR_LIGHTCYAN, COLOR_CYAN, COLOR_WHITE, COLOR_GRAY, COLOR_YELLOW},
   };

void SetWindowTextColors( void )
   {
   int32 numopen;

   numopen = WindowsOpen();
   if (numopen > 0)
      numopen--;
   numopen %= MAXWINDOWCOLORS;
   ActiveColor = WindowColor[numopen].active;
   InActiveColor = WindowColor[numopen].inactive;
   DisplayColor = WindowColor[numopen].display;
   }

void GetWindowColors( int32 * foreground, int32 * background )
   {
   int32 numopen;

   numopen = WindowsOpen();
   numopen %= MAXWINDOWCOLORS;
   *foreground = WindowColor[numopen].foreground;
   *background = WindowColor[numopen].background;
   }



/*
===================
=
= DisplayMenu
=
===================
*/

void DisplayMenu( MenuType * menu )
   {
   int32 w,h;
   int32 foreground;
   int32 background;


   GetMenuDimensions( menu, &w, &h );
   GetWindowColors(&foreground, &background);
   menu->windowhandle = OpenCenteredWindow(
                        w,
                        h,
                        foreground,
                        background);
   DrawMenu( menu );
   }

/*
===================
=
= UnDisplayMenu
=
===================
*/

void UnDisplayMenu( MenuType * menu )
   {
   CloseWindow( menu->windowhandle );
   }

/*
===================
=
= ChooseEntry
=
===================
*/

void ChooseEntry( MenuType * menu )
   {
   MenuSectionType * section;
   MenuEntryType * entry;

   section = (MenuSectionType * )menu->sections[menu->currentsection];
   entry = &section->entries[section->currententry];

   switch ( entry->type )
      {
      case entrytype_menulink:
         {
         MenuLinkType * menulink;
         MenuType * menu;

         menulink = (MenuLinkType *)entry;
         menu = (MenuType *)menulink->ptr;
         if (menu != NULL)
            {
            HandleMenu( menu );
            }
         }
         break;
      case entrytype_functionlink:
         {
         FunctionLinkType * functionlink;
         void (* function)(int32 value);

         functionlink = (FunctionLinkType *)entry;
         function = ( void (*) (int32 value) )functionlink->ptr;
         if (function != NULL)
            {
            function( functionlink->value );
            }
         }
         break;
      case entrytype_fromfile:
         DoFromFile((FromFileType *)entry);
         break;
      case entrytype_fromfunctions:
         DoFromFunctions((FromFunctionsType *)entry);
         break;
      case entrytype_togglebutton:
         {
         BooleanButtonType * button;

         button = (BooleanButtonType *)entry;
         if (button->ptr != NULL)
            {
            *((int32 *)button->ptr)=*((int32 *)button->ptr) ^ 1;
            }
         }
         break;
      case entrytype_string:
      case entrytype_displaystring:
         {
         StringType * string;

         string = (StringType *)entry;
         if (string->ptr != NULL)
            {
            MenuInputString
               (
               string->ptr,
               string->textstring,
               true,
               string->maxlength
               );
            }
         }
         break;
      case entrytype_dualstring:
         {
         DualStringType * string;

         string = (DualStringType *)entry;
         strcpy(string->dest,string->string2);
         }
         break;
      case entrytype_entervalue:
         {
         EnterValueType * valueptr;

         valueptr = (EnterValueType *)entry;
         if (valueptr->ptr != NULL)
            {
            if (valueptr->valuetype == valuetype_slider)
               {
               MenuInputSlider
                  (
                  (int32 *)valueptr->ptr,
                  valueptr->textstring,
                  valueptr->minimum,
                  valueptr->maximum
                  );
               }
            else
               {
               MenuInputValue
                  (
                  (int32 *)valueptr->ptr,
                  valueptr->textstring,
                  true,
                  (valueptr->valuetype==valuetype_hexadecimal),
                  valueptr->minimum,
                  valueptr->maximum
                  );
               }
            }
         }
         break;

      case entrytype_value:
      case entrytype_choice:
         {
         ValueType * valueptr;

         valueptr = (ValueType *)entry;
         if (valueptr->ptr != NULL)
            {
            *((int32 *)valueptr->ptr)=valueptr->value;
            }
         }
         break;
      }
   DrawMenu( menu );
   }

/*
===================
=
= DeleteEntry
=
===================
*/

void DeleteEntry( MenuType * menu )
   {
   MenuSectionType * section;
   MenuEntryType * entry;

   section = (MenuSectionType * )menu->sections[menu->currentsection];
   entry = &section->entries[section->currententry];

   switch ( entry->type )
      {
      case entrytype_fromfunctions:
         strcpy(((FromFunctionsType *)entry)->ptr,"");
         break;
      }
   DrawMenu( menu );
   }


/*
===================
=
= EditEntry
=
===================
*/

void EditEntry( MenuType * menu )
   {
   MenuSectionType * section;
   MenuEntryType * entry;

   section = (MenuSectionType * )menu->sections[menu->currentsection];
   entry = &section->entries[section->currententry];

   switch ( entry->type )
      {
      case entrytype_dualstring:
         {
         DualStringType * string;
         boolean cont;

         cont = true;
         string = (DualStringType *)entry;
         if (string->string1 != NULL)
            {
            cont = MenuInputString
               (
               string->string1,
               string->description1,
               true,
               string->maxlength1
               );
            }
         if (
              (string->string2 != NULL) &&
              (cont == true)
            )
            {
            MenuInputString
               (
               string->string2,
               string->description2,
               true,
               string->maxlength2
               );
            }
         }
         break;
      }
   DrawMenu( menu );
   }


/*
===================
=
= GetCurrentSectionEntry
=
===================
*/

void GetCurrentSectionEntry( MenuSectionType * section )
   {
   int32 i;

   //
   // Check to see if an entry is already active
   //

   if (section->currententry != -1)
      return;

   for (i=0; i < section->numentries; i++)
      {
      if (section->entries[i].status == status_active)
         {
         section->currententry = i;
         return;
         }
      }
   Error ("Could not find an active entry");
   }


/*
===================
=
= SectionActive
=
===================
*/

boolean SectionActive( MenuSectionType * section )
   {
   int32 i;

   for (i=0; i < section->numentries; i++)
      {
      if (section->entries[i].status == status_active)
         {
         return true;
         }
      }
   return false;
   }

/*
===================
=
= GetCurrentMenuSection
=
===================
*/

void GetCurrentMenuSection( MenuType * menu )
   {
   int32 i;

   //
   // Check to see if a section is already active
   //

   if (menu->currentsection != -1)
      return;

   for (i=0; i < menu->numsections; i++)
      {
      if (SectionActive(menu->sections[i]) == true)
         {
         menu->currentsection = i;
         return;
         }
      }
   Error ("Could not find an active section");
   }

/*
===================
=
= TryPreviousEntry
=
===================
*/

boolean TryPreviousEntry( MenuSectionType * section )
   {
   int32 current;

   current = section->currententry-1;

   while (
            (current >= 0) &&
            (section->entries[current].status != status_active)
         )
      {
      current--;
      }
   if (current < 0)
      {
      return false;
      }

   section->currententry = current;

   return true;
   }

/*
===================
=
= TryPreviousSection
=
===================
*/

boolean TryPreviousSection( MenuType * menu )
   {
   int32 current;

   current = menu->currentsection-1;
   while (
            (current >= 0) &&
            ( !SectionActive( menu->sections[current] ) )
         )
      {
      current--;
      }
   if (current < 0)
      {
      return false;
      }

   menu->currentsection = current;
   return true;
   }

/*
===================
=
= SetCurrentEntryToLast
=
===================
*/

void SetCurrentEntryToLast( MenuSectionType * section )
   {
   section->currententry = section->numentries;
   if (TryPreviousEntry( section ) == false)
      {
      Error("Could not find active entry in current section from last\n");
      }
   }

/*
===================
=
= PreviousEntry
=
===================
*/

void PreviousEntry( MenuType * menu )
   {
   boolean done;

   done = false;
   while (done == false)
      {
      //
      // Try to decrement to the previous entry in the current section
      //

      done = TryPreviousEntry( menu->sections[ menu->currentsection ] );

      if (done == false)
         {
         //
         // Decrement section
         //
         done = !(TryPreviousSection( menu ));
         if (done == false)
            {
            SetCurrentEntryToLast( menu->sections[ menu->currentsection ] );
            done =true;
            }
         }
      }
   DrawMenu( menu );
   }

/*
===================
=
= TryNextEntry
=
===================
*/

boolean TryNextEntry( MenuSectionType * section )
   {
   int32 current;

   current = section->currententry+1;
   while (
            (current < section->numentries) &&
            (section->entries[current].status != status_active)
         )
      {
      current++;
      }
   if (current == section->numentries)
      {
      return false;
      }

   section->currententry = current;
   return true;
   }

/*
===================
=
= TryNextSection
=
===================
*/

boolean TryNextSection( MenuType * menu )
   {
   int32 current;

   current = menu->currentsection+1;
   while (
            (current < menu->numsections) &&
            ( !SectionActive( menu->sections[current] ) )
         )
      {
      current++;
      }
   if (current == menu->numsections)
      {
      return false;
      }

   menu->currentsection = current;
   return true;
   }

/*
===================
=
= SetCurrentEntryToFirst
=
===================
*/

void SetCurrentEntryToFirst( MenuSectionType * section )
   {
   section->currententry = -1;
   if (TryNextEntry( section ) == false)
      {
      Error("Could not find active entry in current section from first\n");
      }
   }

/*
===================
=
= NextEntry
=
===================
*/

void NextEntry( MenuType * menu )
   {
   boolean done;

   done = false;
   while (done == false)
      {
      //
      // Try to increment to the next entry in the current section
      //

      done = TryNextEntry( menu->sections[ menu->currentsection ] );

      if (done == false)
         {
         //
         // Increment section
         //
         done = !(TryNextSection( menu ));
         if (done == false)
            {
            SetCurrentEntryToFirst( menu->sections[ menu->currentsection ] );
            done =true;
            }
         }
      }
   DrawMenu( menu );
   }

/*
===================
=
= HandleMenu
=
===================
*/

boolean HandleMenu( MenuType * menu )
   {
   boolean done;
   boolean escaped;
   int32 keypress;

   GetCurrentMenuSection( menu );
   GetCurrentSectionEntry( menu->sections[ menu->currentsection ] );
   DisplayMenu( menu );
   done = false;
   escaped = false;
   while ( done == false )
      {
      if (KB_KeyWaiting() == true)
         {
         keypress = KB_Getch();
         if (keypress == 0)
            {
            // Must be a scan code
            keypress = KB_Getch();
            switch (keypress)
               {
               case sc_UpArrow:
               case sc_kpad_8:
                  PreviousEntry( menu );
                  break;
               case sc_DownArrow:
               case sc_kpad_2:
                  NextEntry( menu );
                  break;
               case sc_Delete:
               case sc_kpad_Period:
                  DeleteEntry( menu );
                  break;
               }
            }
         else
            {
            switch (keypress)
               {
               case asc_Enter:
               case asc_Space:
                  ChooseEntry( menu );
                  if (menu->sections[ menu->currentsection ]->sectiontype == sectiontype_choose)
                     {
                     done = true;
                     }
                  break;

               case 'e':
               case 'E':
                  EditEntry( menu );
                  break;

               case asc_Escape:
                  done = true;
                  escaped = true;
                  break;
               }
            }
         }
      }
  UnDisplayMenu( menu );
  return escaped;
  }

//******************************************************************************
//
// ErrorWindow()
//
///******************************************************************************

#define ERRORMESSAGECOLOR COLOR_WHITE
#define MAXSTRING 80

void ErrorWindow( char * errormsg )
   {
   boolean  done;
   int32    windowhandle;
   int32    windowwidth;
   int32    windowheight;
   int32    blockwidth;
   char     footer[MAXSTRING];
   int32    keypress;

   done = false;

   KB_FlushKeyboardQueue();
   KB_ClearKeysDown();

   strcpy (footer,"Press any key to continue");

   BlockSize( errormsg, &blockwidth, &windowheight );
   windowwidth = blockwidth + 4;

   if ( strlen(footer)-1 > windowwidth )
      {
      windowwidth = strlen(footer)-1;
      }

   windowhandle = OpenCenteredWindow(
               windowwidth,
               windowheight,
               COLOR_GRAY,
               COLOR_RED);

   DrawWindowCenteredString
       (
       windowhandle,
       windowheight,
       footer,
       WindowForegroundColor( windowhandle ),
       WindowBackgroundColor( windowhandle )
       );

   DrawWindowCenteredBlock
       (
       windowhandle,
       0,
       errormsg,
       ERRORMESSAGECOLOR,
       WindowBackgroundColor( windowhandle )
       );

   while (done == false)
      {
      if (KB_KeyWaiting() == true)
         {
         keypress = KB_Getch();
         done = true;
         }
      }

   CloseWindow( windowhandle );

   KB_FlushKeyboardQueue();
   KB_ClearKeysDown();

   }

//******************************************************************************
//
// MessageWindow()
//
///******************************************************************************

#define MESSAGECOLOR COLOR_BLUE

int32 MessageWindow( char * message )
   {
   int32    windowhandle;
   int32    windowwidth;
   int32    windowheight;
   int32    blockwidth;

   BlockSize( message, &blockwidth, &windowheight );
   windowheight--;
   windowwidth = blockwidth + 4;

   windowhandle = OpenCenteredWindow(
               windowwidth,
               windowheight,
               COLOR_GRAY,
               COLOR_WHITE);

   DrawWindowCenteredBlock
       (
       windowhandle,
       0,
       message,
       MESSAGECOLOR,
       WindowBackgroundColor( windowhandle )
       );
   return windowhandle;
   }


