/***************************************************************************
**
**  This file is part of QGpCoreMath.
**
**  QGpCoreTools is free software: you can redistribute it and/or modify
**  it under the terms of the GNU General Public License as published by
**  the Free Software Foundation, either version 3 of the License, or
**  (at your option) any later version.
**
**  QGpCoreTools 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 General Public License for more details.
**
**  You should have received a copy of the GNU General Public License
**  along with Foobar.  If not, see <http://www.gnu.org/licenses/>
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2020-02-18
**  Copyright: 2020
**    Marc Wathelet (ISTerre, Grenoble, France)
**
***************************************************************************/

#include "XUniqueYColorData.h"

namespace QGpCoreMath {

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

    Full description of class still missing
  */

  /*!
    Description of constructor still missing
  */
  XUniqueYColorData::XUniqueYColorData()
  {
    _curveCount=0;
    _xCount=0;
    _x=0;
    _y=0;
    _colors=0;
  }

  /*!
    Description of destructor still missing
  */
  XUniqueYColorData::~XUniqueYColorData()
  {
    clear();
  }

  /*!
  */
  void XUniqueYColorData::clear()
  {
    delete [] _x;
    delete [] _y;
    delete [] _colors;
    _x=nullptr;
    _y=nullptr;
    _colors=nullptr;
    _curveCount=0;
    _xCount=0;
  }

  /*!
    This is the unique function you have to call to populate this layer with lines.
  */
  void XUniqueYColorData::setPointCount(int nCurves, int nX)
  {
    if(_curveCount>0 && nX==_xCount) {
      if(nCurves==0) {
        clear();
        return;
      }
      int minNCurves=nCurves;
      if(_curveCount<minNCurves) minNCurves=_curveCount;
      double * new_y=new double [nCurves*nX];
      memcpy(new_y, _y, minNCurves*nX*sizeof(double));
      delete [] _y;
      _y=new_y;
      _curveCount=nCurves;
    } else {
      clear();
      _curveCount=nCurves;
      _xCount=nX;
      if(_xCount>0) _x=new double[_xCount];
      if(_curveCount > 0) _y=new double [_xCount*_curveCount];
    }
  }

  void XUniqueYColorData::setColors(Color * col)
  {
    delete [] _colors;
    _colors=col;
  }

  /*!
    Calculate the rectangle that includes all the curves
  */
  Rect XUniqueYColorData::boundingRect() const
  {
    if(_curveCount==0 || !_xCount) return Rect();
    Rect r(_x[0], _y[0], _x[0], _y[0]);
    double * y=_y;
    for(int i=0; i<_curveCount; i++) {
      for(int j=0; j<_xCount; j++) {
        r.add(_x[j], y[j]);
      }
      y+=_xCount;
    }
    return r;
  }

  /*!
    Return the list of points inside rectangle \a r.
  */
  QVector<int> * XUniqueYColorData::inside(const Rect& r)
  {
    QVector<int> * indexList=new QVector<int>;
    double * y=_y;
    for(int i=0; i<_curveCount; i++) {
      for(int j=1; j<_xCount; j++) {
        if(r.includes(_x[j-1], y[j-1], _x[j], y[j])) {
          indexList->push_back(i);
          break;
        }
      }
      y+=_xCount;
    }
    return indexList;
  }

  void XUniqueYColorData::toStream(QDataStream& s) const
  {
    s << _curveCount;
    s << _xCount;
    saveColors(s, _colors, _curveCount);
    s.writeRawData((const char *)_x, sizeof(double) * _xCount);
    s.writeRawData((const char *)_y, sizeof(double) * _xCount*_curveCount);
  }

  bool XUniqueYColorData::fromStream(QDataStream& s, const Version * fileVersion)
  {
    TRACE;
    s >> _curveCount;
    s >> _xCount;
    if(_curveCount>0) {
      restoreColors(s, _colors, _curveCount, fileVersion);
      _x=new double [_xCount];
      s.readRawData((char *) _x, sizeof(double)*_xCount);
      _y=new double [_xCount*_curveCount];
      s.readRawData((char *) _y, sizeof(double)*_xCount*_curveCount);
    }
    return true;
  }

  void XUniqueYColorData::saveColors(QDataStream& s, Color * colors, int count)
  {
    if(colors) {
      const unsigned char colorSize=4;
      s << colorSize;
      // We cannot save the QColor structure as whole block any longer (bugs)
      // Transform QColor into 4 unsigned char r,g,b,a. Transparency introduced on 20091117
      unsigned char * tmpColors=new unsigned char[colorSize*count];
      unsigned char * tmpPtr=tmpColors;
      for(int i=0; i<count; i++) {
        const Color& c=colors[i];
        *(tmpPtr++)=(unsigned char)c.red();
        *(tmpPtr++)=(unsigned char)c.green();
        *(tmpPtr++)=(unsigned char)c.blue();
        *(tmpPtr++)=(unsigned char)c.alpha();
      }
      s.writeRawData((const char *) tmpColors, colorSize*sizeof(unsigned char)*count);
      delete [] tmpColors;
    } else {
      const unsigned char colorSize=0;
      s << colorSize;
    }
  }

  /*!

  */
  void XUniqueYColorData::restoreColors(QDataStream& s, Color *& colors, int count,
                                        const Version * fileVersion)
  {
    // Compatibility
    //   before 20091117, a bool was recorded: color or not
    //   Introduction of an unsigned char was required to introduce transparency
    unsigned char colorSize;
    ASSERT(sizeof(bool)==sizeof(unsigned char) && true==1 && false==0);
    static const Version vRef(1, 0, 99); // 20070503 (version 1.1.0): add boolean flag for colors or not
    if(!fileVersion || *fileVersion>vRef) {
      s >> colorSize;
      if(colorSize==1) colorSize=3;
    } else {
      colorSize=3; // Except for .page generated from PtMotion geopsy module, this value is the correct one
                   // Old .page files generated with PtMotion geopsy module won't display the curves but it won't crash.
                   // This is due to an historical stupid format missing a flag telling if colors were there or not.
    }
    delete [] colors;
    if(colorSize>0) {
      colors=new Color[count];
      unsigned char * tmpColors=new unsigned char[colorSize*count];
      s.readRawData((char *) tmpColors, colorSize*sizeof(unsigned char)*count);
      Color *& origColors=colors;
      unsigned char * tmpPtr=tmpColors;
      if(colorSize==3) {
        for(int i=0; i<count; i++) {
          origColors[i].setRgba(tmpPtr[0], tmpPtr[1], tmpPtr[2]);
          tmpPtr+=3;
        }
      } else {
        for(int i=0; i<count; i++) {
          origColors[i].setRgba(tmpPtr[0], tmpPtr[1], tmpPtr[2], tmpPtr[3]);
          tmpPtr+=4;
        }
      }
      delete [] tmpColors;
    } else {
      colors=0;
    }
  }

} // namespace QGpCoreMath

