#include <stdlib.h>
#include <unistd.h>
#include <GL/glut.h>


#include "serverobject.h"
#include "sizes.h"
#include "input.h"
#include "netvariables.h"
#include "game.h"
#include "object.h"
#include "screen.h"
#include "configuration.h"
#include "serverconfig.h"
#include "score.h"
#include "sound.h"
#include "thread.h"
#include "netconfig.h"
#include "serverdata.h"
#include "scorevals.h"
#include "server.h"
#include "netdata.h"
#include "network.h"


struct ConfMenuItemStruct {
  char ItemText[80];
  char EntryText[80];
  void *EntryValue;
  int EntryLength;
  int EntryType;
  void (*EntryFunction)(char *, void *, int, int);
  void (*ItemFunction)();
};

struct ScoreMenuItemStruct {
  char ItemText[80];
  void (*ItemFunction)();
};

struct MainMenuItemStruct {
  char ItemText[80];
  void (*ItemFunction)();
};


void SetupMainMenu();
void SetupConfMenu();
void SetupScoreMenu();
void SetupConfMenu();
void SetupScoreMenu();
void AbortGame();
void MainMenu();
void ConfMenu();
void ScoreMenu();
void SetupMainDisplay();
void SetupConfDisplay();
void InitMainMenu();
void InitConfMenu();
void InitScoreMenu();
void DrawMainMenu();
void DrawConfMenu();
void DrawScoreMenu();
void MainMenuItemSelected();
void ConfMenuItemSelected();
void ScoreMenuItemSelected();
void SetKeyValue();
void TextEntry();
void ScoreEntry();
void IntTextEntry();
void SetValue(char *ValueText, void *Value, int ValueLength, int type);
void SetKey(char *KeyId, char *Key);
void SetText(char *TextId, char *Text, int MaxLength);
void SetIntText(char *TextId, int *Value, int MaxLength);
void StartSingleGame();
void StartMultiGame();
void StartServer();
void KillServer();
void QuitGame();


int MainMenuItemHighlighted;
int ConfMenuItemHighlighted;
int ScoreMenuItemHighlighted;
char *KeyValue;
char KeyName[MAX_NAME_LENGTH];
char *TextValue;
char TextName[MAX_NAME_LENGTH];
int MaxTextLength;
int *IntValue;
int NewScreenWidth, NewScreenHeight;
pthread_t ServerThread;
int ServerStarted;
int TopItemDisplayed;
int BottomItemDisplayed;
int MainMenuStartHeight;
int ConfMenuStartHeight;
int NumMainMenuItems;
int NumConfMenuItems;
int NumScoreMenuItems;
struct MainMenuItemStruct MainMenuItems[MAX_MENU_ITEMS];
struct ConfMenuItemStruct ConfMenuItems[MAX_MENU_ITEMS];
struct ScoreMenuItemStruct ScoreMenuItems[MAX_MENU_ITEMS];


void AbortGame()
{
  int rc;

  TellServer(ABORT_KEY, 1);
  GameStop=1;

  CleanupSounds();

  if (GameType==SINGLE_PLAYER) {
    rc=pthread_join(ServerThread, NULL);
    if (!rc) {
      ReadServerConfig(ServerConfigFileName);
    }
  }

  ReadConfig();

  pthread_mutex_unlock(&ClientLock);
  InitMatrixMode();
  glutKeyboardFunc(MainMenuKey);
  glutKeyboardUpFunc(NULL);
  glutSpecialFunc(MainMenuSpecialKey);
  glutIdleFunc(NULL);
  glutDisplayFunc(MainMenu);
  MainMenu();
}


void MainMenu()
{
  SetupMainDisplay();
  ClearScreen();
  DrawMainMenu();
  UpdateScreen();
}


void ConfMenu()
{
  SetupConfDisplay();
  ClearScreen();
  DrawConfMenu();
  UpdateScreen();
}


void ScoreMenu()
{
  ClearScreen();
  DrawScoreMenu();
  UpdateScreen();
}


// Function to handle reading in one key
void SetKeyValue()
{
  char KeyText[80]="Enter key for ";

  strcat(KeyText, KeyName);

  ClearScreen();
  DrawText(ScreenWidth/2-100, ScreenHeight/2, KeyText, &Red, 1);
  UpdateScreen();
}


