#ifndef _COPYEVENT_CPP_
#define _COPYEVENT_CPP_

#include <iostream.h>

#include "copyEvent.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;

CopyEvent::CopyEvent(Position p, Event * ev, Part * pt, int pi) : _event(0), _delete(0), _part(pt), _selection(0), _delete_sel(0) {
  _type = COPYEVENT;
  _description = "copy event";
  _to_be_undone = true;
  if (ev) {
    long _delta_pos = (p - pt->start()) - ev->internalStart().ticks();
    int _delta_pitch = 0;
    if (ev->isA()==NOTE) if (pi!=0) _delta_pitch = pi - ((Note*) ev)->pitch();

    //
    // the event has to be copied and added!
    //

    if (!selectioN->hasEntry(ev)) {
      //
      // single event:
      //
      _event = (Event*) ev->copy();
      _event->setInternalStart(ev->internalStart() + _delta_pos);
      //
      // apply pitch-shift, when note:
      //
      if (_event->isA()==NOTE) {
	Note * n = (Note*) _event;
	if (_delta_pitch != 0) n->setPitch(n->pitch() + _delta_pitch);
      }
      _part->add(_event);
    } else {
      //
      // selection:
      //
      _selection = new Table();
      _description = "copy events";
      for (Reference * r = (Reference*)selectioN->first(); r != 0; r = (Reference*) Element::next(r)) {
	Event * ev = (Event*) r->getValue()->copy();
	_selection->add(new Reference(ev));
	ev->setInternalStart(ev->internalStart() + _delta_pos);
	//
	// apply pitch-shift, when note:
	//
	if (ev->isA()==NOTE) {
	  Note * n = (Note*) ev;
	  if (_delta_pitch != 0) n->setPitch(n->pitch() + _delta_pitch);
	}
	_part->add(ev);
      }
    }

  }
}

CopyEvent::CopyEvent(const CopyEvent& el) : Operation(el) {
  _type = COPYEVENT;
  _event = el._event;
  _part = el._part;
  _selection = el._selection;
  _delete = el._delete;
  _delete_sel = el._delete_sel;
}

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

void CopyEvent::undo() {
  if (_selection==0) {
    //
    // single event:
    //
    if (_event) _part->remove(_event);
    _delete = _event;
  } else {
    //
    // selection:
    //
    for (Reference * r = (Reference*)_selection->first(); r != 0; r = (Reference*) Element::next(r)) {
      Event * ev = (Event*) r->getValue();
      _part->remove(ev);
    }
    _delete_sel = _selection;
  }
}

void CopyEvent::redo() {
  if (_selection==0) {
    //
    // single event:
    //
    if (_event) _part->add(_event);
    _delete = 0;
  } else {
    //
    // selection:
    //
    for (Reference * r = (Reference*)_selection->first(); r != 0; r = (Reference*) Element::next(r)) {
      Event * ev = (Event*) r->getValue();
      _part->add(ev);
    }
    _delete_sel = 0;
  }
}



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

ostream & CopyEvent::print(int dep, ostream & s) const {
  s << spc(dep) << "<COPYEVENT event=\"" << _event << "\" _part=\"" << _part << "\" />" << endl;
  return s;
}

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

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




#endif
