#ifndef CGAL_VOLUME_PLANE_THREAD_H
#define CGAL_VOLUME_PLANE_THREAD_H

#include "Volume_plane.h"
#include <CGAL/Image_3.h>

#include "Scene_image_item.h"

#include <QApplication>
#include <QThread>
#include <vector>

struct Clamp_to_one_zero_range {
  std::pair<float, float> min_max;
  float operator()(const float& inVal) {
    float inValNorm = inVal - min_max.first;
    float aUpperNorm = min_max.second - min_max.first;
    float bValNorm = inValNorm / aUpperNorm;
    return bValNorm;
  }
};

class Volume_plane_thread : public QThread {
Q_OBJECT
public:
  Volume_plane_thread(const CGAL::Image_3* img, const Clamp_to_one_zero_range& clamp, const QString& name)
    : img(img), clamper(clamp), item(nullptr), name(name) { _type = 'n';}

  Volume_plane_interface* getItem() {
    return item;
  }
  char type()const{
    return _type;
  }

Q_SIGNALS:
  void finished(Volume_plane_thread*);

protected:
  const CGAL::Image_3* img;
  Clamp_to_one_zero_range clamper;
  Volume_plane_interface* item;
  std::vector<float> buffer;
  QString name;
  char _type;
};

template<typename Word>
class X_plane_thread : public Volume_plane_thread {
public:
 X_plane_thread(Volume_plane<x_tag>*p_it, const CGAL::Image_3* img, const Clamp_to_one_zero_range& clamp, const QString& name)
  : Volume_plane_thread(img, clamp, name) { item = p_it; _type = 'x';}
protected:
  void run();
};

template<typename Word>
class Y_plane_thread : public Volume_plane_thread {
public:
 Y_plane_thread(Volume_plane<y_tag>* p_it, const CGAL::Image_3* img, const Clamp_to_one_zero_range& clamp, const QString& name)
  : Volume_plane_thread(img, clamp, name) {item = p_it; _type = 'y';}
protected:
  void run();
};

template<typename Word>
class Z_plane_thread : public Volume_plane_thread {
public:
 Z_plane_thread(Volume_plane<z_tag>* p_it, const CGAL::Image_3* img, const Clamp_to_one_zero_range& clamp, const QString& name)
  : Volume_plane_thread(img, clamp, name) {item = p_it; _type = 'z';}
protected:
  void run();
};

template<typename Word>
void X_plane_thread<Word>::run() {
    buffer.reserve(img->size());
    for(unsigned int i = 0; i < img->xdim(); ++i) {
      for(unsigned int j = 0; j < img->ydim(); ++j) {
        for(unsigned int k = 0; k < img->zdim(); ++k) {
          float x = float(CGAL::IMAGEIO::static_evaluate<Word>(img->image(),
                                                               i, j, k));
          x = clamper(x);
          buffer.push_back(x);
          buffer.push_back(x);
          buffer.push_back(x);
        }
      }
    }
    item->setData(static_cast<int>(img->ydim()), static_cast<int>(img->zdim()), static_cast<int>(img->xdim()),
                         img->vx(), img->vy(), img->vz(), buffer);

    item->setName(name);
    item->moveToThread(QApplication::instance()->thread());
    Q_EMIT finished(this);
}

template<typename Word>
void Y_plane_thread<Word>::run() {
      buffer.reserve(img->size());
    for(unsigned int i = 0; i < img->ydim(); ++i) {
      for(unsigned int j = 0; j < img->xdim(); ++j) {
        for(unsigned int k = 0; k < img->zdim(); ++k) {
          float x = float(CGAL::IMAGEIO::static_evaluate<Word>(img->image(),
                                                               j, i, k));
          x = clamper(x);
          buffer.push_back(x);
          buffer.push_back(x);
          buffer.push_back(x);
        }
      }
    }
    item->setData(static_cast<int>(img->xdim()), static_cast<int>(img->zdim()), static_cast<int>(img->ydim()),
                                   img->vx(), img->vy(), img->vz(), buffer);
    item->setName(name);
    item->moveToThread(QApplication::instance()->thread());
    Q_EMIT finished(this);
}

template<typename Word>
void Z_plane_thread<Word>::run() {
  for(unsigned int i = 0; i < img->zdim(); ++i) {
    for(unsigned int j = 0; j < img->xdim(); ++j) {
      for(unsigned int k = 0; k < img->ydim(); ++k) {
        float x = float(CGAL::IMAGEIO::static_evaluate<Word>(img->image(),
                                                             j, k, i));
        x = clamper(x);
        buffer.push_back(x);
        buffer.push_back(x);
        buffer.push_back(x);
      }
    }
  }
  item->setData(static_cast<int>(img->xdim()), static_cast<int>(img->ydim()), static_cast<int>(img->zdim()),
                                 img->vx(), img->vy(), img->vz(), buffer);
  item->setName(name);
  item->moveToThread(QApplication::instance()->thread());
  Q_EMIT finished(this);
}

#endif /* CGAL_VOLUME_PLANE_THREAD_H */
