#ifdef _LINUX
#include "stdafx.h"
//#include <csl/csl.h> //********************************* rabbahiff
#include <esd.h>
#include <unistd.h>

# include <sys/time.h>
# include <ctype.h>
# include "CSBTypes.h"

#include <stdio.h>

#include "UI.h"
#include "Objects.h"
#include "Dispatch.h"
#include "CSB.h"
#include "Data.h"

void EnqueMouseClick(i32, i32, i32);
void  TAG001afe(i32, i32, i32);
i32 AddSD(char *, i32, float, float, float);
void ItemsRemaining(i32 mode);
char *parentFolder(char *folderName, char *endName);

extern i32 WindowHeight;
extern i32 WindowWidth;
extern i32 WindowX;
extern i32 WindowY;
extern bool fullscreenRequested;
extern bool fullscreenActive;

extern ui32 TImER;
extern i32 VBLperTimer;
extern i32 VBLMultiplier;
extern i32 screenSize;
extern i32 keyboardMode;
extern i32 trace;
void PlayfileOpen(bool);
void RecordfileOpen(bool);
void RecordfilePreOpen(void);
extern bool BeginRecordOK;
extern bool TimerTraceActive;
extern bool AttackTraceActive;
extern bool RepeatGame;
extern i32 NoSpeedLimit;
bool OpenTraceFile(void);
void CloseTraceFile(void);
extern bool cursorIsShowing;
extern bool RecordCommandOption;
extern bool NoRecordCommandOption;

extern HWND hWnd;
extern HDC hdc;

#define maxMessageStack 20
CSB_UI_MESSAGE msgStack[maxMessageStack];
i32 msgStackLen = 0;
i32 messageMask = 1; //Right now just 0 or 1

i32 latestScanp1 = 0;
i32 latestScanp2 = 0;
XLATETYPE latestScanType = TYPEIGNORED;
i32 latestScanXlate = 0;
XLATETYPE latestCharType = TYPEIGNORED;
i32 latestCharp1 = 0;
i32 latestCharXlate = 0;
char *PlayfileName = "Playfile.log";
char *dungeonName = "dungeon.dat";
extern char *folderSavedGame="./";
bool PlaybackCommandOption = false;
bool RecordCommandOption = false;
bool NoRecordCommandOption = false;
bool RecordDesignOption = false;
bool DMRulesDesignOption = false;
bool RecordMenuOption = false;
bool NoRecordMenuOption = false;
bool extendedPortraits = false;

i32 keyQueueStart=0; // Next key to process
i32 keyQueueEnd=0;   // Next Empty entry
i32 keyQueueLen=3;
i32 keyQueue[3];


class KEYXLATE 
{
private:
  i32 m_numkey;
  i32 *m_xlate;
public:
  KEYXLATE(void)
  {
    m_numkey=0;
    m_xlate=NULL;
  };
  ~KEYXLATE(void)
  {
    if (m_xlate!=NULL) UI_free(m_xlate);
    m_xlate = NULL;
  };
  void addkey(i32 scan, i32 key, i32 mode, XLATETYPE type);
  i32 translate(i32 scan, i32 mode, XLATETYPE type);
};

void KEYXLATE::addkey(i32 scan, i32 key, i32 mode, XLATETYPE type)
{
  m_xlate = (i32 *)UI_realloc(m_xlate, 16*(m_numkey+1));
  m_xlate[m_numkey*4+0] = scan;
  m_xlate[m_numkey*4+1] = key;
  m_xlate[m_numkey*4+2] = mode;
  m_xlate[m_numkey*4+3] = type;
  m_numkey++;
}

i32 KEYXLATE::translate(i32 scan, i32 mode, XLATETYPE type)
{
  for (i32 i=0; i<m_numkey; i++)
  {
    if (   (m_xlate[4*i+0] == scan)
        && (m_xlate[4*i+2] == mode) 
        && (m_xlate[4*i+3] == type) ) return m_xlate[4*i+1];
  };
  return 0;
}

KEYXLATE keyxlate;

char *getfield(char *buf, i32& col)
{
  static char result[200];
  char term;
  i32 len = 0;
  term = ' ';
  while (buf[col] != '\n')
  {
    if ((buf[col]!=' ') && (buf[col]!='\t')) break;
    col++;
  };
  if (buf[col] == '"')
  {
    term = '"';
    col++;
  };
  while (buf[col] != '\n')
  {
    if (   (buf[col]==term) 
        || ((term==' ') && (buf[col]=='\t'))) break;
    result[len++] = buf[col];
    if (len>198) len--;
    col++;
  };
  result[len]=0;
  return result;
}

i32 gethex(char *buf, i32& col)
{
  i32 result;
  char *field;
  field = getfield(buf,col);
  sscanf(field,"%x", &result);
  return result;
}

i32 AddSmartDiscard(char *buf)
{
  char fld[10][200];
  i32 i, j, col=0;
  i32 minimum;
  float level,y_intercept,slope;
  char *pfld;
  for (i=0; i<10; i++)
  {
    pfld=getfield(buf,col);
    if (*pfld == 0) break;
    strcpy(fld[i],pfld);
  };
  j=1;
  while (i>5)
  {
    if ((fld[j][0]>='A') && (fld[j][0]<='Z'))
    {
      strcat(fld[0]," ");
      strcat(fld[0],fld[j]);
      j++;
      i--;
    }
    else break;
  };
  if (i<5) return 1; //error
  if (sscanf(fld[j],"%d",&minimum)!=1) return 1;
  if (sscanf(fld[j+1],"%f",&level)!=1) return 1;
  if (sscanf(fld[j+2],"%f",&y_intercept)!=1) return 1;
  if (sscanf(fld[j+3],"%f",&slope)!=1) return 1;
  return AddSD(fld[0],minimum,level,y_intercept,slope);
  //return 0;
}


