/***************************************************************************
**
**  This file is part of SciFigs.
**
**  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-02-14
**  Copyright: 2008-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include "LayerPainterRequest.h"
#include "GraphContent.h"
#include "SciFigsGlobal.h"

namespace SciFigs {

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

  Full description of class still missing
*/

/*!
  \fn void LayerPainterRequest::setGraphContent(GraphContent * gc)
*/

/*!
  \fn void LayerPainterRequest::setDepth(int depth)
  Depth is relative to the final display. It is not the layer index to start with. A depth of 0 is for starting
  from the uppermost layer. A depth of -1, means do nothing.
*/

/*!
  \fn int LayerPainterRequest::depth() const
  \sa setDepth()
*/

LayerPainterRequest::LayerPainterRequest()
{
  _terminate=false;
  _gc=nullptr;
}

/*!
  \fn void LayerPainterRequest::setGraphContent(GraphContent * gc)
  Can be called only outside a painting thread.
*/

/*!
  \fn void LayerPainterRequest::setLayers(QList<GraphContentLayer *> layers)
  Can be called only outside a painting thread. Used only for true painting requests. For other requests (e.g. clear),
  setLayers() is not mandatory.
*/

/*!
  Can be called only outside a painting thread. Set the depth of painting. It is automatically adjusted to available
  layer images (setLayerImage() must be called before).
*/
void LayerPainterRequest::setDepth(int depth)
{
  _depth=depth;
  if(_depth > 0) {
    GraphContentLayer * l=_layers.at(_depth);
    if(!_layerImages.contains(l)) {
      _layerImages.insert(l,QImage(_size, QImage::Format_ARGB32_Premultiplied));
      do {
        _depth--;
      } while(_depth>0 && !_layerImages.contains(_layers.at(_depth)));
    }
  }
}

inline void LayerPainterRequest::paintLayers(QPainter& p)
{
  TRACE;
  GraphContentLayer * l;
  int nLayers=_layers.count();
  if(_layerImages.isEmpty()) {
    for(int i=0;i<nLayers;i++) {
      if(terminated()) return;
      _layers.at(i)->paint(*this, p, SciFigsGlobal::screenResolution());
    }
  } else { // Save some pixmap layers
    for(int i=0;i<nLayers;i++) {
      if(terminated()) return;
      l=_layers.at(i);
      if(_layerImages.contains(l)) {
        // Force a deep copy (implicit sharing of QImage does not work properly because inside begin/end)
        _layerImages[l]=_image.copy();
      }
      l->paint(*this, p, SciFigsGlobal::screenResolution());
    }
  }
}

inline void LayerPainterRequest::paintLayers(int fromIndex, QPainter& p)
{
  if(terminated()) return;
  GraphContentLayer * l;
  // Start to paint ith layer
  l=_layers.at(fromIndex);
  p.drawImage(0,0,_layerImages[l]);
  l->paint(*this, p, SciFigsGlobal::screenResolution());
  // Then draw others according to drawing order
  int nLayers=_layers.count();
  for(int i=fromIndex+1;i<nLayers;i++) {
    if(terminated()) return;
    l=_layers.at(i);
    if(_layerImages.contains(l)) {
      // Force a deep copy (implicit sharing of QImage does not work properly because inside begin/end)
      _layerImages[l]=_image.copy();
    }
    l->paint(*this, p, SciFigsGlobal::screenResolution());
  }
}

void LayerPainterRequest::paintText()
{
  int nLayers=_layers.count();
  for(int i=_depth;i<nLayers;i++) {
    _layers.at(i)->paintText( *this, SciFigsGlobal::screenResolution());
  }
}

void LayerPainterRequest::paint()
{
  _image=QImage(_size, QImage::Format_ARGB32_Premultiplied);

  QPainter p;
  p.begin(&_image);
  if(_depth==0) {
    p.fillRect(0, 0, _size.width(), _size.height(), Qt::white);
    if(_options.gridLines()) {
      _options.paintGridLines(p, SciFigsGlobal::screenResolution(), _size.width(), _size.height());
    }
    paintLayers(p);
  } else { // Plot only some of the layers
    paintLayers(_depth, p);
  }
  if(terminated()) {
    p.end();
    return;
  }
  if(_options.contourWeight()>0) {
    _options.paintContour(p, SciFigsGlobal::screenResolution(), _size.width(), _size.height());
  }
  p.end();
  emit finished(_image, _layerImages);
}

} // namespace SciFigs
