#ifndef _QUANTIZEALL_CPP_
#define _QUANTIZEALL_CPP_

#include <iostream.h>

#include <reference.h>
#include <table.h>
#include <event.h>
#include <part.h>
#include <track.h>
#include <song.h>
#include <str.h>
#include <prMainEditor.h>

#include "quantizeAll.h"

extern Table * selectioN;
extern Table * selectionMemory;
extern PrMainEditor * mainEditor;

#define QUANTIZEALL_CONTEXT Addon::TREAT_SELECTION + Addon::TREAT_TRACK + Addon::TREAT_PART + Addon::TREAT_SONG

extern "C" {
  Addon * quantizeAll(Element * target) { return new QuantizeAll(target); }
  const char  * quantizeAll_name() { return "quantize all"; }
  const char  * quantizeAll_category() { return "quantize"; }
  int     quantizeAll_context() { return QUANTIZEALL_CONTEXT; }
}


QuantizeAll::QuantizeAll(Element * target) : Addon("quantize", target, TO_BE_UNDONE, QUANTIZEALL_CONTEXT), context(0), count(0) { run(); }

QuantizeAll::~QuantizeAll() {
  delete[] pos;
  delete[] len;
}

void setLength(Event * ev, int grid) {
  long foo = ev->duration();
  foo += int(0.5*grid);
  foo -= foo%grid;
  if (foo==0) foo = grid;
  ev->setDuration(foo);
}

void QuantizeAll::selection(Table * selection) {
  context = Addon::TREAT_SELECTION;
  int grid = mainEditor->grid();
  int sz = selection->size();
  pos = new long[sz];
  len = new long[sz];
  for (Reference * r = (Reference*)selection->first(); r != 0; r = (Reference*) Element::next(r)) {
    Event * ev = (Event*) r->getValue();
    pos[count]   = ev->internalStart().ticks();
    len[count++] = ev->duration();
    ev->snapStart(grid);
    setLength(ev,grid);
  }
}

void QuantizeAll::part(Part * part) {
  context = Addon::TREAT_PART;
  int grid = mainEditor->grid();
  int sz = part->size();
  pos = new long[sz];
  len = new long[sz];
  for (Event * ev = (Event*)part->first(); ev != 0; ev = (Event*) Element::next(ev)) {
    pos[count]   = ev->internalStart().ticks();
    len[count++] = ev->duration();
    ev->snapStart(grid);
    setLength(ev,grid);
  }
}

void QuantizeAll::track(Track * track) {
  context = Addon::TREAT_TRACK;
  int grid = mainEditor->grid();
  int sz = track->size();
  int totalsz = 0;
  for (int i=0; i<sz; i++) {
    Part * pt = (Part*) track->get(i);
    totalsz += pt->size();
  }
  pos = new long[totalsz];
  len = new long[totalsz];
  for (int i=0; i<sz; i++) {
    Part * pt = (Part*) track->get(i);
    for (Event * ev = (Event*) pt->first(); ev != 0; ev = (Event*) Element::next(ev)) {
      pos[count]   = ev->internalStart().ticks();
      len[count++] = ev->duration();
      ev->snapStart(grid);
      setLength(ev,grid);
    }
  }
}

void QuantizeAll::song(Song * song) {
  context = Addon::TREAT_SONG;
  int grid = mainEditor->grid();
  int totalsz = 0;
  int szs = song->size();
  for (int i=0; i<szs; i++) {
    Track * track = (Track*) song->get(i);
    int sz = track->size();
    for (int i=0; i<sz; i++) {
      Part * pt = (Part*) track->get(i);
      totalsz += pt->size();
    }
  }
  pos = new long[totalsz];
  len = new long[totalsz];
  for (int i=0; i<szs; i++) {
    Track * track = (Track*) song->get(i);
    int sz = track->size();
    for (int i=0; i<sz; i++) {
      Part * pt = (Part*) track->get(i);
      for (Event * ev = (Event*) pt->first(); ev != 0; ev = (Event*) Element::next(ev)) {
	pos[count]   = ev->internalStart().ticks();
	len[count++] = ev->duration();
	ev->snapStart(grid);
	setLength(ev,grid);
      }
    }
  }
}

void QuantizeAll::undo() {
  long foo1 = 0;
  long foo2 = 0;
  int mem = 0;
  if (context == Addon::TREAT_SELECTION) {
    Table * selection = (Table*) _target;
    int sz = selection->size();
    for (Reference * r = (Reference*)selection->first(); r != 0; r = (Reference*) Element::next(r)) {
      Event * ev = (Event*) r->getValue();
      foo1 = ev->internalStart().ticks();
      foo2 = ev->duration();
      ev->setInternalStart(pos[mem]);
      ev->setDuration(len[mem]);
      pos[mem]   = foo1;
      len[mem++] = foo2;
    }
  } else if (context == Addon::TREAT_PART) {
    Part * part = (Part*) _target;
    int sz = part->size();
    for (Event * ev = (Event*)part->first(); ev != 0; ev = (Event*) Element::next(ev)) {
      foo1 = ev->internalStart().ticks();
      foo2 = ev->duration();
      ev->setInternalStart(pos[mem]);
      ev->setDuration(len[mem]);
      pos[mem]   = foo1;
      len[mem++] = foo2;
    }
  } else if (context == Addon::TREAT_TRACK) {
    cout << "TODO: undo quantize track" << endl;
  } else if (context == Addon::TREAT_SONG) {
    cout << "TODO: undo quantize song" << endl;
  }
}

void QuantizeAll::redo() {
  long foo1 = 0;
  long foo2 = 0;
  int mem = 0;
  if (context == Addon::TREAT_SELECTION) {
    Table * selection = (Table*) _target;
    int sz = selection->size();
    for (Reference * r = (Reference*)selection->first(); r != 0; r = (Reference*) Element::next(r)) {
      Event * ev = (Event*) r->getValue();
      foo1 = ev->internalStart().ticks();
      foo2 = ev->duration();
      ev->setInternalStart(pos[mem]);
      ev->setDuration(len[mem]);
      pos[mem]   = foo1;
      len[mem++] = foo2;
    }
  } else if (context == Addon::TREAT_PART) {
    Part * part = (Part*) _target;
    int sz = part->size();
    for (Event * ev = (Event*)part->first(); ev != 0; ev = (Event*) Element::next(ev)) {
      foo1 = ev->internalStart().ticks();
      foo2 = ev->duration();
      ev->setInternalStart(pos[mem]);
      ev->setDuration(len[mem]);
      pos[mem]   = foo1;
      len[mem++] = foo2;
    }
  } else if (context == Addon::TREAT_TRACK) {
    cout << "TODO: redo quantize track" << endl;
  } else if (context == Addon::TREAT_SONG) {
    cout << "TODO: redo quantize song" << endl;
  }
}






#endif