// Function to handle reading in text entry
void TextEntry()
{
  int pos;

  ClearScreen();
  pos=DrawText(ScreenWidth/2-200, ScreenHeight/2, TextName, &Blue, 1);
  DrawRect(pos+17, ScreenHeight/2-2, pos+17, ScreenHeight/2+20,
	   pos+300, ScreenHeight/2+20, pos+300, ScreenHeight/2-2, &DarkGray);
  pos=DrawText(pos+20, ScreenHeight/2, TextValue, &Red, 1);
  DrawRect(pos+2, ScreenHeight/2, pos+2, ScreenHeight/2+15,
	   pos+8, ScreenHeight/2+15, pos+8, ScreenHeight/2, &White);
  UpdateScreen();
}


// Function to handle reading in entry of high score name
void ScoreEntry()
{
  int pos;

  ClearScreen();
  DrawText(ScreenWidth/2-200, ScreenHeight/2+50,
	   "Congratulations, you've made a high score", &Blue, 1);
  pos=DrawText(ScreenWidth/2-200, ScreenHeight/2, "Enter Name", &Blue, 1);
  DrawRect(pos+17, ScreenHeight/2-2, pos+17, ScreenHeight/2+20,
	   pos+300, ScreenHeight/2+20, pos+300, ScreenHeight/2-2, &DarkGray);
  pos=DrawText(pos+20, ScreenHeight/2, TextValue, &Red, 1);
  DrawRect(pos+2, ScreenHeight/2, pos+2, ScreenHeight/2+15,
	   pos+8, ScreenHeight/2+15, pos+8, ScreenHeight/2, &White);
  UpdateScreen();
}


// Function to handle reading in text entry of integer
void IntTextEntry()
{
  int pos;
  char Value[80];

  sprintf(Value, "%d", *IntValue);

  ClearScreen();
  pos=DrawText(ScreenWidth/2-200, ScreenHeight/2, TextName, &Blue, 1);
  DrawRect(pos+17, ScreenHeight/2-2, pos+17, ScreenHeight/2+20,
	   pos+300, ScreenHeight/2+20, pos+300, ScreenHeight/2-2, &DarkGray);
  pos+=20;
  pos=DrawText(pos, ScreenHeight/2, Value, &Red, 1);

  DrawRect(pos+2, ScreenHeight/2, pos+2, ScreenHeight/2+15,
	   pos+8, ScreenHeight/2+15, pos+8, ScreenHeight/2, &White);
  UpdateScreen();
}


void DrawMainMenu()
{
  int i;
  struct Color *TextColor;

  for (i=TopItemDisplayed; i<=BottomItemDisplayed; i++) {
    if (i==MainMenuItemHighlighted) {
      TextColor=&White;
    } else {
      TextColor=&Blue;
    }
    DrawText(ScreenWidth/2-100,
             ScreenHeight-MainMenuStartHeight-25*(i-TopItemDisplayed),
             MainMenuItems[i].ItemText, TextColor, 1);
  }
}


void DrawConfMenu()
{
  int i, pos;
  char tempval[80];
  struct Color *TextColor;

  for (i=TopItemDisplayed; i<=BottomItemDisplayed; i++) {
    if (i==ConfMenuItemHighlighted) {
      TextColor=&White;
    } else {
      TextColor=&Blue;
    }
    pos=DrawText(ScreenWidth/2-200,
                 ScreenHeight-ConfMenuStartHeight-25*(i-TopItemDisplayed),
                 ConfMenuItems[i].ItemText, TextColor, 1);
    if (ConfMenuItems[i].EntryValue) {
      if (ConfMenuItems[i].EntryType==0) {
        strcpy(tempval, (char *)ConfMenuItems[i].EntryValue);
      } else if (ConfMenuItems[i].EntryType==1) {
        sprintf(tempval, "%d", *(int *)ConfMenuItems[i].EntryValue);
      } else if (ConfMenuItems[i].EntryType==2) {
        sprintf(tempval, "%c", *(char *)ConfMenuItems[i].EntryValue);
      }
      DrawText(pos+20, ScreenHeight-ConfMenuStartHeight-25*(i-TopItemDisplayed),
               tempval, &Red, 1);
    }
  }
}


