/***************************************************************************
**
**  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: 2008-03-02
**  Copyright: 2008-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include <math.h>

#include "ColorMapData.h"

namespace QGpCoreMath {

/*!
  \class ColorMapData ColorMapData.h
  \brief Brief description of class still missing

  Full description of class still missing
*/

/*!
  Description of constructor still missing
*/
ColorMapData::ColorMapData()
  : QSharedData()
{
  TRACE;
  _upperValues=0;
  _n2=0;
}

ColorMapData::ColorMapData(const ColorMapData& o)
  : QSharedData(o), _palette(o._palette)
{
  TRACE;
  _n2=o._n2;
  int n1=count()-1;
  _upperValues=new double[n1];
  for(int i=0; i<n1; i++) {
    _upperValues[i]=o._upperValues[i];
  }
}

/*!
  Description of destructor still missing
*/
ColorMapData::~ColorMapData()
{
  TRACE;
  delete [] _upperValues;
}

/*!
  Assign \a pal. If the number of colors is different, the values are lost.
*/
void ColorMapData::setPalette(const ColorPalette& pal)
{
  TRACE;
  resize(pal.count());
  _palette=pal;
}

bool ColorMapData::operator==(const ColorMapData& o) const
{
  TRACE;
  if(_palette==o._palette) {
    int n1=count()-1;
    for(int i=0; i<n1; i++) {
      if(_upperValues[i]!=o._upperValues[i]) {
        return false;
      }
    }
    return true;
  } else {
    return false;
  }
}

/*!
  Compares the number of colors. A bit useless function but required for QMetaType::registerComparators()
*/
bool ColorMapData::operator<(const ColorMapData& o) const
{
  TRACE;
  return _palette.count()<o._palette.count();
}

void ColorMapData::resize(int n)
{
  TRACE;
  if(!_upperValues || n!=count()) {
    _palette.resize(n);
    if(_upperValues) {
      delete [] _upperValues;
    }
    _upperValues=new double[count()-1];
    _n2=1;
    int n1=count()-1;
    while(_n2<n1) {
      _n2=_n2 << 1;
    }
    _n2=_n2 >> 1;
  }
}

void ColorMapData::setVLinear(int imin, int imax, double min, double max)
{
  TRACE;
  if(count()>2) {
    if(imin<0) {
      imin=0;
    } else if(imin>=count()-1) {
      imin=count()-2;
    }
    if(imax<0) {
      imax=0;
    } else if(imax>=count()-1) {
      imax=count()-2;
    }
    double inc=(max-min)/(double)(imax-imin);
    _upperValues[imin]=min;
    for(int i=imin+1; i<=imax; i++) {
      _upperValues[i]=_upperValues[i-1]+inc;
    }
  } else if(count()==2) {
    _upperValues[0]=(min+max)*0.5;
  }
}


void ColorMapData::setVLog(int imin, int imax, double min, double max)
{
  TRACE;
  if(count()>2) {
    if(imin<0) {
      imin=0;
    } else if(imin>=count()-1) {
      imin=count()-2;
    }
    if(imax<0) {
      imax=0;
    } else if(imax>=count()-1) {
      imax=count()-2;
    }
    double inc=pow(max/min, 1.0/(double)(imax-imin));
    _upperValues[imin]=min;
    for(int i=imin+1; i<=imax; i++) {
      _upperValues[i]=_upperValues[i-1]*inc;
    }
  } else if(count()==2) {
    _upperValues[0]=(min+max)*0.5;
  }
}

/*!
  Returns the color index of value \a val.
  The color map must at least contain two items.
*/
int ColorMapData::index(double val) const
{
  TRACE;
  if(val<=_upperValues[0]) {
    return 0;
  }
  int lasti=count()-2;
  if(val>_upperValues[lasti]) {
    return lasti+1;
  }
  int i=_n2;
  int step2=i >> 1;
  while(step2>0) {
    if(i>lasti) {
      i-=step2;
    } else if(val<=_upperValues[i]) {
      if(val>_upperValues[i-1]) {
        break;
      }
      i-=step2;
    } else {
      i+=step2;
    }
    step2=step2 >> 1;
  }
  return i;
}

} // namespace QGpCoreMath
