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

#ifndef tools_sg_event
#define tools_sg_event

#include "../scast"
#include "../S_STRING"
#include "../typedefs"

#ifdef TOOLS_MEM
#include "../mem"
#endif

#define TOOLS_SG_EVENT_ID_CAST

namespace tools {
namespace sg {

class event {
public:
#ifdef TOOLS_SG_EVENT_ID_CAST
  static cid id_class() {return 0;}
  virtual void* cast(cid) const = 0;
#else
  virtual void* cast(const std::string&) const = 0;
#endif
  virtual event* copy() const = 0;
public:
#ifdef TOOLS_MEM
  TOOLS_SCLASS(tools::sg::event)
#endif
public:
  event(){
#ifdef TOOLS_MEM
    mem::increment(s_class().c_str());
#endif
  }
  virtual ~event(){
#ifdef TOOLS_MEM
    mem::decrement(s_class().c_str());
#endif
  }
public:
  event(const event&){
#ifdef TOOLS_MEM
    mem::increment(s_class().c_str());
#endif
  }
  event& operator=(const event&){return *this;}
};

class size_event : public event {
  typedef event parent;
public:
#ifdef TOOLS_SG_EVENT_ID_CAST
  static cid id_class() {return parent::id_class()+1;}
  virtual void* cast(cid a_class) const {
    if(void* p = cmp_cast<size_event>(this,a_class)) return p;
    return 0;
  }
#else
  TOOLS_SCLASS(tools::sg::size_event)
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<size_event>(this,a_class)) {return p;}
    return 0;
  }
#endif
  virtual event* copy() const {return new size_event(*this);}
public:
  size_event(unsigned int a_ow,unsigned int a_oh,
             unsigned int a_w,unsigned int a_h)
  :m_ow(a_ow)
  ,m_oh(a_oh)
  ,m_w(a_w)
  ,m_h(a_h)
  {}
  virtual ~size_event(){}
public:
  size_event(const size_event& a_from)
  :event(a_from)
  ,m_ow(a_from.m_ow)
  ,m_oh(a_from.m_oh)
  ,m_w(a_from.m_w)
  ,m_h(a_from.m_h)
  {}
  size_event& operator=(const size_event& a_from){
    event::operator=(a_from);
    m_ow = a_from.m_ow;
    m_oh = a_from.m_oh;
    m_w = a_from.m_w;
    m_h = a_from.m_h;
    return *this;
  }
public:
  unsigned int old_width() const {return m_ow;}
  unsigned int old_height() const {return m_oh;}
  unsigned int width() const {return m_w;}
  unsigned int height() const {return m_h;}
protected:
  unsigned int m_ow;
  unsigned int m_oh;
  unsigned int m_w;
  unsigned int m_h;
};

class mouse_down_event : public event {
  typedef event parent;
public:
#ifdef TOOLS_SG_EVENT_ID_CAST
  static cid id_class() {return parent::id_class()+2;}
  virtual void* cast(cid a_class) const {
    if(void* p = cmp_cast<mouse_down_event>(this,a_class)) return p;
    return 0;
  }
#else
  TOOLS_SCLASS(tools::sg::mouse_down_event)
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<mouse_down_event>(this,a_class)) {return p;}
    return 0;
  }
#endif
  virtual event* copy() const {return new mouse_down_event(*this);}
public:
  mouse_down_event(int a_x,int a_y) //signed because of wall.
  :m_x(a_x)
  ,m_y(a_y)
  {}
  virtual ~mouse_down_event(){}
public:
  mouse_down_event(const mouse_down_event& a_from)
  :event(a_from)
  ,m_x(a_from.m_x)
  ,m_y(a_from.m_y)
  {}
  mouse_down_event& operator=(const mouse_down_event& a_from){
    event::operator=(a_from);
    m_x = a_from.m_x;
    m_y = a_from.m_y;
    return *this;
  }
public:
  int x() const {return m_x;}
  int y() const {return m_y;}
protected:
  int m_x;
  int m_y;
};

class mouse_up_event : public event {
  typedef event parent;
public:
#ifdef TOOLS_SG_EVENT_ID_CAST
  static cid id_class() {return parent::id_class()+3;}
  virtual void* cast(cid a_class) const {
    if(void* p = cmp_cast<mouse_up_event>(this,a_class)) return p;
    return 0;
  }
#else
  TOOLS_SCLASS(tools::sg::mouse_up_event)
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<mouse_up_event>(this,a_class)) {return p;}
    return 0;
  }
