/*
  libuta - a C++ widget library based on SDL (Simple Direct Layer)
  Copyright (C) 1999-2002  Karsten Laux

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
  
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
  
  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  Boston, MA  02111-1307, SA.
*/


#ifndef _APP_H
#define _APP_H

#include <sigc++/signal_system.h>
#include <sigc++/marshal.h>

#include "rootwindow.h"
#include "event.h"
#include "mouse.h"
#include "mixer.h"
#include "soundmapper.h"
#include "timer.h"

///just a shortcut
#define uapp uta::Application::Instance


namespace uta {
///
class Application : public SigC::Object
{

 public:
  ///
  Application(int argc, char **argv);
  ///
  ~Application();
  
  ///
  void quit();
  ///
  virtual void infoMsg(const char*);

  ///50 ms timer tick
  SigC::Signal0<void> timer;
  ///100ms
  SigC::Signal0<void> timer100;
  /**key has been pressed signal.
     Emitted whenever a key is pressed. Slots connected to this signal may
     swallow the event by returning true. If a slot returns false,
     the rest of the application has a chance to "see" this keystroke as well.
  */
  static SigC::Signal1<bool, const KeyEvent*, SigC::FixedMarshal<bool, false> > keystroke;
  ///mouse has been moved
  static SigC::Signal1<bool, const MouseEvent*, SigC::FixedMarshal<bool, false> > mousemove;
  ///mousebutton has been pressed or released
  static SigC::Signal1<bool, const ButtonEvent*, SigC::FixedMarshal<bool, false> > mouseclick;
  ///
  static SigC::Signal0<bool,SigC::FixedMarshal<bool, false> > sigterm;
  ///
  static SigC::Signal0<bool,SigC::FixedMarshal<bool, false> > iconified;
  ///
  static SigC::Signal0<bool,SigC::FixedMarshal<bool, false> > restored;
  ///
  static SigC::Signal0<bool,SigC::FixedMarshal<bool, false> > lostfocus;
  ///
  static SigC::Signal0<bool,SigC::FixedMarshal<bool, false> > gotfocus;
  ///
  static SigC::Signal0<bool,SigC::FixedMarshal<bool, false> > exposed;
  ///
  static SigC::Signal2<bool,int,int,SigC::FixedMarshal<bool, false> > resized;
  
  ///
  void init(int resX, int resY, int bpp, 
	    bool fullscreen = false, bool resizeable = false,
	    const Surface* icon=0);
  /** Check if this video mode is possible.
      If SDL will emulate the requested pixeldepth, true_bpp (if != NULL)
      will contain the bitdepth of the acutally used video mode.
  */
  bool modeAvailable(int resX, int resY, int bpp, bool fullscreen, int* true_bpp = NULL);
  ///
  int exec();


  ///
  virtual int startupProc() { return 0;};
  ///
  virtual int shutdownProc() { return 0;};
  ///
  virtual int eventloopProc() {return 0;};
  ///
  virtual bool handleEvent(const Event* );

  ///
  static bool startingUp() { return uapp->startup_; };
  ///
  static bool shutingDown()  { return uapp->shutdown_; };
  ///
  static bool running() { return uapp->running_; };

  ///
  static RootWindow *rootWindow() { return uapp->rootWindow_; };
  ///
  static Mouse* mouse() { return uapp->mouse_; };
  ///
  static Mixer* mixer() { return uapp->mixer_; };
  ///
  static SoundMapper* soundMapper() { return uapp->soundMapper_; };
  ///
  static Application* Instance;

  ///
  static void useHardwareCursor(bool flag);
  ///
  static bool hardwareCursor() { return hardwareCursor_; };
  ///
  static unsigned long int ticks() {return uapp->ticks_;};
  ///
  static bool isIconified() { return uapp->iconified_; };
  ///
  static bool hasFocus() { return uapp->focus_; };
  
  ///
  static bool keepAlive();

  /** Sleep for at least n milliseconds.
      Application can only sleep in multiples of loop delay. (set via SetIdleTime)
      The actual time sleeped is returned. 
      When sleeping only basic event handling is active, 
      all keystroke- and mouseclick-events are discarded. (not scheduled !)
      Timer events still occur.
      The screen refresh is done as usual, sound playback is still active.
      The mouse still moves, but movement events are not passed to the application
      itself.
      --> all user input is ignored, while the application itself is still running.
  */
  static unsigned int sleep(unsigned int n);
  /** Set mainloop delay time.
      Set the maximum time to spend idle. The default is 25ms which results
      in a maximum screen refresh rate of 40 frames per second.
  */
  static void setIdleTime(unsigned int);

 protected:

  ///
  bool checkHotKey(const KeyEvent*);

  ///
  void updateScreen();
  ///
  void processKeys();
  ///
  void updateMouse();
  ///
  enum { 
    KEY_TABLE_SIZE = SDLK_LAST , 
    KEY_DELAY = 10, // rough 500ms
    KEY_REPEAT = -1 // 0 means 100ms, -1 means 50ms
  };
  ///
  int eventloop();
  ///
  RootWindow *rootWindow_;
  ///
  Mouse *mouse_;
  ///
  Mixer* mixer_;
  ///
  SoundMapper* soundMapper_;

  bool startup_;
  ///
  bool shutdown_;
  ///
  bool running_;

  ///
  int argc_;
  ///
  char **argv_;

  ///
  unsigned int ticks_;
 
 private:
  ///
  bool focus_;
  ///
  bool iconified_;
  ///
  Timer T50;
  ///
  Timer T100;
  ///
  bool screen_update;
  ///
  Uint32 lastticks;
  ///
  Uint32 tick;
  ///
  Uint32 delta_tick;
  ///
  int result;
  ///
  static bool hardwareCursor_;
  ///
  static bool sleeping_;
  ///
  static unsigned int idleTime_;

};

}
  
#endif // !_APP_H
  