void InitMainMenu()
{
  int itemnum=0;

  MainMenuItemHighlighted=0;

  strcpy(MainMenuItems[itemnum].ItemText, "Start Single Player Game");
  MainMenuItems[itemnum].ItemFunction=StartSingleGame;
  itemnum++;
  strcpy(MainMenuItems[itemnum].ItemText, "Start Multi Player Game");
  MainMenuItems[itemnum].ItemFunction=StartMultiGame;
  itemnum++;
  strcpy(MainMenuItems[itemnum].ItemText, "Start ATR Server");
  MainMenuItems[itemnum].ItemFunction=StartServer;
  itemnum++;
  strcpy(MainMenuItems[itemnum].ItemText, "Stop ATR Server");
  MainMenuItems[itemnum].ItemFunction=KillServer;
  itemnum++;
  strcpy(MainMenuItems[itemnum].ItemText, "Edit Game Configuration");
  MainMenuItems[itemnum].ItemFunction=SetupConfMenu;
  itemnum++;
  strcpy(MainMenuItems[itemnum].ItemText, "View High Scores");
  MainMenuItems[itemnum].ItemFunction=SetupScoreMenu;
  itemnum++;
  strcpy(MainMenuItems[itemnum].ItemText, "Quit Game");
  MainMenuItems[itemnum].ItemFunction=QuitGame;
  itemnum++;

  NumMainMenuItems=itemnum;

  if (NumMainMenuItems*25 <= ScreenHeight-25) {
    MainMenuStartHeight=(ScreenHeight-(NumMainMenuItems+1)*25+50)/2;
  } else {
    MainMenuStartHeight=25+25/2;
  }
}


void DrawScoreMenu()
{
  int i;
  char Score[10];
  int NumScoresDisplayed;
  struct Color *TextColor;

  DrawText(20, ScreenHeight-50, "Name", &Blue, 1);
  DrawText(ScreenWidth/2, ScreenHeight-50, "Score", &Blue, 1);

  NumScoresDisplayed=(ScreenHeight-(150+25*NumScoreMenuItems))/25;
  if (NumScoresDisplayed > NUM_HIGHSCORES) {
    NumScoresDisplayed=NUM_HIGHSCORES;
  }

  for (i=0; i<NumScoresDisplayed; i++) {
    sprintf(Score, "%d", HighScores[i].Score);
    DrawText(20, ScreenHeight-90-25*i, HighScores[i].Name, &Red, 1);
    DrawText(ScreenWidth/2, ScreenHeight-90-25*i, Score, &Red, 1);
  }

  for (i=0; i<NumScoreMenuItems; i++) {
    if (i==ScoreMenuItemHighlighted) {
      TextColor=&White;
    } else {
      TextColor=&Blue;
    }
    DrawText(ScreenWidth/2-100, 25*(NumScoreMenuItems-i+1), ScoreMenuItems[i].ItemText, TextColor, 1);
  }
}