#endif
  virtual event* copy() const {return new mouse_up_event(*this);}
public:
  mouse_up_event(int a_x,int a_y) //signed because of wall.
  :m_x(a_x)
  ,m_y(a_y)
  {}
  virtual ~mouse_up_event(){}
public:
  mouse_up_event(const mouse_up_event& a_from)
  :event(a_from)
  ,m_x(a_from.m_x)
  ,m_y(a_from.m_y)
  {}
  mouse_up_event& operator=(const mouse_up_event& a_from){
    event::operator=(a_from);
    m_x = a_from.m_x;
    m_y = a_from.m_y;
    return *this;
  }
public:
  int x() const {return m_x;}
  int y() const {return m_y;}
protected:
  int m_x;
  int m_y;
};

class mouse_move_event : public event {
  typedef event parent;
public:
#ifdef TOOLS_SG_EVENT_ID_CAST
  static cid id_class() {return parent::id_class()+4;}
  virtual void* cast(cid a_class) const {
    if(void* p = cmp_cast<mouse_move_event>(this,a_class)) return p;
    return 0;
  }
#else
  TOOLS_SCLASS(tools::sg::mouse_move_event)
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<mouse_move_event>(this,a_class)) {return p;}
    return 0;
  }
#endif
  virtual event* copy() const {return new mouse_move_event(*this);}
public:
  mouse_move_event(int a_x,int a_y, //signed because of wall.
                   int a_ox,int a_oy,
                   bool a_touch) //for sliders.
  :m_x(a_x)
  ,m_y(a_y)
  ,m_ox(a_ox)
  ,m_oy(a_oy)
  ,m_touch(a_touch)
  {}
  virtual ~mouse_move_event(){}
public:
  mouse_move_event(const mouse_move_event& a_from)
  :event(a_from)
  ,m_x(a_from.m_x)
  ,m_y(a_from.m_y)
  ,m_ox(a_from.m_ox)
  ,m_oy(a_from.m_oy)
  ,m_touch(a_from.m_touch)
  {}
  mouse_move_event& operator=(const mouse_move_event& a_from){
    event::operator=(a_from);
    m_x = a_from.m_x;
    m_y = a_from.m_y;

    m_ox = a_from.m_ox;
    m_oy = a_from.m_oy;

    m_touch = a_from.m_touch;
    return *this;
  }
public:
  int x() const {return m_x;}
  int y() const {return m_y;}
  int ox() const {return m_ox;}
  int oy() const {return m_oy;}
  bool is_touch() const {return m_touch;}
protected:
  int m_x;
  int m_y;
  int m_ox;
  int m_oy;  //+ = up.
  // etc :
  bool m_touch;
};

class anim_event : public event {
  typedef event parent;
public:
#ifdef TOOLS_SG_EVENT_ID_CAST
  static cid id_class() {return parent::id_class()+5;}
  virtual void* cast(cid a_class) const {
    if(void* p = cmp_cast<anim_event>(this,a_class)) return p;
    return 0;
  }
#else
  TOOLS_SCLASS(tools::sg::anim_event)
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<anim_event>(this,a_class)) {return p;}
    return 0;
  }
#endif
  virtual event* copy() const {return new anim_event(*this);}
public:
  typedef uint64 num_t;
  anim_event(num_t a_secs,num_t a_micro_secs)
  :m_secs(a_secs),m_micro_secs(a_micro_secs)
  ,m_some_found(false)
  {}
  virtual ~anim_event(){}
public:
  anim_event(const anim_event& a_from)
  :event(a_from)
  ,m_secs(a_from.m_secs)
  ,m_micro_secs(a_from.m_micro_secs)
  ,m_some_found(a_from.m_some_found)
  {}
  anim_event& operator=(const anim_event& a_from){
    event::operator=(a_from);
    m_secs = a_from.m_secs;
    m_micro_secs = a_from.m_micro_secs;
    m_some_found = a_from.m_some_found;
    return *this;
  }
public:
/*
  void set_time(num_t a_secs,num_t a_micro_secs) {
    m_secs = a_secs;
    m_micro_secs = a_micro_secs;
  }
*/
  num_t seconds() const {return m_secs;}
  num_t micro_seconds() const {return m_micro_secs;}

  void set_some_found(bool a_v) {m_some_found = a_v;}
  bool some_found() const {return m_some_found;}
protected:
  num_t m_secs;
  num_t m_micro_secs;
  bool m_some_found;
};

