#ifndef n_glWindow_H
#define n_glWindow_H

/*
 *
 * nucleo/gl/window/glWindow.H --
 *
 * Copyright (C) Nicolas Roussel
 *
 * See the file LICENSE for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 */

#include <nucleo/core/ReactiveObject.H>
#include <nucleo/gl/window/keysym.H>

#ifdef __APPLE__
#include <OpenGL/gl.h>
#else
#include <GL/gl.h>
#endif

#include <string>
#include <iostream>

namespace nucleo {

  // ------------------------------------------------------------------

  class glWindow : public ReactiveObject {

  private:

  protected:

  public:

    bool debugEvents ;

    // -------------------------------------------------
    // Options that can be used for GL setup

    enum glOptions {
	 NONE = 0,
	 DOUBLE_BUFFER = 1,
	 STENCIL = 2,
	 DEPTH = 4,
	 ALPHA = 8
    } ;

    // -------------------------------------------------
    // Screen-related utilities

    virtual unsigned int getScreenWidth(void) = 0 ;
    virtual unsigned int getScreenHeight(void) = 0 ;

    // -------------------------------------------------
    // Window-related utilities

    virtual void map(void) = 0 ;
    virtual void unmap(void) = 0 ;

    virtual void setTitle(const char *title) = 0 ;

    virtual void getGeometry(unsigned int *width, unsigned int *height,
					    int *x, int *y) = 0 ;
    // x and y can be negative (relative to parent's width and height)
    virtual void setGeometry(unsigned int width, unsigned int height,
					    int x, int y) = 0 ;

    virtual void fullScreenMode(bool activate) = 0 ;

    virtual void setGeometry(char *geometry) ;
    virtual void resize(unsigned int newwidth, unsigned int newheight) ;
    virtual void move(int newx, int newy) ;
    virtual void moveRel(int dx, int dy) ;

    // -------------------------------------------------
    // GL context manipulation

    virtual void makeCurrent(void) = 0 ;
    virtual void swapBuffers(void) = 0 ;

    // -------------------------------------------------
    // Bonus

    virtual void showCursor(bool activate) {
      std::cerr << "glWindow::showCursor is not implemented on this platform..." << std::endl ;
    }
    virtual void warpCursor(int x, int y) {
	 // x and y are in window coordinates
      std::cerr << "glWindow::warpCursor is not implemented on this platform..." << std::endl ;
    }
    virtual void keyboardAutoRepeat(bool activate) {
      std::cerr << "glWindow::keyboardAutoRepeat is not implemented on this platform..." << std::endl ;
    }
    virtual void syncToVbl(int nb_vbls=1) {
      std::cerr << "glWindow::syncToVbl is not implemented on this platform..." << std::endl ;
    }
    virtual void setAspectRatio(int width, int height) {
      std::cerr << "glWindow::setAspectRatio is not implemented on this platform..." << std::endl ;
    }
    virtual void setMinMaxSize(int minwidth, int minheight, int maxwidth, int maxheight) {
      std::cerr << "glWindow::setMinMaxSize is not implemented on this platform..." << std::endl ;
    }
    virtual void raise(void) {
      std::cerr << "glWindow::raise is not implemented on this platform..." << std::endl ;
    }
    virtual void lower(void) {
      std::cerr << "glWindow::lower is not implemented on this platform..." << std::endl ;
    }

    // -------------------------------------------------
    // Event handling

    struct event {
	 static const char * const strings[] ;

	 enum {
#define EVENTDEF(eventname,eventnum) eventname = eventnum,
#include <nucleo/gl/window/_events.H>
#undef EVENTDEF
	 } type ;

	 // If you add more parameters here, change the copy constructor
	 // implementation accordingly...

	 int width, height ;

	 int x, y ;
	 int button ;
	 int axis, delta ;
	 int time;
   
	 unsigned long keysym ;
	 std::string keystr ;

	 event(void) ;
	 event& operator = (event& src) ;
	 void debug(std::ostream& out) const ;
	 ~event() ;
    } ;

    virtual bool getNextEvent(event *e) = 0 ;

    static glWindow *create(long options, long eventmask) ;

  } ;

  // ------------------------------------------------------------------

}

#endif