void InitConfMenu()
{
  int itemnum=0;

  ConfMenuItemHighlighted=0;
  strcpy(ConfMenuItems[itemnum].ItemText, "Server IP (MultiPlayer Only)");
  strcpy(ConfMenuItems[itemnum].EntryText, "Enter Server IP");
  ConfMenuItems[itemnum].EntryValue=ServerIP;
  ConfMenuItems[itemnum].EntryLength=15;
  ConfMenuItems[itemnum].EntryType=0;
  ConfMenuItems[itemnum].EntryFunction=SetValue;
  ConfMenuItems[itemnum].ItemFunction=NULL;
  itemnum++;
  strcpy(ConfMenuItems[itemnum].ItemText, "Server Port (MultiPlayer Only)");
  strcpy(ConfMenuItems[itemnum].EntryText, "Enter Server Port");
  ConfMenuItems[itemnum].EntryValue=&ServerPort;
  ConfMenuItems[itemnum].EntryLength=5;
  ConfMenuItems[itemnum].EntryType=1;
  ConfMenuItems[itemnum].EntryFunction=SetValue;
  ConfMenuItems[itemnum].ItemFunction=NULL;
  itemnum++;
  strcpy(ConfMenuItems[itemnum].ItemText, "Player Name (MultiPlayer Only)");
  strcpy(ConfMenuItems[itemnum].EntryText, "Enter Player Name");
  ConfMenuItems[itemnum].EntryValue=PlayerName;
  ConfMenuItems[itemnum].EntryLength=MAX_PLAYERNAME_LENGTH-1;
  ConfMenuItems[itemnum].EntryType=0;
  ConfMenuItems[itemnum].EntryFunction=SetValue;
  ConfMenuItems[itemnum].ItemFunction=NULL;
  itemnum++;
  strcpy(ConfMenuItems[itemnum].ItemText, "Screen Width");
  strcpy(ConfMenuItems[itemnum].EntryText, "Enter Screen Width");
  ConfMenuItems[itemnum].EntryValue=&NewScreenWidth;
  ConfMenuItems[itemnum].EntryLength=4;
  ConfMenuItems[itemnum].EntryType=1;
  ConfMenuItems[itemnum].EntryFunction=SetValue;
  ConfMenuItems[itemnum].ItemFunction=NULL;
  itemnum++;
  strcpy(ConfMenuItems[itemnum].ItemText, "Screen Height");
  strcpy(ConfMenuItems[itemnum].EntryText, "Enter Screen Height");
  ConfMenuItems[itemnum].EntryValue=&NewScreenHeight;
  ConfMenuItems[itemnum].EntryLength=4;
  ConfMenuItems[itemnum].EntryType=1;
  ConfMenuItems[itemnum].EntryFunction=SetValue;
  ConfMenuItems[itemnum].ItemFunction=NULL;
  itemnum++;
  strcpy(ConfMenuItems[itemnum].ItemText, "Volume");
  strcpy(ConfMenuItems[itemnum].EntryText, "Enter Volume (Values 0 through 9)");
  ConfMenuItems[itemnum].EntryValue=&newvolume;
  ConfMenuItems[itemnum].EntryLength=1;
  ConfMenuItems[itemnum].EntryType=1;
  ConfMenuItems[itemnum].EntryFunction=SetValue;
  ConfMenuItems[itemnum].ItemFunction=NULL;
  itemnum++;
  strcpy(ConfMenuItems[itemnum].ItemText, "Score Key (DeathMatch Only)");
  strcpy(ConfMenuItems[itemnum].EntryText, "Enter Score Key");
  ConfMenuItems[itemnum].EntryValue=&controls.Score;
  ConfMenuItems[itemnum].EntryLength=1;
  ConfMenuItems[itemnum].EntryType=2;
  ConfMenuItems[itemnum].EntryFunction=SetValue;
  ConfMenuItems[itemnum].ItemFunction=NULL;
  itemnum++;
  strcpy(ConfMenuItems[itemnum].ItemText, "Fire Key");
  strcpy(ConfMenuItems[itemnum].EntryText, "Enter Fire Key");
  ConfMenuItems[itemnum].EntryValue=&controls.Fire;
  ConfMenuItems[itemnum].EntryLength=1;
  ConfMenuItems[itemnum].EntryType=2;
  ConfMenuItems[itemnum].EntryFunction=SetValue;
  ConfMenuItems[itemnum].ItemFunction=NULL;
  itemnum++;
  strcpy(ConfMenuItems[itemnum].ItemText, "Shield Key");
  strcpy(ConfMenuItems[itemnum].EntryText, "Enter Shield Key");
  ConfMenuItems[itemnum].EntryValue=&controls.Shield;
  ConfMenuItems[itemnum].EntryLength=1;
  ConfMenuItems[itemnum].EntryType=2;
  ConfMenuItems[itemnum].EntryFunction=SetValue;
  ConfMenuItems[itemnum].ItemFunction=NULL;
  itemnum++;
  strcpy(ConfMenuItems[itemnum].ItemText, "Warp Key");
  strcpy(ConfMenuItems[itemnum].EntryText, "Enter Warp Key");
  ConfMenuItems[itemnum].EntryValue=&controls.Warp;
  ConfMenuItems[itemnum].EntryLength=1;
  ConfMenuItems[itemnum].EntryType=2;
  ConfMenuItems[itemnum].EntryFunction=SetValue;
  ConfMenuItems[itemnum].ItemFunction=NULL;
  itemnum++;
  strcpy(ConfMenuItems[itemnum].ItemText, "Nuke Key");
  strcpy(ConfMenuItems[itemnum].EntryText, "Enter Nuke Key");
  ConfMenuItems[itemnum].EntryValue=&controls.Nuke;
  ConfMenuItems[itemnum].EntryLength=1;
  ConfMenuItems[itemnum].EntryType=2;
  ConfMenuItems[itemnum].EntryFunction=SetValue;
  ConfMenuItems[itemnum].ItemFunction=NULL;
  itemnum++;
  strcpy(ConfMenuItems[itemnum].ItemText, "Quit Key");
  strcpy(ConfMenuItems[itemnum].EntryText, "Enter Quit Key");
  ConfMenuItems[itemnum].EntryValue=&controls.Quit;
  ConfMenuItems[itemnum].EntryLength=1;
  ConfMenuItems[itemnum].EntryType=2;
  ConfMenuItems[itemnum].EntryFunction=SetValue;
  ConfMenuItems[itemnum].ItemFunction=NULL;
  itemnum++;
  /*
    strcpy(ConfMenuItems[itemnum].ItemText, "x Forward Key");
    strcpy(ConfMenuItems[itemnum].EntryText, "Enter x Forward Key");
    ConfMenuItems[itemnum].EntryValue=&controls.xForward;
    ConfMenuItems[itemnum].EntryLength=1;
    ConfMenuItems[itemnum].EntryType=2;
    ConfMenuItems[itemnum].EntryFunction=SetValue;
    ConfMenuItems[itemnum].ItemFunction=NULL;
    itemnum++;
    strcpy(ConfMenuItems[itemnum].ItemText, "x Backward Key");
    strcpy(ConfMenuItems[itemnum].EntryText, "Enter x Backward Key");
    ConfMenuItems[itemnum].EntryValue=&controls.xBackward;
    ConfMenuItems[itemnum].EntryLength=1;
    ConfMenuItems[itemnum].EntryType=2;
    ConfMenuItems[itemnum].EntryFunction=SetValue;
    ConfMenuItems[itemnum].ItemFunction=NULL;
    itemnum++;
    strcpy(ConfMenuItems[itemnum].ItemText, "y Forward Key");
    strcpy(ConfMenuItems[itemnum].EntryText, "Enter y Forward Key");
    ConfMenuItems[itemnum].EntryValue=&controls.yForward;
    ConfMenuItems[itemnum].EntryLength=1;
    ConfMenuItems[itemnum].EntryType=2;
    ConfMenuItems[itemnum].EntryFunction=SetValue;
    ConfMenuItems[itemnum].ItemFunction=NULL;
    itemnum++;
    strcpy(ConfMenuItems[itemnum].ItemText, "y Backward Key");
    strcpy(ConfMenuItems[itemnum].EntryText, "Enter y Backward Key");
    ConfMenuItems[itemnum].EntryValue=&controls.yBackward;
    ConfMenuItems[itemnum].EntryLength=1;
    ConfMenuItems[itemnum].EntryType=2;
    ConfMenuItems[itemnum].EntryFunction=SetValue;
    ConfMenuItems[itemnum].ItemFunction=NULL;
    itemnum++;
  */
  strcpy(ConfMenuItems[itemnum].ItemText, "Forward Thrust Key");
  strcpy(ConfMenuItems[itemnum].EntryText, "Enter Forward Thrust Key");
  ConfMenuItems[itemnum].EntryValue=&controls.zForward;
  ConfMenuItems[itemnum].EntryLength=1;
  ConfMenuItems[itemnum].EntryType=2;
  ConfMenuItems[itemnum].EntryFunction=SetValue;
  ConfMenuItems[itemnum].ItemFunction=NULL;
  itemnum++;
  strcpy(ConfMenuItems[itemnum].ItemText, "Reverse Thrust Key");
  strcpy(ConfMenuItems[itemnum].EntryText, "Enter Reverse Thrust Key");
  ConfMenuItems[itemnum].EntryValue=&controls.zBackward;
  ConfMenuItems[itemnum].EntryLength=1;
  ConfMenuItems[itemnum].EntryType=2;
  ConfMenuItems[itemnum].EntryFunction=SetValue;
  ConfMenuItems[itemnum].ItemFunction=NULL;
  itemnum++;
  strcpy(ConfMenuItems[itemnum].ItemText, "x Forward Rotate Key");
  strcpy(ConfMenuItems[itemnum].EntryText, "Enter x Forward Rotate Key");
  ConfMenuItems[itemnum].EntryValue=&controls.xFRotate;
  ConfMenuItems[itemnum].EntryLength=1;
  ConfMenuItems[itemnum].EntryType=2;
  ConfMenuItems[itemnum].EntryFunction=SetValue;
  ConfMenuItems[itemnum].ItemFunction=NULL;
  itemnum++;
  strcpy(ConfMenuItems[itemnum].ItemText, "x Backward Rotate Key");
  strcpy(ConfMenuItems[itemnum].EntryText, "Enter x Backward Rotate Key");
  ConfMenuItems[itemnum].EntryValue=&controls.xBRotate;
  ConfMenuItems[itemnum].EntryLength=1;
  ConfMenuItems[itemnum].EntryType=2;
  ConfMenuItems[itemnum].EntryFunction=SetValue;
  ConfMenuItems[itemnum].ItemFunction=NULL;
  itemnum++;
  strcpy(ConfMenuItems[itemnum].ItemText, "y Forward Rotate Key");
  strcpy(ConfMenuItems[itemnum].EntryText, "Enter y Forward Rotate Key");
  ConfMenuItems[itemnum].EntryValue=&controls.yFRotate;
  ConfMenuItems[itemnum].EntryLength=1;
  ConfMenuItems[itemnum].EntryType=2;
  ConfMenuItems[itemnum].EntryFunction=SetValue;
  ConfMenuItems[itemnum].ItemFunction=NULL;
  itemnum++;
  strcpy(ConfMenuItems[itemnum].ItemText, "y Backward Rotate Key");
  strcpy(ConfMenuItems[itemnum].EntryText, "Enter y Backward Rotate Key");
  ConfMenuItems[itemnum].EntryValue=&controls.yBRotate;
  ConfMenuItems[itemnum].EntryLength=1;
  ConfMenuItems[itemnum].EntryType=2;
  ConfMenuItems[itemnum].EntryFunction=SetValue;
  ConfMenuItems[itemnum].ItemFunction=NULL;
  itemnum++;
  strcpy(ConfMenuItems[itemnum].ItemText, "z Forward Rotate Key");
  strcpy(ConfMenuItems[itemnum].EntryText, "Enter z Forward Rotate Key");
  ConfMenuItems[itemnum].EntryValue=&controls.zFRotate;
  ConfMenuItems[itemnum].EntryLength=1;
  ConfMenuItems[itemnum].EntryType=2;
  ConfMenuItems[itemnum].EntryFunction=SetValue;
  ConfMenuItems[itemnum].ItemFunction=NULL;
  itemnum++;
  strcpy(ConfMenuItems[itemnum].ItemText, "z Backward Rotate Key");
  strcpy(ConfMenuItems[itemnum].EntryText, "Enter z Backward Rotate Key");
  ConfMenuItems[itemnum].EntryValue=&controls.zBRotate;
  ConfMenuItems[itemnum].EntryLength=1;
  ConfMenuItems[itemnum].EntryType=2;
  ConfMenuItems[itemnum].EntryFunction=SetValue;
  ConfMenuItems[itemnum].ItemFunction=NULL;
  itemnum++;
  strcpy(ConfMenuItems[itemnum].ItemText, "Reverse View Key");
  strcpy(ConfMenuItems[itemnum].EntryText, "Enter Reverse View Key");
  ConfMenuItems[itemnum].EntryValue=&controls.rView;
  ConfMenuItems[itemnum].EntryLength=1;
  ConfMenuItems[itemnum].EntryType=2;
  ConfMenuItems[itemnum].EntryFunction=SetValue;
  ConfMenuItems[itemnum].ItemFunction=NULL;
  itemnum++;
  strcpy(ConfMenuItems[itemnum].ItemText, "Save Settings As Defaults");
  *ConfMenuItems[itemnum].EntryText='\0';
  ConfMenuItems[itemnum].EntryValue=NULL;
  ConfMenuItems[itemnum].EntryLength=0;
  ConfMenuItems[itemnum].EntryType=0;
  ConfMenuItems[itemnum].EntryFunction=NULL;
  ConfMenuItems[itemnum].ItemFunction=SaveConfig;
  itemnum++;
  strcpy(ConfMenuItems[itemnum].ItemText, "Return To Main Menu");
  *ConfMenuItems[itemnum].EntryText='\0';
  ConfMenuItems[itemnum].EntryValue=NULL;
  ConfMenuItems[itemnum].EntryLength=0;
  ConfMenuItems[itemnum].EntryType=0;
  ConfMenuItems[itemnum].EntryFunction=NULL;
  ConfMenuItems[itemnum].ItemFunction=SetupMainMenu;
  itemnum++;

  NumConfMenuItems=itemnum;

  if (NumConfMenuItems*25 <= ScreenHeight-25) {
    ConfMenuStartHeight=(ScreenHeight-NumConfMenuItems*25+50)/2;
  } else {
    ConfMenuStartHeight=25+25/2;
  }
}