/************************************************************************
* Smart Discard definitions
*
*Smart Discard only operates on databases which have been enlarged
* to size 1023.  Each item in a database is given a discard priority
* which is compared to other items in the same database.  The item with
* the highest priority is discarded first.
*
* The program operates as follows:  every clock tick initiates the
* "Smart Discard" process.  The databases are considered one at a time.
* Each clock tick causes the items in a single room to be evaluated and
* added to the list.  When all rooms have been evaluated and there are
* fewer than 900 items in the database then the next database is considered.
* If more than 900 items exist then on each tick of the clock the item
* with the highest discard priority has its priority recomputed.  If it
* is still at least as great as the next higher item then it is deleted.
* On the other hand, if its priority has declined (perhaps due to party
* movement, because we just discarded an item of this type, etc) then it 
* is put back in the list in its proper place and we wait for the next 
* clock tick.
*
* The priority calculation includes a random number between 0.0 and 1.0
* so that items with the same basic priority will be randomly selected.
*
* Format:
*
*   name  minimum  level  y-intercept  slope
*
*     name         item name - blanks are allowed  (or "default") (case-insensitive)
*     minimum      integer - If this many or fewer of the item exist then
*                            none will be considered for discard.
*     level        float - additional priority for not being on a level 
*                          adjacent to the party.
*     y-intercept  float - discard priority for minimum
*     slope        float - additional discard priority for each item over minimum
*
* The item's deletion priority is  y-intercept + slope*(num-minimum) + level
*     
* Let us provide an example:
*
* example   -->  Discard   Worm Round  20  10.0  0  1
*
* Worm Rounds are not considered for deletion unless there are more than
* 20 of them in the dungeon.  Assume there are 30 of them in the dungeon.
* The discard priority for each of the 30 Worm Rounds is equal to:
*         0 + 1*(30-20).
* Each Worm Round which is on a level not immediately adjacent to the party
* will have 10.0 added to its priority.
*
*/
char *SmartDiscards[] = {
"default       30  50  20.0   1.0",
"Wooden Shield 10  50  20.0   1.0", // We hardly need more than 10 of these 
"Rock          10  50  20.0   1.0",
"Sword         10  50  20.0   1.0",
"Dagger        10  50  20.0   1.0",
"Falchion      10  50  20.0   1.0",
"Club          10  50  20.0   1.0",
"Stone Club    10  50  20.0   1.0",
"Armet         10  50  20.0   1.0",
"Torso Plate   10  50  20.0   1.0",
"Leg Plate     10  50  20.0   1.0",
"Foot Plate    10  50  20.0   1.0",
//; Miscellaneous items
"Boulder       20  50  70.0   1.0", // Be sure Boulders go before food
"Dragon Steak 150   0  20.0   0.0", // Default goes before Dragon Steak.
 NULL
};

#ifdef _LINUX
#define strupr( a ) _strupr( a )
static void _strupr(char *str) {
    if( str ) {
	while(*str) {
	    *str = toupper( *str );
	    str++;
	}
    }
}
#endif
void ReadConfigFile(void)
{
  char buf[501];
  i16 f;
  i32 lineNumber = 0;
  i32 col, numerror=0;
  char *field;
  i32 scancode, key, mode;
  for (i32 i=0; SmartDiscards[i] != NULL; i++)
  {
    _strupr(SmartDiscards[i]);
    if (AddSmartDiscard(SmartDiscards[i]) == 0) continue;
  };
  f=OPEN("config.linux", "r");
  if (f < 0) {
      g_warning("Failed to open config.linux");
      return;
      }
  while (GETS(buf,500,f) != NULL)
  {
    lineNumber++;
    col=0;
    if (buf[0] == ';') continue;
    field=getfield(buf,col);
    _strupr(field);
    if (strcmp(field, ";")==0) continue;
    if (strcmp(field, "") ==0) continue;
    if (strcmp(field, "KEY")==0)
    {
      mode    =gethex(buf,col);
      scancode=gethex(buf,col);
      key     =gethex(buf,col);
      keyxlate.addkey(scancode, key, mode, TYPEKEY);
      continue;
    };
    if (strcmp(field,"SCAN")==0)
    {
      mode    =gethex(buf,col);
      scancode=gethex(buf,col);
      key     =gethex(buf,col);
      keyxlate.addkey(scancode, key, mode, TYPESCAN);
      continue;
    };
    if (strcmp(field,"MSCAN")==0)
    {
      i32 x, y;
      XLATETYPE type;
      char *button;
      mode    =gethex(buf,col);
      scancode=gethex(buf,col);
      x       =gethex(buf,col);
      y       =gethex(buf,col);
      button  =getfield(buf,col);
      _strupr(button);
      if (strcmp(button,"L")==0) type=TYPEMSCANL; else type=TYPEMSCANR;
      keyxlate.addkey(scancode, (x<<16)+y, mode, type);
      continue;
    };
    if (strcmp(field,"DIRECTORY")==0)
    {
      field = getfield(buf,col);
      if (folderName) continue; //cmd line has higher priority than config.linux
      folderName = (char *) UI_malloc(strlen(field) + 1,
                                      MALLOC030);
      if (folderName!=NULL)
      {
	if(folderParentName) continue; //cmd line has higher priority...
        strcpy(folderName, field);
        folderParentName = parentFolder(folderName, folderName+strlen(folderName+1));
      };
      continue;
    };
     if (strcmp(field,"TIMER")==0)
    {
      field = getfield(buf,col);
      if (TImER) continue; //cmd line has higher priority than config.linux
      //sscanf(TIMER,"%d", field);
      TImER=strtol( field,NULL, 10);
      continue;
    };
    if (strcmp(field,"PLACE") == 0)
    {
      i32 k, size, srcx, srcy, width, height, x, y;
      field = getfield(buf,col);
      if ( (field[0] < 'A')||(field[0] > 'E') ) continue;
      k = field[0] - 'A';
      size = gethex(buf,col);
      if ( (size < 0)||(size > 4) ) continue;
      srcx = gethex(buf,col);
      if ( (srcx<0) || (srcx>319) ) continue;
      srcy = gethex(buf,col);
      if ( (srcy<0) || (srcy>199) ) continue;
      width = gethex(buf,col);
      if ( (width<1) || (srcx+width>320) )continue;
      height = gethex(buf,col);
      if ( (height<1) || (srcy+height>200) )continue;
      x = gethex(buf,col);
      if ( (x < 0)||(x > 4096) ) continue;
      y = gethex(buf,col);
      if ( (y < 0)||(y >4096) ) continue;
      videoSegSize[k] = size;
      videoSegSrcX[k] = srcx;
      videoSegSrcY[k] = srcy;
      videoSegWidth[k] = width;
      videoSegHeight[k] = height;
      videoSegX[k] = x;
      videoSegY[k] = y;
      continue;
    };
    if (numerror==0)
    {
      char msg[200];
      if (strlen(buf)>0)
        if (buf[strlen(buf)-1] == '\n')
          buf[strlen(buf)-1] = 0;
      buf[100] = 0; //Just in case it is very long;
      sprintf(msg,"Line number = %d\n%s",lineNumber,buf);
      UI_MessageBox(msg,"Bad Config Line",MESSAGE_OK);
      numerror++;
    };
  };
  CLOSE(f);
}




