#ifndef CWINDOW_H
#define CWINDOW_H


class CWindow;

// Type definition
typedef void (CWindow::*DisplayType)(void);
typedef void (CWindow::*ReshapeType)(int, int);
typedef void (CWindow::*KeyboardType)(unsigned char, int, int);
typedef void (CWindow::*MouseType)(int, int, int, int);
typedef void (CWindow::*MotionType)(int, int);
typedef void (CWindow::*PassiveMotionType)(int, int);
typedef void (CWindow::*EntryType)(int);
typedef void (CWindow::*VisibilityType)(int);
typedef void (CWindow::*IdleType)(void);
typedef void (CWindow::*MenuStateType)(int);
#if (GLUT_API_VERSION >= 2)
typedef void (CWindow::*SpecialType)(int, int, int);
typedef void (CWindow::*SpaceballMotionType)(int, int, int);
typedef void (CWindow::*SpaceballRotateType)(int, int, int);
typedef void (CWindow::*SpaceballButtonType)(int, int);
typedef void (CWindow::*ButtonBoxType)(int, int);
typedef void (CWindow::*DialsType)(int, int);
typedef void (CWindow::*TabletMotionType)(int, int);
typedef void (CWindow::*TabletButtonType)(int, int, int, int);
#if (GLUT_API_VERSION >= 3)
typedef void (CWindow::*MenuStatusType)(int, int, int);
typedef void (CWindow::*OverlayDisplayType)(void);
#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9)
typedef void (CWindow::*WindowStatusType)(int);
#endif
#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13)
typedef void (CWindow::*KeyboardUpType)(unsigned char, int, int);
typedef void (CWindow::*SpecialUpType)(int, int, int);
#endif
#endif
#endif
// End of type definition





// Constants definition
#define MYGLUT_Display           0x00000001
#define MYGLUT_Reshape           0x00000002
#define MYGLUT_Keyboard          0x00000004
#define MYGLUT_Mouse             0x00000008
#define MYGLUT_Motion            0x00000010
#define MYGLUT_PassiveMotion     0x00000020
#define MYGLUT_Entry             0x00000040
#define MYGLUT_Visibility        0x00000080
#define MYGLUT_Idle              0x00000100
#if (GLUT_API_VERSION >= 2)
#define MYGLUT_MenuState         0x00000200
#define MYGLUT_Special           0x00000400
#define MYGLUT_SpaceballMotion   0x00000800
#define MYGLUT_SpaceballRotate   0x00001000
#define MYGLUT_SpaceballButton   0x00002000
#define MYGLUT_ButtonBox         0x00004000
#define MYGLUT_Dials             0x00008000
#define MYGLUT_TabletMotion      0x00010000
#define MYGLUT_TabletButton      0x00020000
#if (GLUT_API_VERSION >= 3)
#define MYGLUT_MenuStatus        0x00040000
#define MYGLUT_OverlayDisplay    0x00080000
#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9)
#define MYGLUT_WindowStatus      0x00100000
#endif
#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13)
#define MYGLUT_KeyboardUp        0x00200000
#define MYGLUT_SpecialUp         0x00400000
#endif
#endif
#endif
// End of constants definition





//////////////////////////////
//////////////////////////////
////                      ////
////                      ////
////    A window class    ////
////                      ////
////                      ////
//////////////////////////////
//////////////////////////////

class CWindow
{
 protected:
  int Width, Height;
  std::string Caption;
  unsigned int ToActivate;

  ///////////////////////////////////
  //                               //
  //  Data manipulation functions  //
  //                               //
  ///////////////////////////////////
 public:
  int GetWidth() const { return Width; }
  void SetWidth(int width) { Width = width; }
  int GetHeight() const { return Height; }
  void SetHeight(int height) { Height = height; }	
  std::string GetCaption() const { return Caption; }
  void SetCaption(const std::string& caption) { Caption = caption; }
  unsigned int GetToActivate()const { return ToActivate; }




