//=========================================================
//  MusE
//  Linux Music Editor
//  $Id: event.h,v 1.1.1.1 2003/10/29 10:05:07 wschweer Exp $
//
//  (C) Copyright 1999/2000 Werner Schweer (ws@seh.de)
//=========================================================

#ifndef __EVENT_H__
#define __EVENT_H__

#include "qpoint.h"
#include "qstring.h"
#include "pos.h"

#include <list>
#include <map>

class MidiTrack;
class MidiPlayEvent;
class Clip;
class Xml;

//---------------------------------------------------------
//   Attribute
//    Event Attributes:  0 - Lyrics
//---------------------------------------------------------

class Attribute {
      int _type;
      QPoint _pos;
      QString s;

   public:
      Attribute(int t) {
            _type = t;
            }
      Attribute(int t, int x, int y) {
            _type = t;
            _pos.setX(x);
            _pos.setY(y);
            }
      Attribute(int t, const QPoint& p) : _pos(p) {
            _type = t;
            }
      Attribute(int t, int x, int y, const QString& txt) : s(txt) {
            _type = t;
            _pos.setX(x);
            _pos.setY(y);
            }
      Attribute(int t, const QString& txt) : s(txt) {
            _type = t;
            }
      int type() const                    { return _type; }
      QString text() const                { return s; }
      void setText(const QString& string) { s = string; }
      QPoint pos() const                  { return _pos; }
      void setPos(const QPoint& p)        { _pos = p; }
      };

//---------------------------------------------------------
//   AttributeList
//---------------------------------------------------------

class AttributeList:public std::list<Attribute> {
   public:
      void add(int type) { push_back(Attribute(type)); }
      Attribute* add(Attribute a) {
            push_back(a);
            return &back();
            }
      void addLyrics(const QString& s);
      AttributeList() {}
      };

typedef AttributeList::iterator iAttribute;
typedef AttributeList::const_iterator ciAttribute;

//---------------------------------------------------------
//   Event
//---------------------------------------------------------

class Event : public PosLen {

   protected:
      int refs;
      bool _selected;

   public:
      Event();
      Event(int t, int l);
      Event(const Event& ev);

      virtual ~Event() {}

      int incRefs(int val)      { refs += val; return refs; }

      bool selected() const      { return _selected; }
      void setSelected(bool val) { _selected = val; }

      void move(int offset);

      virtual void read(Xml&) = 0;
      virtual void write(int, Xml&, int offset) const = 0;
      virtual void dump() const;
      virtual Event* clone() = 0;
      virtual Event* mid(int, int) = 0;
      };

//---------------------------------------------------------
//   EvData
//    variable len event data (sysex, meta)
//---------------------------------------------------------

struct EvData {
      unsigned char* data;
      int dataLen;
      int refCount;

      EvData()  { data = 0; dataLen = 0; refCount = 0; }

      ~EvData() {
            if (data)
                  delete[] data;
            }
      EvData(const unsigned char* p, int l) {
            setData(p, l);
            }
      void setData(const unsigned char* p, int l) {
            data = new unsigned char[l];
            memcpy(data, p, l);
            dataLen = l;
            }
      };

//---------------------------------------------------------
//   MidiEvent
//    Ctrl14    a - CtrlNo, b, value
//    NRPN      a - CtrlNo, b, value
//    RPN       a - CtrlNo, b, value
//---------------------------------------------------------

class MidiEvent : public Event {
   public:
      enum EventType {
            NoEvent, Note, NoteOff, Program, Ctrl7,
               Sysex, PAfter, CAfter, Pitch, Meta, NRPN, RPN,
               Symbol, Quantize, Clock, Ctrl14
            };
   private:
      EventType _type;
      int a, b, c;                  // pitch, velo-on, velo-off
      char _enh;                    // enharmonische Verwechslung 0 - 4
      char _voice;                  // 0 - automatic
                                    // 1 - upper system
                                    // 2 - lower system
      char _stem;                   // 0 - automatic
                                    // 1 - up
                                    // 2 - down
      EvData* edata;
      AttributeList attributes;
      MidiTrack* _trk;              //  only unsed inside
                                    //  sequencer

   public:
      MidiEvent();
      MidiEvent(const MidiEvent&);
      MidiEvent(const MidiPlayEvent*);
      virtual ~MidiEvent();
      MidiEvent& operator=(const MidiEvent&);

      MidiEvent(int tick, EventType type, int a, int b, int c, int len);
      MidiEvent(int tick, EventType type, int len, const unsigned char* data);

      bool isNote() const                   { return _type == Note; }
      bool isNoteOff() const {
            return (_type == NoteOff) || ((_type == Note) && (b == 0));
            }
      bool isNoteOff(MidiEvent*);