void InitScoreMenu()
{
  int itemnum=0;

  ScoreMenuItemHighlighted=0;

  strcpy(ScoreMenuItems[itemnum].ItemText, "Clear High Scores");
  ScoreMenuItems[itemnum].ItemFunction=ClearHighScores;
  itemnum++;
  strcpy(ScoreMenuItems[itemnum].ItemText, "Return To Main Menu");
  ScoreMenuItems[itemnum].ItemFunction=SetupMainMenu;
  itemnum++;

  NumScoreMenuItems=itemnum;
}


void SetupMainDisplay()
{
  if (TopItemDisplayed > MainMenuItemHighlighted) {
    TopItemDisplayed=MainMenuItemHighlighted;
  }
  BottomItemDisplayed=TopItemDisplayed+(ScreenHeight-50)/25;
  if (BottomItemDisplayed >= NumMainMenuItems) {
    BottomItemDisplayed=NumMainMenuItems-1;
    TopItemDisplayed=BottomItemDisplayed-(ScreenHeight-50)/25;
    if (TopItemDisplayed < 0) {
      TopItemDisplayed=0;
    }
  }
  if (BottomItemDisplayed < MainMenuItemHighlighted) {
    TopItemDisplayed+=MainMenuItemHighlighted-BottomItemDisplayed;
    BottomItemDisplayed=MainMenuItemHighlighted;
  }
}