i32 UI_DisableAllMessages(void)
{
  i32 oldmask = messageMask;
  messageMask = 0;
  return oldmask;
}

i32 UI_EnableMessages(i32 mask)
{
  messageMask |= mask;
  return messageMask;
}


i32 CSBUI(CSB_UI_MESSAGE *msg)
{
  i32 CallCheckVBL= 0;
  if (messageMask == 0) return UI_STATUS_NORMAL;
  try
  {
    switch (msg->type)
    {
    case UIM_INITIALIZE:
        ReadConfigFile();
        //Set the GameMode //0=quit
                           //1=dungeon
                           //2=utility
                           //3=hint
        DispatchCSB(st_AskWhatToDo);
        break;
    case UIM_SETOPTION:
      switch (msg->p1)
      {
      case OPT_DMRULES:
        DM_rules = !DM_rules;
        break;
      case OPT_NORMAL:
        screenSize = 1;
        break;
      case OPT_DOUBLE:
        if (msg->p2 == 1) screenSize = 1;
        else screenSize = 2;
        break;
      case OPT_TRIPLE:
        if (msg->p2 == 1) screenSize = 1;
        else screenSize = 3;
        break;
      case OPT_QUADRUPLE:
        if (msg->p2 == 1) screenSize = 1;
        else screenSize = 4;
        break;
      case OPT_RECORD:
        if (msg->p2 == 1)
	{
		RecordMenuOption = true; 
		NoRecordMenuOption = false;
	}
	else {
		//RecordfileOpen(true);
		RecordfileOpen(false);
		RecordMenuOption = false;
		NoRecordMenuOption = true;
	}
        break;
      case OPT_PLAYBACK:
        if (msg->p2 == 1) PlayfileOpen(true);
        else PlayfileOpen(false);
        break;
      case OPT_QUICKPLAY:
        if (msg->p2 == 1) NoSpeedLimit = 2000000000;
        else 
        {
          NoSpeedLimit = 0;
          VBLMultiplier = 1;
        };
        break;
      case OPT_CLOCK:
        gameSpeed = (SPEEDS)msg->p2;
        break;
      case OPT_VOLUME:
	gameVolume = (VOLUMES)msg->p2;
	break;
      case OPT_PLAYERCLOCK:
        playerClock = !playerClock;
        break;
      case OPT_EXTRATICKS:
        extraTicks = !extraTicks;
        break;
      case OPT_ITEMSREMAINING:
        ItemsRemaining(0);// "Defined" in AsciiDump.cpp
        break;
      case OPT_NONCSBITEMSREMAINING:
        ItemsRemaining(1);
        break;
      case OPT_TIMERTRACE:
        if (TimerTraceActive)
        {
          TimerTraceActive = false;
          if (!AttackTraceActive && !AITraceActive)
          {
            CloseTraceFile();
          };
        }
        else
        {
          if (AttackTraceActive || AITraceActive  || OpenTraceFile())
          {
            TimerTraceActive = true;
          };
        };
        break;
      case OPT_ATTACKTRACE:
        if (AttackTraceActive)
        {
          AttackTraceActive = false;
          if (!TimerTraceActive && !AITraceActive)
          {
            CloseTraceFile();
          };
        }
        else
        {
          if (TimerTraceActive || AITraceActive || OpenTraceFile())
          {
            AttackTraceActive = true;
          };
        };
        break;
      case OPT_AITRACE:
        if (AITraceActive)
        {
          AITraceActive = false;
          if (!TimerTraceActive && !AttackTraceActive)
          {
            CloseTraceFile();
          };
        }
        else
        {
          if (TimerTraceActive || AttackTraceActive || OpenTraceFile())
          {
            AITraceActive = true;
          };
        };
        break;
      default:
        ASSERT(0);
      };
      break;
    case UIM_TERMINATE:
        return UI_STATUS_TERMINATE; 
    case UIM_CHAR:
        {
          if ((latestCharp1 == 3) && (msg->p1 == 3))
          {
            UI_Die();
            break;
          };
          latestCharp1 = msg->p1;
          latestCharType = TYPEIGNORED;
          i32 key = keyxlate.translate(msg->p1, keyboardMode, TYPEKEY);
          if (key != 0)
          {
            i32 next = keyQueueEnd+1;
            latestCharType = TYPEKEY;
            latestCharXlate = key;
            if (next >= keyQueueLen) next=0;
            if (next != keyQueueStart)
            {
              keyQueue[keyQueueEnd]= key;
              keyQueueEnd = next;
            };
          }
        }
        break;
    case UIM_KEYDOWN:
        {
          i32 key;
          latestScanp1 = msg->p1;
          latestScanp2 = msg->p2;
          if ((key = keyxlate.translate(msg->p2&0xff, 
                                        keyboardMode, 
                                        TYPESCAN))!= 0)
          {
            latestScanType = TYPESCAN;
            latestScanXlate = key;
            i32 next = keyQueueEnd+1;
            if (next >= keyQueueLen) next=0;
            if (next != keyQueueStart)
            {
              keyQueue[keyQueueEnd]= key;
              keyQueueEnd = next;
            };
          }
          else
          if ((key = keyxlate.translate(msg->p1, keyboardMode, TYPEMSCANL))!= 0)
          {
            latestScanType = TYPEMSCANL;
            latestScanXlate = key;
            OnMouseSwitchAction(2, key>>16, key & 0xffff);
            OnMouseSwitchAction(0);
          }
          else
          if ((key = keyxlate.translate(msg->p1, keyboardMode, TYPEMSCANR))!= 0)
          {
            latestScanType = TYPEMSCANR;
            latestScanXlate = key;
            OnMouseSwitchAction(1, key>>16, key & 0xffff);
            OnMouseSwitchAction(0);
          }
          else
          {
            latestScanType = TYPEIGNORED;
          };
        }
        break;
    case UIM_TIMER:
        //The UIM_TIMER messages come no more often than
        //20 per second on my machine.  So we can cause multiple
        //VBLs per UIM_TIMER.  Our stategy is to call CheckVBL.
        //Then dispatch until nothing is left to do.  Then
        //call CheckVBL again.  Repeat entire process 10 times
        CallCheckVBL = VBLperTimer*VBLMultiplier; // do it 10 times
        if (trace >= 0) 
        {
          fprintf(GETFILE(trace),"UIM_TIMER\n");
          fflush(GETFILE(trace));
        }
        break;
    case UIM_PAINT:
        display();
        break;
    case UIM_REDRAW_ENTIRE_SCREEN:
        ForceScreenDraw();
        UI_Invalidate();
        break;
    case UIM_LEFT_BUTTON_DOWN:
	OnMouseSwitchAction(0x2);
	if (fullscreenActive)
	{
		i32 x,y,size;
		size = screenSize;
		TranslateFullscreen(msg->p1,msg->p2,x,y);
		EnqueMouseClick(x, y, 1);
		TAG001afe(x, y, 1);
	}
	else
	{
		EnqueMouseClick(X_TO_CSB(msg->p1,screenSize), Y_TO_CSB(msg->p2,screenSize),1);
		TAG001afe(X_TO_CSB(msg->p1,screenSize), Y_TO_CSB(msg->p2,screenSize), 1);
	}
	UI_PushMessage(msg->type);
	break;
    case UIM_LEFT_BUTTON_UP:
        OnMouseSwitchAction(0x0);
        break;
    case UIM_RIGHT_BUTTON_DOWN:
        OnMouseSwitchAction(0x1);
        if (fullscreenActive)
        {
          i32 x, y, size;
          size = screenSize;
          TranslateFullscreen(msg->p1,msg->p2,x,y);
          EnqueMouseClick(x, y, 1);
          TAG001afe(x, y, 1);
        }
        else
	{
		EnqueMouseClick(X_TO_CSB(msg->p1,screenSize), Y_TO_CSB(msg->p2,screenSize),1);
		TAG001afe(X_TO_CSB(msg->p2,screenSize), Y_TO_CSB(msg->p1,screenSize), 1);
	}
        UI_PushMessage(msg->type);
        break;
    case UIM_RIGHT_BUTTON_UP:
        OnMouseSwitchAction(0x0);
        break;
    case UIM_EditGameInfo:
	    //do nothing
    	break;
    default:
      ASSERT(0);
    };
    do
    {
      if (CallCheckVBL > 0)
      {
        checkVBL();
        CallCheckVBL--;
      };
      while (msgStackLen != 0)
      {
        msgStackLen--;
        if (msgStack[msgStackLen].type == UIM_TERMINATE)
        { 
          return UI_STATUS_TERMINATE;
        };
        DispatchCSB(&msgStack[msgStackLen]);
      };
    } while (CallCheckVBL > 0);
      return UI_STATUS_NORMAL;
  }
  catch (i32)
  {
      g_warning("Exception caught in: i32 CSBUI(CSB_UI_MESSAGE *msg)\n");
    return UI_STATUS_TERMINATE;
  };
};

