#include <QtGui>
#include <iostream>
#include "bsstructureview.h"
#include "math.h"

using namespace std;


BSStructureView::BSStructureView (QImage *im, BSDetector *sd)
{
  graylevelImage = im;
  currentImage = im;
  det = sd;
  int w = im->width ();
  int h = im->height ();
  imageInBack = true;
  gradImage = NULL;
  gradInBack = false;
  setBackgroundBrush (QBrush (*currentImage));
  setScene (new QGraphicsScene (0, 0, w, h));
  grid = new BSStructureItem (w, h, im, sd);
  scene()->addItem (grid);
  setWindowTitle (grid->itemTitle ());
}


BSStructureView::~BSStructureView ()
{
  scene()->removeItem (grid);
  delete grid;
  delete gradImage;
}


void BSStructureView::setGradientImage (VMap *gMap)
{
  if (gradImage != NULL) delete gradImage;
  int w = gMap->getWidth ();
  int h = gMap->getHeight ();
  double gn[w * h];
  for (int j = 0; j < h; j++)
    for (int i = 0; i < w; i++)
      gn[j * w + i] = gMap->cmpNorm (i, j);
      // gn[j * w + i] = sqrt (gMap->sqNorm (i, j));
  double max = 0;
  for (int i = 0; i < w * h; i++) if (max < gn[i]) max = gn[i];
  gradImage = new QImage (w, h, QImage::Format_RGB32);
  for (int j = 0; j < h; j++)
    for (int i = 0; i < w; i++)
    {
      uint val = (uint) (gn[(h - 1 - j) * w + i] * 255 / max);
      gradImage->setPixel (i, j, val + val * 256 + val * 256 * 256);
    }
  // gradImage->save ("gradient.png");
}


void BSStructureView::updateBackground (bool zoomChanged)
{
  if (imageInBack)
  {
    int w = currentImage->width ();
    int h = currentImage->height ();
    int zf = grid->zoomFactor ();
    if (zoomChanged) image = currentImage->scaled (w * zf, h * zf);
    QBrush qb (image);
    qb.setTransform (QTransform::fromTranslate (
          w / 2 - zf * (w / 2 + grid->focusX ()),
          h / 2 - zf * (h / 2 + grid->focusY ())));
    setBackgroundBrush (qb);
  }
}


void BSStructureView::toggleBackground ()
{
  imageInBack = ! imageInBack;
  if (imageInBack) setBackgroundBrush (QBrush (image));
  else setBackgroundBrush (QBrush (Qt::white));
}


void BSStructureView::toggleGradient ()
{
  if (currentImage == gradImage) currentImage = graylevelImage;
  else if (gradImage != NULL) currentImage = gradImage;
}


void BSStructureView::paint (QPainter *painter,
                             const QStyleOptionGraphicsItem *option,
                             QWidget *widget)
{
  Q_UNUSED (painter);
  Q_UNUSED (option);
  Q_UNUSED (widget);
}


bool BSStructureView::processKeyEvent (QKeyEvent *event)
{
  bool processed = false;
  switch (event->key ())
  {
    case Qt::Key_I : // Info
      if (event->modifiers () & Qt::ControlModifier) grid->switchScanDisplay ();
      else grid->toggleDisplay ((event->modifiers () & Qt::ShiftModifier) == 0);
      setWindowTitle (grid->itemTitle ());
      update ();
      processed = true;
      break;

    case Qt::Key_V : // Info display
      grid->switchInfoDisplay ();
      update ();
      processed = true;
      break;

    case Qt::Key_B : // Background
      if (event->modifiers () & Qt::ShiftModifier) toggleGradient ();
      else toggleBackground ();
      updateBackground (true);
      update ();
      processed = true;
      break;

    case Qt::Key_Plus : // Zoom in
      grid->zoomIn ();
      updateBackground (true);
      update ();
      processed = true;
      break;

    case Qt::Key_Minus : // Zoom out
      grid->zoomOut ();
      updateBackground (true);
      update ();
      processed = true;
      break;

    case Qt::Key_Left : // Go leftwards
      grid->shift (-1, 0);
      updateBackground (false);
      update ();
      processed = true;
      break;

    case Qt::Key_Right : // Go rightwards
      grid->shift (1, 0);
      updateBackground (false);
      update ();
      processed = true;
      break;

    case Qt::Key_Up : // Go upwards
      grid->shift (0, -1);
      updateBackground (false);
      update ();
      processed = true;
      break;

    case Qt::Key_Down : // Go downwards
      grid->shift (0, 1);
      updateBackground (false);
      update ();
      processed = true;
      break;

    case Qt::Key_C : // Increments the connected components min size
      det->incConnectedComponentMinSize (
            (event->modifiers () & Qt::ShiftModifier) == 0);
      update ();
      processed = true;
      break;

    case Qt::Key_G : // Increments the connected components min size
      det->switchConnectivityConstraint ();
      update ();
      processed = true;
      break;

    case Qt::Key_S : // Switch dynamic scans
      det->switchDynamicScans ();
      update ();
      processed = true;
      break;

    case Qt::Key_O : // Switch orthographic scans
      det->switchOrthoScans ();
      update ();
      processed = true;
      break;

    case Qt::Key_P : // Switch pre-filtering
      det->switchFiltering (0);
      update ();
      processed = true;
      break;

    case Qt::Key_F : // Switch final filtering
      det->switchFiltering (1);
      update ();
      processed = true;
      break;

    case Qt::Key_D : // Initial detection extension limitation
      det->switchInitialBounding ();
      update ();
      processed = true;
      break;

    case Qt::Key_W : // Input max width
      det->setInputMaxWidth (det->getInputMaxWidth () +
        (event->modifiers () & Qt::ShiftModifier ? -1 : 1));
      update ();
      processed = true;
      break;

    case Qt::Key_K : // Output blurred segment min size
      det->setBSminSize (det->getBSminSize () +
        (event->modifiers () & Qt::ShiftModifier ? -1 : 1));
      update ();
      processed = true;
      break;

    case Qt::Key_H : // Pixel lack tolerence
      det->setPixelLackTolerence (det->getPixelLackTolerence () +
        (event->modifiers () & Qt::ShiftModifier ? -1 : 1));
      update ();
      processed = true;
      break;
  }
  return processed;
}