// 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"


namespace tools {
namespace sg {

class event {
public:
  static cid id_class() {return 0;}
  virtual void* cast(cid) const = 0;
  virtual event* copy() const = 0;
public:
  event(){
  }
  virtual ~event(){
  }
public:
  event(const event&){
  }
  event& operator=(const event&){return *this;}
};

class size_event : public event {
  typedef event parent;
public:
  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;
  }
  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 position_modifiers {
public:
  position_modifiers(int a_x,int a_y,bool a_shift_modifier,bool a_control_modifier)
  :m_x(a_x)
  ,m_y(a_y)
  ,m_shift_modifier(a_shift_modifier)
  ,m_control_modifier(a_control_modifier)
  {}
  virtual ~position_modifiers(){}
public:
  position_modifiers(const position_modifiers& a_from)
  :m_x(a_from.m_x)
  ,m_y(a_from.m_y)
  ,m_shift_modifier(a_from.m_shift_modifier)
  ,m_control_modifier(a_from.m_control_modifier)
  {}
  position_modifiers& operator=(const position_modifiers& a_from){
    m_x = a_from.m_x;
    m_y = a_from.m_y;
    m_shift_modifier = a_from.m_shift_modifier;
    m_control_modifier = a_from.m_control_modifier;
    return *this;
  }
public:
  int x() const {return m_x;}
  int y() const {return m_y;}
  bool shift_modifier() const {return m_shift_modifier;}
  bool control_modifier() const {return m_control_modifier;}
protected:
  int m_x;
  int m_y;
  bool m_shift_modifier;
  bool m_control_modifier;
};

class mouse_down_event : public event, public position_modifiers {
  typedef event parent;
  typedef position_modifiers parent_pos_mod;
public:
  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;
  }
  virtual event* copy() const {return new mouse_down_event(*this);}
public:
  mouse_down_event(int a_x,int a_y,bool a_shift_modifier,bool a_control_modifier)
  :parent_pos_mod(a_x,a_y,a_shift_modifier,a_control_modifier)
  {}
  virtual ~mouse_down_event(){}
public:
  mouse_down_event(const mouse_down_event& a_from)
  :parent(a_from)
  ,parent_pos_mod(a_from)
  {}
  mouse_down_event& operator=(const mouse_down_event& a_from){
    parent::operator=(a_from);
    parent_pos_mod::operator=(a_from);
    return *this;
  }
};

class mouse_up_event : public event, public position_modifiers {
  typedef event parent;
  typedef position_modifiers parent_pos_mod;
public:
  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;
  }
  virtual event* copy() const {return new mouse_up_event(*this);}
public:
  mouse_up_event(int a_x,int a_y,bool a_shift_modifier,bool a_control_modifier)
  :parent_pos_mod(a_x,a_y,a_shift_modifier,a_control_modifier)
  {}
  virtual ~mouse_up_event(){}
public:
  mouse_up_event(const mouse_up_event& a_from)
  :parent(a_from)
  ,parent_pos_mod(a_from)
  {}
  mouse_up_event& operator=(const mouse_up_event& a_from){
    parent::operator=(a_from);
    parent_pos_mod::operator=(a_from);
    return *this;
  }
};

class mouse_move_event : public event, public position_modifiers {
  typedef event parent;
  typedef position_modifiers parent_pos_mod;
public:
  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;
  }
  virtual event* copy() const {return new mouse_move_event(*this);}
public:
  mouse_move_event(int a_x,int a_y,bool a_shift_modifier,bool a_control_modifier,
                   int a_ox,int a_oy,
                   bool a_touch) //for sliders.
  :parent_pos_mod(a_x,a_y,a_shift_modifier,a_control_modifier)
  ,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)
  :parent(a_from)
  ,parent_pos_mod(a_from)
  ,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){
    parent::operator=(a_from);
    parent_pos_mod::operator=(a_from);

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

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

class anim_event : public event {
  typedef event parent;
public:
  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;
  }
  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:
  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:
  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;
  }
  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:
  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;
  }
  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, public position_modifiers {
  typedef event parent;
  typedef position_modifiers parent_pos_mod;
public:
  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;
  }
  virtual event* copy() const {return new wheel_rotate_event(*this);}
public:
  wheel_rotate_event(int a_angle,int a_x,int a_y,bool a_shift_modifier,bool a_control_modifier)
  :parent_pos_mod(a_x,a_y,a_shift_modifier,a_control_modifier)
  ,m_angle(a_angle)
  {}
  virtual ~wheel_rotate_event(){}
public:
  wheel_rotate_event(const wheel_rotate_event& a_from)
  :parent(a_from)
  ,parent_pos_mod(a_from)
  ,m_angle(a_from.m_angle)
  {}
  wheel_rotate_event& operator=(const wheel_rotate_event& a_from){
    parent::operator=(a_from);
    parent_pos_mod::operator=(a_from);
    m_angle = a_from.m_angle;
    return *this;
  }
public:
  int angle() const {return m_angle;}
protected:
  int m_angle;
};

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);}

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