void UI_PushMessage(MTYPE type,
                    i32 p1,i32 p2,i32 p3,i32 p4,i32 p5,i32 p6)
{
  if (msgStackLen >= maxMessageStack-1) UI_Die();
  msgStack[msgStackLen].type = type;
  msgStack[msgStackLen].p1 = p1;
  msgStack[msgStackLen].p2 = p2;
  msgStack[msgStackLen].p3 = p3;
  msgStack[msgStackLen].p4 = p4;
  msgStack[msgStackLen].p5 = p5;
  msgStack[msgStackLen].p6 = p6;
  msgStackLen++;
}
  


i32 UI_DeleteFile(char *fname)
{
  return (remove(fname)==0) ? 1 : 0;;
}


volatile gboolean dialog_not_clicked = TRUE;
volatile gint dialog_answer;
void __dialog_release( gpointer A ) { dialog_not_clicked = FALSE; }
void __dialog_unset( gpointer A ) { dialog_answer = 1; dialog_not_clicked = FALSE; gtk_widget_destroy(GTK_WIDGET(A)); }
void __dialog_reset( gpointer A ) { dialog_answer = 0; dialog_not_clicked = FALSE; gtk_widget_destroy(GTK_WIDGET(A)); }


i32 UI_MessageBox(char *msg, char *title, i32 flags ) {
    printf("\nMessageBox: [%s] %s", title, msg);
    GtkWidget *dialog;
    GString *text = g_string_new(msg);
	
  i32 i=1;// default answer
    if(title==NULL){
	title="Error: \n";    
    }else{
	text = g_string_prepend(text,": \n");
    }
    
    text = g_string_prepend(text,title);
   
  bool saveCursorShowing, cursorIsShowing, is_ok=false;
  saveCursorShowing = cursorIsShowing = ( SDL_ENABLE == SDL_ShowCursor(SDL_QUERY) );
  if (!cursorIsShowing) SDL_ShowCursor(SDL_ENABLE);
  
    GtkWidget *label, *yes_button, *no_button, *ok_button;
	dialog = gtk_dialog_new();
	label = gtk_label_new (text->str);
	dialog_not_clicked = TRUE;
	dialog_answer = 1;


      if (flags & MESSAGE_OK){
	ok_button = gtk_button_new_with_label("Okay");
	gtk_signal_connect_object (GTK_OBJECT (ok_button), "clicked",GTK_SIGNAL_FUNC (__dialog_reset),GTK_OBJECT( dialog ));
	gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),ok_button);
	is_ok=true;
  }
    else if (flags & MESSAGE_YESNO){
	yes_button = gtk_button_new_with_label("Yes");
	no_button = gtk_button_new_with_label("No");
	gtk_signal_connect_object (GTK_OBJECT (yes_button), "clicked",GTK_SIGNAL_FUNC (__dialog_reset), GTK_OBJECT(dialog));
	gtk_signal_connect_object (GTK_OBJECT (no_button), "clicked",GTK_SIGNAL_FUNC (__dialog_unset), GTK_OBJECT(dialog));
	gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),yes_button);
	gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),no_button);
   }   
   GtkWidget *hbox = gtk_hbox_new(FALSE,10);
   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),hbox);
   gtk_container_add (GTK_CONTAINER (hbox),gtk_label_new(""));
   gtk_container_add (GTK_CONTAINER (hbox),label);
   gtk_container_add (GTK_CONTAINER (hbox),gtk_label_new(""));
   gtk_window_set_modal(GTK_WINDOW(dialog),TRUE);
   gtk_signal_connect_object (GTK_OBJECT (dialog), "destroy",GTK_SIGNAL_FUNC (__dialog_release),GTK_OBJECT( dialog ));
   gtk_widget_show_all (dialog);

	while(dialog_not_clicked) gtk_main_iteration_do(FALSE);
	i = dialog_answer;
	i32 mask = UI_DisableAllMessages();

  UI_EnableMessages(mask);
  if (!saveCursorShowing) SDL_ShowCursor(SDL_DISABLE);
  if (i == 0 && is_ok == false) return MESSAGE_IDYES; // 0 == first button pressed
  if (i == 1 || i == -1)  return MESSAGE_IDNO; // 1 == second button pressed, (-1) == if MsgBox is 'destroyed'
  g_string_free(text,TRUE);
  return MESSAGE_IDOK;
}


