#ifndef _CHANGENOTE_CPP_
#define _CHANGENOTE_CPP_

#include <iostream.h>

#include "changeNote.h"
#include "element.h"
#include "compound.h"
#include "reference.h"

#include "event.h"
#include "part.h"
#include "track.h"
#include "song.h"
#include "note.h"

extern Song * sonG;
extern Table * selectioN;

ChangeNote::ChangeNote(Note * nt, Part * pt, int pitch, int len, int vel, int enh, int chan)
 : _note(nt), _part(pt), _delta_pitch(0), _delta_len(0), _delta_vel(0), _delta_enh(0), _delta_chan(0), _selection(0) {
  _type = CHANGENOTE;
  _description = "change note";
  _to_be_undone = true;
  if (_note) {
    if ( pitch > 0 ) _delta_pitch = pitch - _note->pitch();
    if ( len > 0 ) _delta_len = len - _note->duration();
    if ( vel > -1 ) _delta_vel = vel - _note->vel();
    if ( enh > -4 ) _delta_enh = enh - _note->enh();
    if ( chan > -2 ) _delta_chan = chan - _note->chan();

    if (!selectioN->hasEntry(_note)) {
      //
      // single event:
      //
      if (_delta_pitch != 0) _note->setPitch(_note->pitch() + _delta_pitch);
      if (_delta_len != 0) _note->setDuration(_note->duration() + _delta_len);
      if (_delta_vel != 0) _note->setVel(_note->vel() + _delta_vel);
      if (_delta_enh != 0) _note->setEnh(_note->enh() + _delta_enh);
      if (_delta_chan != 0) _note->setChan(_note->chan() + _delta_chan);
    } else {
      //
      // selection:
      //
      _selection = new Table();
      _description = "change notes";
      for (Reference * r = (Reference*)selectioN->first(); r != 0; r = (Reference*) Element::next(r)) {
	Event * ev = (Event*) r->getValue();
	if (ev->isA()==NOTE) {
	  Note * n = (Note*) ev;
	  _selection->add(new Reference(ev));
	  if (_delta_pitch != 0) n->setPitch(n->pitch() + _delta_pitch);
	  if (_delta_len != 0) n->setDuration(n->duration() + _delta_len);
	  if (_delta_vel != 0) n->setVel(n->vel() + _delta_vel);
	  if (_delta_enh != 0) n->setEnh(n->enh() + _delta_enh);
	  if (_delta_chan != 0) n->setChan(n->chan() + _delta_chan);
	}
      }
    }

  }
}

ChangeNote::ChangeNote(const ChangeNote& el) : Operation(el) {
  _type = CHANGENOTE;
  _note = el._note;
  _part = el._part;
  _delta_pitch = el._delta_pitch;
  _delta_len = el._delta_len;
  _delta_vel = el._delta_vel;
  _delta_enh = el._delta_enh;
  _delta_chan = el._delta_chan;
  _selection = el._selection;
}

ChangeNote::~ChangeNote() {
  if (_selection!=0) {
    ((Compound*)_selection)->scratch();
    delete _selection;
  }
}

void ChangeNote::undo() {
  if (_note) {
    if (_selection==0) { // single event:
      if (_delta_pitch != 0) _note->setPitch(_note->pitch() - _delta_pitch);
      if (_delta_len != 0) _note->setDuration(_note->duration() - _delta_len);
      if (_delta_vel != 0) _note->setVel(_note->vel() - _delta_vel);
      if (_delta_enh != 0) _note->setEnh(_note->enh() - _delta_enh);
      if (_delta_chan != 0) _note->setChan(_note->chan() - _delta_chan);
    } else {                            // selection:
      for (Reference * r = (Reference*)_selection->first(); r != 0; r = (Reference*) Element::next(r)) {
	Event * ev = (Event*) r->getValue();
	if (ev->isA()==NOTE) {
	  Note * n = (Note*) ev;
	  if (_delta_pitch != 0) n->setPitch(n->pitch() - _delta_pitch);
	  if (_delta_len != 0) n->setDuration(n->duration() - _delta_len);
	  if (_delta_vel != 0) n->setVel(n->vel() - _delta_vel);
	  if (_delta_enh != 0) n->setEnh(n->enh() - _delta_enh);
	  if (_delta_chan != 0) n->setChan(n->chan() - _delta_chan);
	}
      }
    }
  }
}

void ChangeNote::redo() {
  if (_note) {
    if (_selection==0) { // single event:
      if (_delta_pitch != 0) _note->setPitch(_note->pitch() + _delta_pitch);
      if (_delta_len != 0) _note->setDuration(_note->duration() + _delta_len);
      if (_delta_vel != 0) _note->setVel(_note->vel() + _delta_vel);
      if (_delta_enh != 0) _note->setEnh(_note->enh() + _delta_enh);
      if (_delta_chan != 0) _note->setChan(_note->chan() + _delta_chan);
    } else {                            // selection:
      for (Reference * r = (Reference*)_selection->first(); r != 0; r = (Reference*) Element::next(r)) {
	Event * ev = (Event*) r->getValue();
	if (ev->isA()==NOTE) {
	  Note * n = (Note*) ev;
	  if (_delta_pitch != 0) n->setPitch(n->pitch() + _delta_pitch);
	  if (_delta_len != 0) n->setDuration(n->duration() + _delta_len);
	  if (_delta_vel != 0) n->setVel(n->vel() + _delta_vel);
	  if (_delta_enh != 0) n->setEnh(n->enh() + _delta_enh);
	  if (_delta_chan != 0) n->setChan(n->chan() + _delta_chan);
	}
      }
    }
  }
}



// ---------------
// virtuals:
//

ostream & ChangeNote::print(int dep, ostream & s) const {
  s << spc(dep) << "<CHANGENOTE note=\"" << _note << "\" _part=\"" << _part << "\" />" << endl;
  return s;
}

void ChangeNote::flush(const char * c) const {
  cout << c << "CHANGENOTE" << endl;
}

Element * ChangeNote::copy() const {
  return new ChangeNote(*this);
}




#endif