void SetupConfDisplay()
{
  if (TopItemDisplayed > ConfMenuItemHighlighted) {
    TopItemDisplayed=ConfMenuItemHighlighted;
  }
  BottomItemDisplayed=TopItemDisplayed+(ScreenHeight-50)/25;
  if (BottomItemDisplayed >= NumConfMenuItems) {
    BottomItemDisplayed=NumConfMenuItems-1;
    TopItemDisplayed=BottomItemDisplayed-(ScreenHeight-50)/25;
    if (TopItemDisplayed < 0) {
      TopItemDisplayed=0;
    }
  }
  if (BottomItemDisplayed < ConfMenuItemHighlighted) {
    TopItemDisplayed+=ConfMenuItemHighlighted-BottomItemDisplayed;
    BottomItemDisplayed=ConfMenuItemHighlighted;
  }
}


// Handle item selected from main menu
void MainMenuItemSelected()
{
  MainMenuItems[MainMenuItemHighlighted].ItemFunction();
}


void ConfMenuItemSelected()
{
  if (ConfMenuItems[ConfMenuItemHighlighted].EntryFunction) {
    ConfMenuItems[ConfMenuItemHighlighted].EntryFunction(ConfMenuItems[ConfMenuItemHighlighted].EntryText,
                                                         ConfMenuItems[ConfMenuItemHighlighted].EntryValue,
                                                         ConfMenuItems[ConfMenuItemHighlighted].EntryLength,
                                                         ConfMenuItems[ConfMenuItemHighlighted].EntryType);
  } else if (ConfMenuItems[ConfMenuItemHighlighted].ItemFunction) {
    ConfMenuItems[ConfMenuItemHighlighted].ItemFunction();
  }
}