i32 UI_CONSTAT(void)
{
  if (keyQueueStart != keyQueueEnd) return 1;
  return 0; // No console input available
}

i32 UI_DIRECT_CONIN(void)
{ //We should wait for a keystroke.  But we don't.  It is
  // up to you to be sure that input exists before
  // calling DIRECT_CONIN.
  ASSERT(keyQueueStart != keyQueueEnd);
  if (keyQueueStart == keyQueueEnd) return -1;
  i32 key = keyQueue[keyQueueStart];
  keyQueueStart++;
  if (keyQueueStart >= keyQueueLen) keyQueueStart=0;
  return key;
}

void UI_Die(void)
{
  throw 0xbad;
}

void UI_Sleep(i32 milliseconds)
{
  usleep(milliseconds*1000);
}

/* 
* The audio management
*/
//static CslDriver *driver = NULL;
//static CslPcmStream *AUDIO = NULL;
static const unsigned int AUDIOCOUNT = 16;
static unsigned int AUDIOPOS = 0;
static int AUDIO[AUDIOCOUNT];
/*
static SDL_AudioSpec spec;
static GSList * sound_queue = NULL;
static guint8 * current_audio_buffer = NULL;
static int audio_volume = SDL_MIX_MAXVOLUME;
static int audio_to_go = 0;
static bool audio_closed=true;
struct LinSound {
    ui8* data;
    ui32 size;
    int vol;
};
static void __sound_callback(void *userdata, Uint8 *stream, int length) {
    int written;
    Uint8 *buf = stream;
    int len = length;
    
    if(audio_to_go<=0 && NULL==sound_queue){
//	    SDL_PauseAudio(TRUE);
	printf("audio closed\n");
//	    audio_closed=true;
	    return;
	}
//    memset( stream, 0, length);


  //  SDL_PauseAudio(FALSE);
    
    do {
	if( audio_to_go > 0 ) {
	//	g_warning("Aaaaaudio!");
	} else {
	    GSList * node = sound_queue;
	    if(node) {
		sound_queue = node->next;
		LinSound *spec = (LinSound*)  node->data;
		g_slist_free_1( node );
		if( spec->data != (void*) __sound_callback ) {
			current_audio_buffer = spec->data;
			audio_to_go = spec->size;
			audio_volume = spec->vol;
		} else {
			gpointer kill_data = GINT_TO_POINTER(spec->size);
			audio_to_go = 0;
			UI_free(kill_data);
			written = 0x42; // Do I really need this?
			continue;
		}
		UI_free(spec);
	    } else {
		// No more to play.
		memset( buf, 0x00, len );
		SDL_PauseAudio(TRUE);
		return;
	    }
	}
	written = len > audio_to_go ? audio_to_go : len ;
	if(current_audio_buffer) {
		memcpy( buf, current_audio_buffer, written ); // The fast and orginal way
/_*		Uint8* p = current_audio_buffer;
		Uint8* b = buf;
		int i=written;
		for( ; i>0 ; i--, p++, b++ ) *p = (*p>>1) + (*b>>1); *_/
	}
	current_audio_buffer += written;
	audio_to_go -= written;
	buf += written;
	len -= written;
//	if(len<=0) { buf = stream; len = length; }
    } while(written);
    memset( buf, 0x80, len );
}*/
void UI_Initialize_sounds(void) {
    //CslOptions options;
    //CslErrorType error;
    int error=0;

    //memset( &options, 0, sizeof(options) );
 //   options.n_channels = 1;
  //  options.rate = 5120;//44100;
  //  options.pcm_format = CSL_PCM_FORMAT_U8; //CSL_PCM_FORMAT_S16_LE;
  //  error = csl_driver_init (NULL, &driver);
    //if(driver!=NULL){
//	error = csl_pcm_open_output (driver, "cslpcm1", options.rate, options.n_channels, options.pcm_format, &AUDIO);
    //}
    //if(error!=CSL_ENONE){
	//g_warning("UI_Initialize_sounds: %s\n",csl_strerror(error));
    //}
    error = esd_open_sound(NULL);
    esd_send_auth(error);
    while(AUDIOPOS < AUDIOCOUNT) {
	AUDIO[AUDIOPOS++] = esd_play_stream_fallback(ESD_BITS8|ESD_MONO|ESD_STREAM|ESD_PLAY,5120,NULL,"Chaio Says Back");
    }
    AUDIOPOS = 0;
    /*
    spec.freq=5120; //22050;
    spec.channels = 1;//mono
    spec.format=AUDIO_U8 ; //AUDIO_S16LSB;
    spec.samples=4096; //8192;
    spec.callback=__sound_callback;
    spec.userdata=&current_audio_buffer;
    if ( SDL_OpenAudio(&spec,NULL) < 0 ){  fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError());  exit(-1); }
    SDL_PauseAudio(FALSE);
    */
}
/*
* Put a request to destroy data on the stack.
* We cannot remove it before we have finished using it...
*  Yep.. Ugly. If sound data points to callback (nobody
*  outside will ever use that address) we have a killing frenzy.
*/
void LIN_KillSound(i8* audio ){
 //   csl_pcm_flush(AUDIO);
 //   csl_pcm_sync(AUDIO);
	UI_free(audio);
/*	LinSound *l = (LinSound*) UI_malloc(sizeof(LinSound));
	if(l) {
	    l->data = (void*) __sound_callback;
	    l->size = GPOINTER_TO_INT(audio);
	    l->vol = 0;
	    SDL_LockAudio();
	    sound_queue = g_slist_append(sound_queue, l);
	    SDL_UnlockAudio();
	    SDL_PauseAudio(FALSE);
	}*/
}
/*
* Play a sound. We do currently not bother about volume, it just looks nice...
*/
void LIN_PlaySound(i8* audio, ui32 size, int volume) {
	//if(AUDIO!=NULL && audio!=NULL)
	if(NULL == audio) return;
	unsigned int pjupp = AUDIOCOUNT;
	while(pjupp-->0 && NULL == AUDIO[AUDIOPOS=(AUDIOPOS+1)&(AUDIOCOUNT-1)]);
    if(AUDIO[AUDIOPOS]) {
//	csl_pcm_write(AUDIO, size, audio);
	write(AUDIO[AUDIOPOS],audio,size);
    }
//	bool play = (audio_to_go <= 0);csl_pcm_write
/*	if( g_slist_length(sound_queue) > 4) return;
	LinSound *l = (LinSound*) UI_malloc(sizeof(LinSound));
	if(l) {
	    l->data = audio;
	    l->size = size;
	    l->vol = volume;
	    SDL_LockAudio();
	    sound_queue = g_slist_append(sound_queue, l);
	    SDL_UnlockAudio();
	    SDL_PauseAudio(FALSE);
	}*/
//	if(play) SDL_PauseAudio(FALSE);
}
enum {
    		    enum_directory=42,
		    enum_ignore, // ignore = do not expect arguments
		    enum_height,
		    enum_quick,
		    enum_vblmultiplier,
		    enum_dungeon,
		    enum_width,
		    enum_x,
		    enum_y,
		    enum_module,
		    enum_extralarge,
		    enum_verylarge,
		    enum_large,
		    enum_small,
		    enum_play,
		    enum_timer,
		    enum_path,
    		    enum_gamsav,
	    };

