// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.

#ifndef toolx_Windows_sg_viewer
#define toolx_Windows_sg_viewer

#include "session"
#include "window"
#include "glarea"

#include <GL/gl.h>

#include "gl_functions"

#include "../sg/GL_action"
#include "../sg/GL_viewer"

namespace toolx {
namespace sg {
  using GL_action = GL_action_T<Windows::gl_functions>;
  using GL_manager = GL_manager_T<Windows::gl_functions>;
  using GL_viewer = GL_viewer_T<GL_manager,GL_action>;
}}

// disable the warning about the usage of "this" in the constructor.
#pragma warning(disable:4355)

namespace toolx {
namespace Windows {

class sg_viewer : public window, public sg::GL_viewer  {
  typedef window parent_window;
  typedef sg::GL_viewer parent_viewer;
public:
  sg_viewer(session& a_session,
            int a_x = 0,int a_y = 0,
            unsigned int a_width = 500,unsigned int a_height = 500,
            const std::string& a_title = "")
  :parent_window(a_title.c_str(),a_x,a_y,a_width,a_height)
  ,parent_viewer(a_session.out(),a_width,a_height)
  ,m_session(a_session)
  ,m_glarea(m_hwnd,*this)
  {
    parent_window::set_focus_hwnd(m_glarea.hwnd());
  }
  virtual ~sg_viewer() {}
protected:
  sg_viewer(const sg_viewer& a_from)
  :parent_window(a_from)
  ,parent_viewer(a_from)
  ,m_session(a_from.m_session)
  ,m_glarea(a_from.m_glarea)
  {}
  sg_viewer& operator=(const sg_viewer& a_from){
    parent_window::operator=(a_from);
    return *this;
  }
public:
  bool has_window() const {return m_hwnd?true:false;} //for SWIG

  HWND window() const {return m_hwnd;}

  bool show() {
    if(!m_hwnd) return false;
    m_session.show_window(m_hwnd);
    return true;
  }

  void win_render() {
    m_glarea.wm_paint();
    m_session.sync();
  }

  void emit_win_render() {m_glarea.post_WM_PAINT();}

  bool window_size(unsigned int& a_w,unsigned int& a_h) {
    if(!m_glarea.hwnd()) {a_w = 0;a_h = 0;return false;}
    RECT wrect;
    ::GetWindowRect(m_glarea.hwnd(),&wrect);
    a_w = wrect.right-wrect.left;
    a_h = wrect.bottom-wrect.top;
    return true;
  }
  void render_area_size(unsigned int& a_w,unsigned int& a_h) {
    a_w = parent_viewer::width();
    a_h = parent_viewer::height();
  }

public:
  void set_device_interactor(tools::sg::device_interactor* a_interactor) {  //we do not have ownership.
    m_glarea.set_device_interactor(a_interactor);
  }
protected:
  class _glarea : public glarea {
  public:
    virtual void paint(unsigned int a_w,unsigned int a_h) {
      m_viewer.set_size(a_w,a_h);
      m_viewer.render();
    }
  public:
    _glarea(HWND a_parent,parent_viewer& a_viewer)
    :glarea(a_parent)
    ,m_viewer(a_viewer)
    {}
  protected:
    parent_viewer& m_viewer;
  };

protected:
  session& m_session;
  _glarea m_glarea;
};

}}

#endif
