/***************************************************************************
**
**  This file is part of QGpCoreMath.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This file is distributed in the hope that it will be useful, but WITHOUT
**  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
**  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
**  License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2002-05-24
**  Copyright: 2002-2019
**    Marc Wathelet
**    Marc Wathelet (ULg, Liège, Belgium)
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include "ColorMap.h"

namespace QGpCoreMath {

/*!
  \class ColorMap ColorMap.h
  \brief A ColorMap links a color palette with a vector of values

  ColorMap are defined by a QColor vector of n elements and a vector
  of double of n-1 elements. Each value at i corresponds to the interface between
  the two colors at positions i and i+1. 
*/

const QString ColorMap::xmlColorMapTag="ColorMap";

// Automatic registration of ColorMap upon loading of the library
REGISTER_METATYPE(ColorMap)

bool ColorMap::xml_isValidTagName(const QString& t) const
{
  return t=="ColorPalette"; // Compatibility with old release
}

ColorPalette ColorMap::palette() const
{
  return _d->palette();
}

void ColorMap::setPalette(const ColorPalette& pal)
{
  _d->setPalette(pal);
}

void ColorMap::generateColorScale(int n, ColorPalette::Model m,
                                  bool reversed, int transparency)
{
  _d->generateColorScale(n, m, reversed, transparency);
}

void ColorMap::generateGrayScale(int n, ColorPalette::Model m,
                                 bool reversed, int transparency)
{
  _d->generateGrayScale(n, m, reversed, transparency);
}

void ColorMap::rgbInterpole(int imin, int imax)
{
  _d->rgbInterpole(imin, imax);
}

void ColorMap::hsvInterpole(int imin, int imax)
{
  _d->hsvInterpole(imin, imax);
}

void ColorMap::setWhiteTransparent(bool b)
{
  _d->setWhiteTransparent(b);
}

QTextStream& operator<<(QTextStream& s, const ColorMap& p)
{
  TRACE;
  int n=p.count();
  s << n << " elements\n";
  s << "upper   red    green    blue    alpha\n";
  n--;
  for(int i=0; i<n; i++ ) {
    s << p.upperValue(i) << " ";
    s << p.color(i).red() << " ";
    s << p.color(i).green() << " ";
    s << p.color(i).blue() << " ";
    s << p.color(i).alpha() << "\n";
  }
  // for compatibility reasons (with Sardine), store a last value
  s << 0 << " ";
  s << p.color(n).red() << " ";
  s << p.color(n).green() << " ";
  s << p.color(n).blue() << " ";
  s << p.color(n).alpha() << "\n";
  return s;
}

QTextStream& operator>>(QTextStream& s, ColorMap& p)
{
  TRACE;
  QString str;
  int r, g, b;
  bool ok;

  str=s.readLine();
  int n=str.section( " ", 0, 0).toInt(&ok);
  if( !ok || !n) goto error;
  p.resize(n);
  s.readLine();
  for(int i=0; i < n - 1; i++ ) {
    str=s.readLine();
    p.setUpperValue(i, str.section( " ", 0, 0).toDouble(&ok));
    if( !ok) goto error;
    r=str.section( " ", 1, 1).toInt(&ok);
    if( !ok) goto error;
    g=str.section( " ", 2, 2).toInt(&ok);
    if( !ok) goto error;
    b=str.section( " ", 3, 3).toInt(&ok);
    if( !ok) goto error;
    p.setColor(i, Color(r, g, b));
  }
  str=s.readLine();
  // first value is ignored for compatibility reasons (with Sardine)
  r=str.section( " ", 1, 1).toInt(&ok);
  if( !ok) goto error;
  g=str.section( " ", 2, 2).toInt(&ok);
  if( !ok) goto error;
  b=str.section( " ", 3, 3).toInt(&ok);
  if( !ok) goto error;
  p.setColor(n-1, Color(r, g, b));
  str=s.readLine(); // Read precision and number type for compatibility (no longer part of ColorMap 20080326)
  return s;
error:
  Message::wrongTextFormat(s, ColorMap::tr("Restoring color map"));
  return s;
}

void ColorMap::xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const
{
  TRACE;
  Q_UNUSED(context)
  writeProperty(s, "nColors", count());
  QString tmp;
  tmp+=s.indent();
  tmp+="<colorMap>\n";
  int n=count()-1;
  for(int i=0; i<n; i++) {
    tmp+=s.indent();
    tmp+=color(i).name();
    tmp+=" ";
    tmp+=QString::number(upperValue(i));
    tmp+="\n";
  }
  tmp+=s.indent();
  tmp+=color(n).name();
  tmp+="\n";
  tmp+=s.indent();
  tmp+="</colorMap>\n";
  s << tmp;
}

XMLMember ColorMap::xml_member(XML_MEMBER_ARGS)
{
  TRACE;
  Q_UNUSED(attributes)
  Q_UNUSED(context)
  if(tag=="nColors") return XMLMember(0);
  else if(tag=="colorMap") return XMLMember(3);
  else if(tag=="numberType") return XMLMember(1);       // Compatibility
  else if(tag=="numberPrecision") return XMLMember(2);  // Compatibility
  else if(tag=="palette") return XMLMember(3);          // Compatibility
  else if(tag=="numType") return XMLMember(1);          // Compatibility
  else if(tag=="numPrec") return XMLMember(2);          // Compatibility
  else return XMLMember(XMLMember::Unknown);
}

bool ColorMap::xml_setProperty(XML_SETPROPERTY_ARGS)
{
  TRACE;
  Q_UNUSED(tag)
  Q_UNUSED(attributes)
  Q_UNUSED(context)
  switch (memberID) {
  case 0: {
      int n=content.toInt();
      if(n > 0) {
        resize(n);
        return true;
      } else return false;
    }
  case 1:
  case 2:
    return true;
  case 3: {
      if(count()==0) return false;
      const QChar * ptr=nullptr;
      content.nextLine(ptr);
      StringSection f;
      int i;
      Color c;
      int n=count()-1;
      for(i=0; i<n; i++) {
        f=content.nextField(ptr);
        c.setNamedColor(f.toString());
        if(f.isValid()) {
          setColor(i, c);
        } else {
          break;
        }
        f=content.nextField(ptr);
        if(f.isValid()) {
          setUpperValue(i, f.toDouble());
        } else {
          break;
        }
        content.nextLine(ptr);
      }
      if(i==n) {
        // Last color without value
        f=content.nextField(ptr);
        c.setNamedColor(f.toString());
        if(f.isValid()) {
          setColor(i, c);
          i++;
        }
      }
      if(i==n+1) {
        return true;
      } else {
        App::log(tr("Error parsing color %1, incomplete line\n").arg(i));
        return false;
      }
    }
  default:
    break;
  }
  return false;
}


} // namespace QGpCoreMath