class key_down_event : public event {
  typedef event parent;
public:
#ifdef TOOLS_SG_EVENT_ID_CAST
  static cid id_class() {return parent::id_class()+6;}
  virtual void* cast(cid a_class) const {
    if(void* p = cmp_cast<key_down_event>(this,a_class)) return p;
    return 0;
  }
#else
  TOOLS_SCLASS(tools::sg::key_down_event)
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<key_down_event>(this,a_class)) {return p;}
    return 0;
  }
#endif
  virtual event* copy() const {return new key_down_event(*this);}
public:
  key_down_event(key_code a_key)
  :m_key(a_key)
  {}
  virtual ~key_down_event(){}
public:
  key_down_event(const key_down_event& a_from)
  :event(a_from)
  ,m_key(a_from.m_key)
  {}
  key_down_event& operator=(const key_down_event& a_from){
    event::operator=(a_from);
    m_key = a_from.m_key;
    return *this;
  }
public:
  key_code key() const {return m_key;}
protected:
  key_code m_key;
};

class key_up_event : public event {
  typedef event parent;
public:
#ifdef TOOLS_SG_EVENT_ID_CAST
  static cid id_class() {return parent::id_class()+7;}
  virtual void* cast(cid a_class) const {
    if(void* p = cmp_cast<key_up_event>(this,a_class)) return p;
    return 0;
  }
#else
  TOOLS_SCLASS(tools::sg::key_up_event)
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<key_up_event>(this,a_class)) {return p;}
    return 0;
  }
#endif
  virtual event* copy() const {return new key_up_event(*this);}
public:
  key_up_event(key_code a_key)
  :m_key(a_key)
  {}
  virtual ~key_up_event(){}
public:
  key_up_event(const key_up_event& a_from)
  :event(a_from)
  ,m_key(a_from.m_key)
  {}
  key_up_event& operator=(const key_up_event& a_from){
    event::operator=(a_from);
    m_key = a_from.m_key;
    return *this;
  }
public:
  key_code key() const {return m_key;}
protected:
  key_code m_key;
};

class wheel_rotate_event : public event {
  typedef event parent;
public:
#ifdef TOOLS_SG_EVENT_ID_CAST
  static cid id_class() {return parent::id_class()+8;}
  virtual void* cast(cid a_class) const {
    if(void* p = cmp_cast<wheel_rotate_event>(this,a_class)) return p;
    return 0;
  }
#else
  TOOLS_SCLASS(tools::sg::wheel_rotate_event)
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<wheel_rotate_event>(this,a_class)) {return p;}
    return 0;
  }
#endif
  virtual event* copy() const {return new wheel_rotate_event(*this);}
public:
  wheel_rotate_event(int a_angle)
  :m_angle(a_angle)
  {}
  virtual ~wheel_rotate_event(){}
public:
  wheel_rotate_event(const wheel_rotate_event& a_from)
  :event(a_from)
  ,m_angle(a_from.m_angle)
  {}
  wheel_rotate_event& operator=(const wheel_rotate_event& a_from){
    event::operator=(a_from);
    m_angle = a_from.m_angle;
    return *this;
  }
public:
  int angle() const {return m_angle;}
protected:
  int m_angle;
};

#ifdef TOOLS_SG_EVENT_ID_CAST
template <class FROM,class TO> inline TO* event_cast(FROM& a_o) {return id_cast<FROM,TO>(a_o);}
template <class FROM,class TO> inline const TO* event_cast(const FROM& a_o) {return id_cast<FROM,TO>(a_o);}
#else
template <class FROM,class TO> inline TO* event_cast(FROM& a_o) {return safe_cast<FROM,TO>(a_o);}
template <class FROM,class TO> inline const TO* event_cast(const FROM& a_o) {return safe_cast<FROM,TO>(a_o);}
#endif

inline bool get_event_xy(const sg::event& a_event,int& a_x,int& a_y) {
  typedef sg::event evt_t;
  typedef sg::mouse_up_event up_evt_t;
  typedef sg::mouse_down_event dn_evt_t;
  if(const dn_evt_t* devt = event_cast<evt_t,dn_evt_t>(a_event)) {
    a_x = devt->x();
    a_y = devt->y();
    return true;

  } else if(const up_evt_t* uevt = event_cast<evt_t,up_evt_t>(a_event)) {
    a_x = uevt->x();
    a_y = uevt->y();
    return true;

  }
  a_x = 0;
  a_y = 0;
  return false;
}

}}

#endif