  ///////////////////////////////////////////////////////////
  //                                                       //
  //  Declaration of a pointer for each callback function  //
  //  and the Set and Get functions for each of them.      //
  //                                                       //
  ///////////////////////////////////////////////////////////
#define CALLBACKDECLARATION(x)        \
 protected:                           \
  x##Type x##Func;                    \
 public:                              \
  void Set##x##Func(##x##Type func)   \
  {                                   \
    x##Func = func;                   \
    ToActivate |= MYGLUT_##x##;       \
  }                                   \
  x##Type Get##x##Func() const        \
  {                                   \
    return (##x##Func);               \
  }

  CALLBACKDECLARATION(Display);
  CALLBACKDECLARATION(Reshape);
  CALLBACKDECLARATION(Keyboard);
  CALLBACKDECLARATION(Mouse);
  CALLBACKDECLARATION(Motion);
  CALLBACKDECLARATION(PassiveMotion);
  CALLBACKDECLARATION(Entry);
  CALLBACKDECLARATION(Visibility);
  CALLBACKDECLARATION(Idle);
#if (GLUT_API_VERSION >= 2)
  CALLBACKDECLARATION(MenuState);
  CALLBACKDECLARATION(Special);
  CALLBACKDECLARATION(SpaceballMotion);
  CALLBACKDECLARATION(SpaceballRotate);
  CALLBACKDECLARATION(SpaceballButton);
  CALLBACKDECLARATION(ButtonBox);
  CALLBACKDECLARATION(Dials);
  CALLBACKDECLARATION(TabletMotion);
  CALLBACKDECLARATION(TabletButton);
#if (GLUT_API_VERSION >= 3)
  CALLBACKDECLARATION(MenuStatus);
  CALLBACKDECLARATION(OverlayDisplay);
#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9)
  CALLBACKDECLARATION(WindowStatus);
#endif
#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13)
  CALLBACKDECLARATION(KeyboardUp);
  CALLBACKDECLARATION(SpecialUp);
#endif
#endif
#endif
  ///////////
  //       //
  //  END  //
  //       //
  ///////////





  //////////////////////////////////
  //                              //
  //  Default callback functions  //
  //                              //
  //////////////////////////////////
 private:
  virtual void DEFAULT_Display(void) { glutDisplayFunc(0); }
  virtual void DEFAULT_Reshape(int width, int height) { glutReshapeFunc(0); }
  virtual void DEFAULT_Keyboard(unsigned char key, int x, int y) { glutKeyboardFunc(0); }
  virtual void DEFAULT_Mouse(int button, int state, int x, int y) { glutMouseFunc(0); }
  virtual void DEFAULT_Motion(int x, int y) { glutMotionFunc(0); }
  virtual void DEFAULT_PassiveMotion(int x, int y) { glutPassiveMotionFunc(0); }
  virtual void DEFAULT_Entry(int state) { glutEntryFunc(0); }
  virtual void DEFAULT_Visibility(int state) { glutVisibilityFunc(0); }
  virtual void DEFAULT_Idle(void) { glutIdleFunc(0); }
  virtual void DEFAULT_MenuState(int state) { glutMenuStateFunc(0); }
#if (GLUT_API_VERSION >= 2)
  virtual void DEFAULT_Special(int key, int x, int y) { glutSpecialFunc(0); }
  virtual void DEFAULT_SpaceballMotion(int x, int y, int z) { glutSpaceballMotionFunc(0); }
  virtual void DEFAULT_SpaceballRotate(int x, int y, int z) { glutSpaceballRotateFunc(0); }
  virtual void DEFAULT_SpaceballButton(int button, int state) { glutSpaceballButtonFunc(0); }
  virtual void DEFAULT_ButtonBox(int button, int state) { glutButtonBoxFunc(0); }
  virtual void DEFAULT_Dials(int dial, int value) { glutDialsFunc(0); }
  virtual void DEFAULT_TabletMotion(int x, int y) { glutTabletMotionFunc(0); }
  virtual void DEFAULT_TabletButton(int button, int state, int x, int y) { glutTabletButtonFunc(0); }
#if (GLUT_API_VERSION >= 3)
  virtual void DEFAULT_MenuStatus(int status, int x, int y) { glutMenuStatusFunc(0); }
  virtual void DEFAULT_OverlayDisplay(void) { glutOverlayDisplayFunc(0); }
#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9)
  virtual void DEFAULT_WindowStatus(int state) { glutWindowStatusFunc(0); }
#endif
#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13)
  virtual void DEFAULT_KeyboardUp(unsigned char key, int x, int y) { glutKeyboardUpFunc(0); }
  virtual void DEFAULT_SpecialUp(int key, int x, int y) { glutSpecialUpFunc(0); }
#endif
#endif
#endif
  /////////////////////////////////////////
  //                                     //
  //  End of default callback functions  //
  //                                     //
  /////////////////////////////////////////





  ///////////////////
  //               //
  //  Constructor  //
  //               //
  ///////////////////
 public:
#define CONSTRUCTORASSIGNMENT(x) x##Func = &CWindow::DEFAULT_##x##;

  CWindow(int w = -1, int h = -1,
          const std::string& caption = std::string(""))
    : Caption(caption)
    {
      Width = w; Height = h; ToActivate = 0;

      CONSTRUCTORASSIGNMENT(Display);
      CONSTRUCTORASSIGNMENT(Reshape);
      CONSTRUCTORASSIGNMENT(Keyboard);
      CONSTRUCTORASSIGNMENT(Mouse);
      CONSTRUCTORASSIGNMENT(Motion);
      CONSTRUCTORASSIGNMENT(PassiveMotion);
      CONSTRUCTORASSIGNMENT(Entry);
      CONSTRUCTORASSIGNMENT(Visibility);
      CONSTRUCTORASSIGNMENT(Idle);
#if (GLUT_API_VERSION >= 2)
      CONSTRUCTORASSIGNMENT(MenuState);
      CONSTRUCTORASSIGNMENT(Special);
      CONSTRUCTORASSIGNMENT(SpaceballMotion);
      CONSTRUCTORASSIGNMENT(SpaceballRotate);
      CONSTRUCTORASSIGNMENT(SpaceballButton);
      CONSTRUCTORASSIGNMENT(ButtonBox);
      CONSTRUCTORASSIGNMENT(Dials);
      CONSTRUCTORASSIGNMENT(TabletMotion);
      CONSTRUCTORASSIGNMENT(TabletButton);
#if (GLUT_API_VERSION >= 3)
      CONSTRUCTORASSIGNMENT(MenuStatus);
      CONSTRUCTORASSIGNMENT(OverlayDisplay);
#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9)
      CONSTRUCTORASSIGNMENT(WindowStatus);
	#endif
#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13)
      CONSTRUCTORASSIGNMENT(KeyboardUp);
      CONSTRUCTORASSIGNMENT(SpecialUp);
#endif
#endif
#endif
    }

  //////////////////////////
  //                      //
  //  Virtual destructor  //
  //                      //
  //////////////////////////
public:
  virtual ~CWindow() {};

  virtual void init(void) = 0;
};

#endif