bool UI_ProcessOption(char **argv, int &argc)
{
    int state=0;
    int c_index=0;
    int _argc = argc;
    while(_argc-->0)
    {
	char *key=argv[c_index++], *value;
	switch(state) {

		default:
		    if(!strcmp("--directory",key) ) {
			state=enum_directory;
		    }else if(!strcmp("--module",key) || !strcmp("--modules",key) ) {
			state=enum_module;
		    }else if(!strcmp("--gamsav",key) ) {
			state=enum_gamsav;
		    }else if(!strcmp("--root-path",key) ) {
			state=enum_path;
		    }else if(!strcmp("--repeat",key) ) {
			state=enum_ignore;
			RepeatGame = true;
		    }else if(!strcmp("--height",key) ) {
			state=enum_height;
		    }else if(!strcmp("--quick",key) ) {
			state=enum_quick;
		    }else if(!strcmp("--vblmultiplier",key) ) {
			state=enum_vblmultiplier;
		    }else if(!strcmp("--dungeon",key) ) {
			state=enum_dungeon;
		    }else if(!strcmp("--width",key) ) {
			state=enum_width;
/*		    }else if(!strcmp("--x",key) ) {
			state=enum_x;
		    }else if(!strcmp("--y",key) ) {
			state=enum_y;
*/		    }else if(!strcmp("--fullscreen",key) ) {
			    state=enum_ignore;
			    fullscreenRequested = true;
		    }else if(!strcmp("--extralarge",key) ) {
			state=enum_ignore; screenSize=4;
			WindowHeight=960;
			WindowWidth=1280;
		    }else if(!strcmp("--verylarge",key) ) {
			state=enum_ignore; screenSize=3;
			WindowHeight=720;
			WindowWidth=960;
		    }else if(!strcmp("--large",key) ) {
			state=enum_ignore; screenSize=2;
			WindowHeight=480;
			WindowWidth=640;
		    }else if(!strcmp("--small",key) ) {
			state=enum_ignore; screenSize=1;
			WindowHeight=240;
			WindowWidth=320;
		    }else if(!strcmp("--play",key) ) {
			state=enum_play;
		    }else if(!strcmp("--timer",key) ) {
			state=enum_timer;
		    }else if( !strcmp("--version",key) ){
			    exit(0);// CSB version is printed from main()
		    }else if( !strcmp("--norecord",key) ){
			    NoRecordCommandOption = true;
			    RecordCommandOption = false;
			    state=enum_ignore;
		    }else if(!strcmp("--help",key) || !strcmp("-help",key) || !strcmp("-h",key) || !strcmp("help",key) ) {
			printf("Help message:\n"
			"  Possible arguements are:\n"
			"  --gamsav\n"
				"\tUsage: --gamsav modules/chaos\\ strikes\\ back-atari/\n"
				"\tThe directory where any saved game files are\n"
				"\tThe game also tries to save in this directory\n"
				"\tIf not set, then default is to save in your current working directory\n"
			"  --directory\n"	
				"\tUsage: --directory /tmp/\n"
			    	"\tThe directory which holds any game file\n"
			"  --module\n"
				"\tUsage: --module /tmp/\n"
			    	"\tThe directory which holds any other game file\n"
			"  --root-path\n"	
				"\tUsage: --root-path /tmp/\n"
			   	"\tThe fall-back directory if the above pathways failed\n"
//			"  --repeat\n"
			"  --height\t in pixels\n"
			"  --width\t in pixels\n"
			"  --quick\n"
				"\tPlay movie faster than light\n"
//			"  --vblmultiplier\n"
			"  --dungeon\n"
				"\tUsage: --dungeon dungeon.dat\n"
			    	"\tPlay the game in another dungeon.\n"
//			"  --x\n"
//			"  --y\n"
			"  --fullscreen\n"
			"  --norecord\n"
			    	"\tPrevents a dungeon to autorecord a session, even if the dungeon\n"
				"\titself tries to force autorecord. It doesn't prevent you from\n"
				"\tmanually selecting record. Actually, there is no reason not to\n"
				"\tuse this switch.\n"
			"  --timer\n"
				"\tUsage: --timer 50\n"
			    	"\tSet internal callback-timer in ms.\n"
			"  --extralarge\n"
				"\tSet screensize to 1280x960 pixels\n"
			"  --verylarge\n"
				"\tSet screensize to 960x720 pixels\n"
			"  --large\n"
				"\tSet screensize to 640x480 pixels\n"
			"  --small\n"
				"\tSet screensize to 320x240 pixels\n"
			"  --play\n"
				"\tUsage: --play Playfile.log\n"
			    	"\tPlayes a recorded game. Might be reffered to as a \"movie\".\n"
			"  --version\n"
				"\tPrints the version of the program and exits.\n"
			" \n\n  KNOWN BUGS:"
				"\tGiven the evolution of this program, some bugs are more or less\n"
			    	"\tdifficult to treat. Thus it might be a good thing to list them here.\n\n"
//			    	"\t* A lot of enqueued sounds might momentarily freeze the game.\n\t  Especially the GTK interface.\n"
			    	"\t* Fullscreen is not working. \n"
			    	"\t* The GTK menu feels slow because it's only updated every --timer\n"
			    	"\t  settings. Set timer to 10 ms if you want the GTK interface to be\n"
			    	"\t  faster. \n"
//			    	"\t  Fullscreen is not working. \n"
			    	"\t \n"
			    	"\tIf you encounter a bug then catch it on record, send the Record000.txt\n"
				"\t(whatever) and the  saved  game  you used to Paul R. Stevens\n"
				"\t<prsteven@facstaff.wisc.edu>.\n"
			    	"\tIf the bug is not possible to catch on record, then send it to Erik\n\tSvanberg <svanberg@acc.umu.se>.\n"

			);// end of printf()
			exit(0);// Exit after the help message has been displayed
		    } else {
			state = 0;
		    }

		    if(state){
			c_index--;
			memmove(&argv[c_index],&argv[c_index+1],(argc-c_index-1)*sizeof(char *));
			argc--;
			if(state == enum_ignore) state=0;
		    }
		continue;

		case enum_directory:
//		    root = key;
		    folderParentName = key; // Nasty hack. :o)
		    break;
		
		case enum_module:
		    folderName = key;
		    break;

		case enum_gamsav:
		    folderSavedGame = key;
		    break;

		case enum_path:
		    root = key;
		    break;


		case enum_height:
		    sscanf(key,"%d", &WindowHeight);
		    break;
		
		case enum_timer:
		    sscanf(key,"%d", &TImER);
		    break;
		
		case enum_quick:
		    sscanf(key,"%d", &NoSpeedLimit);
		    break;
		
		case enum_vblmultiplier:
		    sscanf(key,"%d", &VBLMultiplier);
		    break;
		
		case enum_dungeon:
		    dungeonName = key;
//		    root = ""; // Nasty hack. :o)
				   // In CSB dungeonName is added to root... and dungeonName is already a working  path
		    break;
		
		case enum_width:
		    sscanf(key,"%d", &WindowWidth);
		    break;
/*	not used with SDL
		case enum_x:
		    sscanf(key,"%d", &WindowX);
		    break;
		    break;
		case enum_y:
		    sscanf(key,"%d", &WindowY);
		    break;
		    break;
*/		
		case enum_extralarge:
		    screenSize = 4;
		    break;
		case enum_verylarge:
		    screenSize = 3;
		    break;
		case enum_large:
		    screenSize = 2;
		    break;
		case enum_small:
		    screenSize = 1;
		    break;
		
		case enum_play:
		    PlayfileName=key;
//		g_warning("pag %s",PlayfileName);
		    extraTicks = false;
		    PlaybackCommandOption = true;
		    break;
	}
	state=0;
    } // end of while
    
    return true;
  }