      int pitch() const                      { return a;      }
      int program() const                    { return a;      }
      int cntrl() const                      { return a;      }
      int dataA() const                      { return a;      }
      void setA(int val)                     { a = val;       }
      void setPitch(int v)                   { a = v;         }

      int cntrlVal() const                   { return b;      }
      int dataB() const                      { return b;      }
      int velo() const                       { return b;      }
      void setB(int val)                     { b = val;       }
      void setVelo(int v)                    { b = v;         }

      int veloOff() const                    { return c;      }
      int dataC() const                      { return c;      }
      void setC(int val)                     { c = val;       }
      void setVeloOff(int v)                 { c = v;         }

      const unsigned char* data() const      { return edata->data;  }
      int dataLen() const                    { return edata->dataLen; }
      EvData* eventData() const              { return edata; }
      void setEvData(EvData* ed)             { edata = ed; }

      EventType type() const                 { return _type;  }
      void setType(EventType t)              { _type = t;     }
      void setEnh(int enh)                   { _enh = enh;    }
      int enh() const                        { return _enh;   }
      int voice() const                      { return _voice; }
      void setVoice(int v)                   { _voice = v;    }
      int stem() const                       { return _stem;  }
      void setStem(int v)                    { _stem = v;     }
      virtual void dump() const;
      virtual void read(Xml&);
      virtual void write(int, Xml&, int offset=0) const;
      void readAttr(Xml& xml);
      iAttribute beginAttr()                 { return attributes.begin(); }
      iAttribute endAttr()                   { return attributes.end(); }
      Attribute* addAttr(const Attribute& a) { return attributes.add(a); }
      void addLyrics(const QString& s)       { attributes.addLyrics(s); }
      void eraseAttr(iAttribute i)           { attributes.erase(i); }
      virtual Event* clone()                 { return new MidiEvent(*this); }
      virtual Event* mid(int, int);

      MidiTrack* trk() const                 { return _trk; }
      void setTrk(MidiTrack*t)               { _trk = t; }
      };

//---------------------------------------------------------
//   WaveEvent
//---------------------------------------------------------

class WaveEvent : public Event {
      Clip* _clip;

   public:
      WaveEvent();
      WaveEvent(int, Clip*);
      virtual ~WaveEvent() {}

      Clip* clip() const    { return _clip; }
      void setClip(Clip* c) { _clip = c; }

      virtual void read(Xml&);
      virtual void write(int, Xml&, int offset=0) const;
      virtual Event* clone();
      virtual Event* mid(int, int);
      virtual void dump() const;
      };

typedef std::multimap<int, Event*, std::less<int> >::iterator iEvent;
typedef std::multimap<int, Event*, std::less<int> >::reverse_iterator riEvent;
typedef std::multimap<int, Event*, std::less<int> >::const_iterator ciEvent;
typedef std::pair <iEvent, iEvent> EventRange;

//---------------------------------------------------------
//   EventList
//    tick sorted list of events
//---------------------------------------------------------

class EventList : std::multimap<int, Event*, std::less<int> > {
      int ref;          // number of references to this EventList
      int aref;         // number of active references (exclude undo list)
      void deselect();

   public:
      EventList()       { ref = 0; aref = 0;  }
      ~EventList();

      void incRef(int n)    { ref += n;    }
      int refCount() const  { return ref;  }
      void incARef(int n)   { aref += n;   }
      int arefCount() const { return aref; }

      iEvent find(Event*);
      void erase(iEvent);
      void erase(iEvent istart, iEvent iend);
      void insert(iEvent istart, iEvent iend);
      void clear();
      iEvent add(Event* event)   { return add(event, event->posTick()); }
      iEvent add(Event* event, int tick);
      void move(Event* event, int tick);
      void dump() const;
      iEvent begin()  { return std::multimap<int, Event*, std::less<int> >::begin(); }
      iEvent end()    { return std::multimap<int, Event*, std::less<int> >::end(); }
      ciEvent begin() const { return std::multimap<int, Event*, std::less<int> >::begin(); }
      ciEvent end() const  { return std::multimap<int, Event*, std::less<int> >::end(); }
      bool empty() const { return std::multimap<int, Event*, std::less<int> >::empty(); }
      int size() const { return std::multimap<int, Event*, std::less<int> >::size(); }
      iEvent lower_bound(int i)   {
            return std::multimap<int, Event*, std::less<int> >::lower_bound(i);
            }
      iEvent upper_bound(int i)   {
            return std::multimap<int, Event*, std::less<int> >::upper_bound(i);
            }
      EventRange equal_range(int i)   {
            return std::multimap<int, Event*, std::less<int> >::equal_range(i);
            }
      void read(Xml& xml, const char* name);
      };

#endif

