//
// This file is part of MorphoGraphX - http://www.MorphoGraphX.org
// Copyright (C) 2012-2016 Richard S. Smith and collaborators.
//
// If you use MorphoGraphX in your work, please cite:
//   http://dx.doi.org/10.7554/eLife.05864
//
// MorphoGraphX is free software, and is licensed under under the terms of the 
// GNU General (GPL) Public License version 2.0, http://www.gnu.org/licenses.
// 
#include "ColorMap.hpp"
#include "Geometry.hpp"
#include "Util.hpp"
#include "Random.hpp"

namespace mgx
{
  Colorb ColorMap::getColor(int index) const
  {
    if(colors().size() == 0)
      return Colorb(0,0,0,0);

    return colors()[index % colors().size()];
  }

  Colorb ColorMap::getColor(float s, float sBegin, float sEnd, int iBegin, int iEnd) const
  {
    if(colors().size() == 0 or isNan(s) or isNan(sBegin) or isNan(sEnd))
      return Colorb(0,0,0,0);

    if(sBegin >= sEnd)
      return colors()[0];

    iBegin = trim(iBegin, 0, int(colors().size() - 1));
    iEnd = trim(iEnd, 0, int(colors().size() - 1));

    if(iBegin >= iEnd)
      return colors()[iBegin];

    s = trim((s - sBegin) / (sEnd - sBegin), 0.0f, 1.0f);
    int size = iEnd - iBegin;
    int idx = iBegin + s * size;
    if(idx >= iEnd)
      return colors()[iEnd];

    s = size * s - int(size * s);

    // Do interpolation in floating point
    Point4f colf((1.0 - s) * Point4f(colors()[idx]) + s * Point4f(colors()[idx + 1]));
		return Colorb(trim(int(colf[0]), 0, 255), trim(int(colf[1]), 0, 255), trim(int(colf[2]), 0, 255), trim(int(colf[3]), 0, 255));
	}

  Colorb ColorMap::getColor(float s, float sBegin, float sEnd) const
  { 
    return getColor(s, sBegin, sEnd, 0, colors().size() - 1);
  }

  Colorb ColorMap::getColor(float s, int iBegin, int iEnd) const
  {
    return getColor(s, bounds()[0], bounds()[1], iBegin, iEnd);
  }

  Colorb ColorMap::getColor(float s) const
  {
    return getColor(s, bounds()[0], bounds()[1], 0, colors().size() - 1);
  }

  bool ColorMap::setColorMap(const QString &map, uint sz)
  {
    if(sz == 0)
      sz = 16;
    if(map == "Labels") {
      colors().resize(16);
      colors()[0] = Colorb(255, 0, 0, 255);
      colors()[1] = Colorb(0, 255, 0, 255);
      colors()[2] = Colorb(0, 0, 255, 255);
      colors()[3] = Colorb(255, 255, 0, 255);
      colors()[4] = Colorb(255, 0, 255, 255);
      colors()[5] = Colorb(0, 255, 255, 255);
      colors()[6] = Colorb(128, 0, 0, 255);
      colors()[7] = Colorb(0, 128, 0, 255);
      colors()[8] = Colorb(0, 0, 128, 255);
      colors()[9] = Colorb(128, 0, 128, 255);
      colors()[10] = Colorb(128, 128, 0, 255);
      colors()[11] = Colorb(255, 0, 128, 255);
      colors()[12] = Colorb(128, 128, 255, 255);
      colors()[13] = Colorb(0, 128, 255, 255);
      colors()[14] = Colorb(128, 0, 255, 255);
      colors()[15] = Colorb(128, 255, 0, 255);
		} else if(map == "Grey") {
      colors().resize(sz);
      for(size_t i = 0; i < colors().size(); ++i) {
        uchar c = double(i) / (colors().size() - 1) * 255;
        Colorb col(c, c, c, 255);
        colors()[i] = col;
      }
    } else if(map == "Random") {
      colors().resize(sz);
      for(size_t i = 0; i < colors().size(); ++i) {
        Point3f r = ran(Point3f(1, 1, 1));
        Colorb col(r.x() * 255, r.y() * 255, r.z() * 255, 255);
        colors()[i] = col;
      } 
    } else if(map == "Jet") {
      colors().resize(9);
      colors()[0] = Colorb(0, 0, 128, 255);
      colors()[1] = Colorb(0, 0, 255, 255);
      colors()[2] = Colorb(0, 128, 255, 255);
      colors()[3] = Colorb(0, 255, 255, 255);
      colors()[4] = Colorb(128, 255, 128, 255);
      colors()[5] = Colorb(255, 255, 0, 255);
      colors()[6] = Colorb(255, 128, 0, 255);
      colors()[7] = Colorb(255, 0, 0, 255);
      colors()[8] = Colorb(128, 0, 0, 255);
    }
    return true;
  }

  QStringList ColorMap::getColorMapList() const
  {
    return QStringList() << "Labels" << "Grey" << "Random" << "Jet";
  }
}
