#ifndef GRAPHOUTPUT_H
#define GRAPHOUTPUT_H

#include <list>
#include <iostream>
#include "output.h"
#include "../micro.h"
#include "../microadam.h"
#include "../microeva.h"
extern"C"
{
  #include <opencv/highgui.h>
//  #include <stdlib.h>
}

using namespace std;

namespace seemicro
{

extern int DEBUGLEVEL;

/**
  * Zeichnet verschiedene Graphen
  * TODO/möglich: CorrelationStrength einzeichnen
  */
struct GraphOutput : public OutputModule
{
  static const int BREITE = 300;
  static const int HOEHE = 300;
  int lastIndex;
  Micro& micro;

  /**
    * ob wir MicroAdams oder MicroEvas plotten
    */
  bool haveAdam, haveEva;

  IplImage *img;

  /**
    * Legen fest, ob die jeweiligen Graphen eingezeichnet
    * werden sollen
    */
  int enableX, enableY, enableRadius, enableAlpha, enableBeta;

  /**
    * Ringbuffer
    */
  Micro *microHistory[BREITE];

  GraphOutput(Micro& Am) : micro(Am)
  {
    enableX = 0;
    enableY = 0;
    enableRadius = 1;
    enableAlpha = 1;
    haveAdam = dynamic_cast<MicroAdam*>(&micro);
    haveEva = dynamic_cast<MicroEva*>(&micro);
    cvNamedWindow("Graph", 1);
    img = cvCreateImage(cvSize(BREITE, HOEHE), IPL_DEPTH_8U, 3);
    cvCreateTrackbar("mitte.x an?", "Graph", &enableX, 1, NULL);
    cvCreateTrackbar("mitte.y an?", "Graph", &enableY, 1, NULL);
    cvCreateTrackbar("radius an?", "Graph", &enableRadius, 1, NULL);
    cvCreateTrackbar("alpha an?", "Graph", &enableAlpha, 1, NULL);
    if(haveAdam || haveEva)
    {
      enableBeta = true;
      cvCreateTrackbar("beta(s) an?", "Graph", &enableBeta, 1, NULL);
    }
    else enableBeta = false;
    lastIndex = 0;
    for(int i=0; i<BREITE; i++) microHistory[i] = NULL;
  }

  ~GraphOutput()
  {
    for(int i=0; i<BREITE; i++) if(microHistory[i]) delete microHistory[i];
    cvReleaseImage(&img);
    cvDestroyWindow("Graph");
  }

  virtual void output(bool keyframe)
  {
#ifdef DEBUG
    if(DEBUGLEVEL>=3) cerr << "->GraphOutput::output()\n";
#endif

    // aktuelles micro-Objekt in Array kopieren
    if(microHistory[lastIndex]) delete microHistory[lastIndex];

    microHistory[lastIndex] = micro.clone();
    lastIndex++;
    if(lastIndex>=BREITE) lastIndex = 0;

    if(!keyframe) return;

    // Graph neu zeichnen
    //cvZero(img);// schwarzer Hintergrund
    cvSet(img, cvScalar(255,255,255));
    mypoint lastX, X(0, 0),
            lastY, Y(0, 0),
	    lastRadius, Radius(0, 0),
	    lastAlpha, Alpha(0, 0),
	    lastBeta[5], Beta[5];
    for(int i=0; i<5; i++) Beta[i] = mypoint(0, 0);
    for(int x=0; x<BREITE; x++)
    {
      lastX = X;
      lastY = Y;
      lastRadius = Radius;
      lastAlpha = Alpha;
      for(int i=0; i<5; i++) lastBeta[i] = Beta[i];

      if(!microHistory[x]) continue;

      if(enableX)
      {
	X = mypoint(x, microHistory[x]->mitte.p.x);
	double c = microHistory[x]->mitteValid ? CV_RGB(0, 255, 0) : CV_RGB(255, 0, 0);
	putPixel8u_3(img, X.p.x, X.p.y, int(c));
	//cvLine(img, lastX, X, c);
      }
      if(enableY)
      {
	Y = mypoint(x, microHistory[x]->mitte.p.y);
	double c = microHistory[x]->mitteValid ? CV_RGB(0, 155, 0) : CV_RGB(155, 0, 0);
	putPixel8u_3(img, Y.p.x, Y.p.y, int(c));
	//cvLine(img, lastY, Y, c);
      }
      if(enableRadius)
      {
	Radius = mypoint(x, int(microHistory[x]->radius * HOEHE / 100));
	double c = microHistory[x]->radiusValid ? CV_RGB(0, 155, 222) : CV_RGB(155, 0, 222);
	putPixel8u_3(img, Radius.p.x, Radius.p.y, int(c));
	//cvLine(img, lastRadius, Radius, c);
      }
      if(enableAlpha)
      {
	Alpha = mypoint(x, int(microHistory[x]->alpha * HOEHE / 2 / M_PI));
	double c = microHistory[x]->alphaValid ? CV_RGB(255, 0, 0) : CV_RGB(155, 0, 222);
	if(fabs(float(lastAlpha.p.y-Alpha.p.y))>50)
	  putPixel8u_3(img, Alpha.p.x, Alpha.p.y, int(c));
	else cvLineAA(img, lastAlpha, Alpha, c);
	//cerr << "Alpha: " << Alpha.p.y << " " << microHistory[x]->alpha << endl;
      }
      if(enableBeta)
      {
	if(haveAdam)
	{
	  MicroAdam *adam = dynamic_cast<MicroAdam*>(microHistory[x]);
	  assert(adam);
	  Beta[0] = mypoint(x, int( (adam->beta/M_PI*2+0.5) * HOEHE));
	  double c = adam->alphaValid ? CV_RGB(222, 155, 0) : CV_RGB(155, 222, 0);
	  //putPixel8u_3(img, Beta[0].p.x, Beta[0].p.y, int(c));
	  cvLineAA(img, lastBeta[0], Beta[0], c);
	  //cerr << "y:" << Beta[0].p.y << " beta: " << adam->beta << " ";
	}
	else if(haveEva)
	{
	  MicroEva *eva = dynamic_cast<MicroEva*>(microHistory[x]);
	  assert(eva);
	  // fünf Graphen untereinander für die 5 Betas
	  for(int i=0; i<5; i++)
	  {
	    Beta[i] = mypoint(x, int(eva->beta[i] * HOEHE/6) + i*HOEHE/5);
	    double c = eva->alphaValid ? CV_RGB(222, 222, 100) : CV_RGB(155, 222, 0);
	    //putPixel8u_3(img, Beta[i].p.x, Beta[i].p.y, int(c));
	    cvLineAA(img, lastBeta[i], Beta[i], c, 0);
	  }
	}
	else cerr << "enableBeta=true, but we have neither adam nor eva?\n";
      }
    } // for()
    cvLine(img, cvPoint(lastIndex,0), cvPoint(lastIndex,HOEHE-1), CV_RGB(55, 55, 255));
    cvShowImage("Graph", img);
    cvResizeWindow("Graph", BREITE+5, HOEHE+280);
  } // output()

}; // GraphOutput

} // seemicro

#endif