void UI_BeginRecordOK(bool ok)
{
  BeginRecordOK = ok;
  if (ok)
  {
    if (RecordCommandOption || RecordMenuOption)
    {
      RecordfileOpen(true);
    }
    else if (!NoRecordMenuOption)
    {
      RecordfilePreOpen();
    };
    if (PlaybackCommandOption)
    {
      PlayfileOpen(true);
    };
  };
}

char *parentFolder(char *filename, char *endname)
{
  char *result=NULL;
  // filename points to first character; endname points to last+1;
   if (*(endname-1) == '/') endname--;
  while (endname > filename)
  {
    endname--;
    if (*endname == '/') break;
  };

  if (endname > filename)
  {
    endname++; //include the backslash at the end
    result = (char *)UI_malloc(endname-filename+1, MALLOC031);
    if (result != NULL)
    {
      memcpy(result,filename,endname-filename);
      result[endname-filename] = 0;
    };
  };
  return result;
}

i64 UI_GetSystemTime(void)
{
    struct timeval t;
    gettimeofday( &t, NULL );
    return ((guint32) t.tv_usec)/1000 + ((guint64) t.tv_sec)*1000;
}	


FILE *UI_fopen(char *name, char *flags)
{
  return fopen(name, flags);
}

void *UI_malloc(i32 size, ui32 id)
{
  void *result;
  result = malloc(size+8);
 /// if(NULL == result) printf("[Out of Memory]: We wish to hold the whole sky, but we never will.");
  *(int *)result = size;
  return (void *)((char *)result+8);
//OLDCODE:  return malloc(size);
}


