#ifndef _RIEMANN_CPP_
#define _RIEMANN_CPP_

#include <iostream.h>
#include <stdio.h>
#include <string.h>

#include <reference.h>
#include <table.h>
#include <event.h>
#include <part.h>
#include <track.h>
#include <scoreTrack.h>
#include <position.h>
#include <song.h>
#include <note.h>
#include <addElement.h>
#include <riemannFunction.h>
#include <midiEvent.h>
#include <stdlib.h>
#include <songIterator.h>

#include "riemann.h"
#include "riemannEvent.h"
#include "harmonyTrack.h"
#include "globals.h"


extern Song * sonG;
extern const char * cType[];
extern "C" { Track * riemann_track(); }

#define RIEMANN_CONTEXT Addon::TREAT_SONG

extern "C" {
  Addon * riemann(Element * target) { return new Riemann(target); }
  const char  * riemann_name() { return "riemann"; }
  const char  * riemann_category() { return "harmony"; }
  int     riemann_context() { return RIEMANN_CONTEXT; }
}


Riemann::Riemann(Element * target) : Addon("determine riemann functions", target, !TO_BE_UNDONE, RIEMANN_CONTEXT) { run(); }

Riemann::~Riemann() {
}



int sgn(int i) {
  if (i==0) return 0;
  else if (i>0) return 1;
  else return -1;
}

void Riemann::sortPitches(int * pi, int * en, int & dim, int * mul, bool remove_doubles) {
  int sort_pi[dim];
  int sort_en[dim];
  int indx[dim];
  for (int i=0; i<dim; i++) mul[i] = 1;
  int x = 0;
  for (int p=0;p<128;p++)
    for (int i=0; i<dim; i++)
      if (pi[i]==p) indx[x++]=i;
  for (int i=0; i<dim; i++) {
    sort_pi[i] = pi[indx[i]];
    sort_en[i] = en[indx[i]];
  }
  int max = dim;
  int i2 = 0;
  if (!remove_doubles) {
    for (int i=0; i<max; i++) {
      pi[i] = sort_pi[i];
      en[i] = sort_en[i];
    }
  } else {
    for (int i=0; i<max; i++)
      if (i==0 || sort_pi[i]!=pi[i2-1]) {
	pi[i2] = sort_pi[i];
	en[i2] = sort_en[i];
	i2++;
      } else {
	mul[i2-1]++;
	dim--;
      }
  }
}


void Riemann::song(Song * _song) {
  int ntracks = 0;
  ntracks = _song->size();

  ScoreTrack * st = (ScoreTrack*) sonG->getTrack(cType[SCORETRACK]);
  // cout << "scoretrack: " << st << endl; if (st!=0) cout << *st << endl;
  if (st==0) return;
  
  Part * scorepart = (Part*) st->first();
  if (scorepart==0) return;

  //
  // get (or create) HarmonyTrack
  //
  HarmonyTrack * ht = (HarmonyTrack*) sonG->getTrack(riemann_name());
  // cout << "harmony track: " << ht << endl;
  if (ht==0) sonG->doo(new AddElement(riemann_track(), sonG));
  ht = (HarmonyTrack*) sonG->getTrack(riemann_name());
  // cout << "harmony track: " << ht << endl;

  //
  // get (or create) Part
  //
  Part * harmonypart = (Part*) ht->first();
  if (harmonypart==0) {
    harmonypart = new Part(ht);
    sonG->doo(new AddElement(harmonypart, ht));
  }

  int key = scorepart->key();
  harmonypart->setKey(key);
  ht->suggestKey((Key)(key+9));
  ht->suggestGenus(MAJOR);

  long pp = 0;
  Position ppos = Position(0);

  int maxvoices = ntracks*10;
  int tendency[maxvoices]; // in here we put the tangent slope prev -> note
  int count = 0;
  int base = 0;
  int gen = 0;
  help = new char[20];

  SongIterator * si = new SongIterator(_song, _song->left(), _song->right());

  Event * event = 0;
  Note * note   = 0;
  Track * tr    = 0;
  Part * pt = 0;
  int temp = 0;
  Note * prevnote = 0;
  int pitchDiff = 0;
  int parallel = 0;
  key = 0;
  RiemannEvent * riemann = 0;
  Chord chord;

  tr = si->track(0);
  pt = (Part*) tr->first();
  key = pt->key();

  current;
  recent;  // Harmony

  while ( !si->done() ) {
    count = 0;
    for (int t=0; t<ntracks; t++) {
      tr = si->track(t);
      while (si->startsAt(t,pp)) {
	if (!si->mute(t)) {
	  event = (Event*) (*si)[t];
	  if (event->isA()==NOTE) {
	    note = (Note*) event;
	    // rf = note->function();
	    // if (rf == 0) { rf = new RiemannFunction(); note->add(rf); }
	    if (count<maxvoices) {
	      prevnote = (Note*) tr->prev(note);
	      if (prevnote!=0) tendency[count] = note->pitch() - prevnote->pitch(); else tendency[count] = 0;
	      _enh[count]   = note->enh();
	      _pit[count++] = note->pitch();
	    } else {
	      cout << "ERROR: too many voices!" << endl;
	    }
	  }
	}
	si->increment(t);
      }
    }
    if (count>0 && Position(pp).tick()==0) {
      sortPitches(_pit, _enh, count, _mul, false);
      // cout << "pos " << pp << ": " << endl;

      event = harmonypart->grabEvent(Position(pp));

      if (event==0) {
	//
	// do not overwrite events, only new events are filled in!
	//

	for (int i=0;i<count;i++)
	  _stf[i] = _pit[i]%12;

	// cout << "_pit: "; for (int i=0; i<count; i++) cout << _pit[i] << " "; cout << " - " << endl;
	
	int stfcount = count;
	sortPitches(_stf, _enh, stfcount, _mul, true);
	
	// cout << "Halbton(Multiplizität): "; for (int i=0; i<stfcount; i++) cout << _stf[i] << " (" << _mul[i] << ") "; cout << endl << endl;
	
	chord = Chord(pp, _stf, _enh, _mul, stfcount);
	
	recent = current;
	current = Harmony(recent, chord, _pit[0]%12);

	riemann = new RiemannEvent(pp, &current);
	harmonypart->add(riemann);

      } else {
	cout << "already there: " << *event << endl;
      }

    }
    pp++;
  }
  delete help;

}

void Riemann::undo() {
}

void Riemann::redo() {
}






#endif