void ScoreMenuItemSelected()
{
  ScoreMenuItems[ScoreMenuItemHighlighted].ItemFunction();
}


void SetValue(char *ValueText, void *Value, int ValueLength, int type)
{
  if (type==0) {
    SetText(ValueText, (char *)Value, ValueLength);
  } else if (type==1) {
    SetIntText(ValueText, (int *)Value, ValueLength);
  } else {
    SetKey(ValueText, (char *)Value);
  }
}


void SetKey(char *KeyId, char *Key)
{
  strcpy(KeyName, KeyId);
  KeyValue=Key;

  glutKeyboardFunc(SetKeyValueKey);
  glutSpecialFunc(NULL);
  glutIdleFunc(NULL);
  glutDisplayFunc(SetKeyValue);
  SetKeyValue();
}


void SetText(char *TextId, char *Text, int MaxLength)
{
  strcpy(TextName, TextId);
  TextValue=Text;
  MaxTextLength=MaxLength;

  glutKeyboardFunc(TextEntryKey);
  glutSpecialFunc(NULL);
  glutIdleFunc(NULL);
  glutDisplayFunc(TextEntry);
  TextEntry();
}


void SetIntText(char *TextId, int *Value, int MaxLength)
{
  strcpy(TextName, TextId);
  IntValue=Value;
  MaxTextLength=MaxLength;

  glutKeyboardFunc(IntTextEntryKey);
  glutSpecialFunc(NULL);
  glutIdleFunc(NULL);
  glutDisplayFunc(IntTextEntry);
  IntTextEntry();
}