void UI_ClearScreen(void)
{
  //nothing;
	UI_Invalidate();
}



void *UI_realloc(void *buf, i32 size)
{
  void *result;
  if (buf == NULL)
  {
    result = realloc(NULL, size+8);
  }
  else
  {
    result = realloc((char *)buf-8, size+8);
  };
  if (result == NULL)
  {
    UI_MessageBox("Cannot allocate memory","Fatal error",MESSAGE_OK);
    die(0xdab6);
  };
  *(i32 *)result = size;
  return (void *)((char *)result+8);
}

void UI_free(void *buf)
{
  free((char *)buf-8);
}

LISTING::LISTING(void)
{
  m_listing = (char *)malloc(1);
  *m_listing = 0;
}

LISTING::~LISTING(void)
{
  free(m_listing);
  m_listing = NULL;
}

void LISTING::AddLine(char *line)
{
  i32 len;
  len = strlen(m_listing);
  m_listing = (char *)realloc(m_listing, len + strlen(line) + 5);
  if (len != 0)
  {
    m_listing[len] = '\015';
    m_listing[len+1] = '\012';
    len +=2;
  };
  strcpy(m_listing+len, line);
}

void LISTING::DisplayList(char * title)
{
	printf("[%s] %s",title, m_listing);
}
#endif //_LINUX