void SetupMainMenu()
{
  glutKeyboardFunc(MainMenuKey);
  glutKeyboardUpFunc(NULL);
  glutSpecialFunc(MainMenuSpecialKey);
  glutIdleFunc(NULL);
  glutDisplayFunc(MainMenu);
  MainMenu();
}


void SetupConfMenu()
{
  glutKeyboardFunc(ConfMenuKey);
  glutSpecialFunc(ConfMenuSpecialKey);
  glutIdleFunc(NULL);
  glutDisplayFunc(ConfMenu);
  ConfMenu();
}


void SetupScoreMenu()
{
  glutKeyboardFunc(ScoreMenuKey);
  glutSpecialFunc(ScoreMenuSpecialKey);
  glutIdleFunc(NULL);
  glutDisplayFunc(ScoreMenu);
  ScoreMenu();
}


void StartSingleGame()
{
  pthread_attr_t attr;

  if (!ServerStarted) {
    playsound(PrizeSound);
    glutSpecialFunc(NULL);
    glutKeyboardFunc(KeyDown);
    glutKeyboardUpFunc(KeyUp);
    glutIdleFunc(RunGame);
    glutDisplayFunc(RunGame);

    InitMatrixMode();
    SetupGameMatrixMode();
    strcpy(ServerIP, "127.0.0.1");
    ServerPort=12345;

    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, !PTHREAD_CREATE_DETACHED);
    if (pthread_create(&ServerThread, &attr, Server, NULL)) {
      printf("Pthread error\n");
      exit(1);
    }
    pthread_attr_destroy(&attr);

    ServerStarted=1;
    GameStop=0;
    sleep(1);
    NewGame();
  } else {
    playsound(ErrorSound);
  }
}


void StartMultiGame()
{
  playsound(PrizeSound);
  glutSpecialFunc(NULL);
  glutKeyboardFunc(KeyDown);
  glutKeyboardUpFunc(KeyUp);
  glutIdleFunc(RunGame);
  glutDisplayFunc(RunGame);
  InitMatrixMode();
  SetupGameMatrixMode();
  GameStop=0;
  NewGame();
}


void StartServer()
{
  pthread_attr_t attr;

  if (!ServerStarted) {
    playsound(PrizeSound);

    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, !PTHREAD_CREATE_DETACHED);
    if (pthread_create(&ServerThread, &attr, Server, (void *)1)) {
      printf("Pthread error\n");
      exit(1);
    }
    pthread_attr_destroy(&attr);

    ServerStarted=1;
    sleep(1);
  } else {
    playsound(ErrorSound);
  }
}


void KillServer()
{
  if (ServerStarted) {
    ServerStarted=1;
    StopServer=1;
    pthread_join(ServerThread, NULL);
  } else {
    playsound(ErrorSound);
  }
}


void QuitGame()
{
  exit(0);
}
