/***************************************************************************
**
**  This file is part of QGpGuiMath.
**
**  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: 2006-01-10
**  Copyright: 2006-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include "ImageLayerProperties.h"
#include "ImageLayer.h"
#include "ImageScalingPoint.h"

namespace QGpGuiMath {

  ImageLayerProperties::ImageLayerProperties(QWidget * parent)
      : PropertyWidget(parent)
  {
    TRACE;
    setupUi(this);
    xEdit->setMinimum(-std::numeric_limits<double>::infinity());
    yEdit->setMinimum(-std::numeric_limits<double>::infinity());
    xScaleEdit->setMinimum(-std::numeric_limits<double>::infinity());
    yScaleEdit->setMinimum(-std::numeric_limits<double>::infinity());
    xEdit->setMaximum(std::numeric_limits<double>::infinity());
    yEdit->setMaximum(std::numeric_limits<double>::infinity());
    xScaleEdit->setMaximum(std::numeric_limits<double>::infinity());
    yScaleEdit->setMaximum(std::numeric_limits<double>::infinity());

    addProperty(XOrigin, xEdit, xLabel);
    addProperty(YOrigin, yEdit, yLabel);
    addProperty(XScale, xScaleEdit, xScaleLabel);
    addProperty(YScale, yScaleEdit, yScaleLabel);
    addProperty(ImageFile, imageEdit, imageLabel);

    _referencePoints=nullptr;
  }

  ImageLayerProperties::~ImageLayerProperties()
  {
    TRACE;
    delete _referencePoints;
  }

  void ImageLayerProperties::addLayer(ImageLayer * layer)
  {
    TRACE;
    if(_layerSet.contains(layer)) return;
    _layerSet.insert(layer);
    toggleReferencePoints();
  }

  void ImageLayerProperties::removeLayer(ImageLayer * layer)
  {
    TRACE;
    if(!_layerSet.contains(layer)) return;
    _layerSet.remove(layer);
    toggleReferencePoints();
    if(_layerSet.isEmpty()) {
      layer->toggleTrackingAction(false, ImageLayer::Scale);
      delete _referencePoints;
      _referencePoints=nullptr;
    }
  }

  /*!
    Return true if the \a fileName can be loaded (exists and user did not cancel).
  */
  bool ImageLayerProperties::loadImage(const QString &fileName)
  {
    TRACE;
    QFileInfo fi(fileName);
    if(fi.exists() && _layerSet.count()==1) {
      QImage im;
      im.load(fileName);
      AxisWindow * w=(*_layerSet.begin())->graph();
      switch(Message::question(MSG_ID, tr("Image layer"),
                               tr("Do you want to adjust image origin and scale automatically?"),
                               Message::yes(), Message::no(), Message::cancel(), true)) {
      case Message::Answer0: {
          switch(w->xAxis()->scaleType()) {
          case Scale::Linear:
          case Scale::Log:
          case Scale::AbsoluteTime:
          case Scale::RelativeTime:
            xEdit->setValue(w->xAxis()->minimum());
            xScaleEdit->setValue((w->xAxis()->maximum()-w->xAxis()->minimum())/im.width());
            break;
          case Scale::Inversed:
          case Scale::InversedLog:
            xEdit->setValue(1.0/w->xAxis()->maximum());
            xScaleEdit->setValue((1.0/w->xAxis()->minimum()-1.0/w->xAxis()->maximum())/im.width());
            break;
          }
          switch(w->yAxis()->scaleType()) {
          case Scale::Linear:
          case Scale::Log:
          case Scale::AbsoluteTime:
          case Scale::RelativeTime:
            yEdit->setValue(w->yAxis()->maximum());
            yScaleEdit->setValue((w->yAxis()->minimum()-w->yAxis()->maximum())/im.height());
            break;
          case Scale::Inversed:
          case Scale::InversedLog:
            yEdit->setValue(1.0/w->yAxis()->minimum());
            yScaleEdit->setValue((1.0/w->yAxis()->maximum()-1.0/w->yAxis()->minimum())/im.height());
            break;
          }
        }
        return true;
      case Message::Answer1:
        return true;
      case Message::Answer2:
        break;
      }
    }
    return false;
  }

  void ImageLayerProperties::on_imageEdit_textEdited(const QString& text)
  {
    TRACE;
    loadImage(text);
  }

  void ImageLayerProperties::on_imageBrowse_clicked()
  {
    TRACE;
    QString fileName=Message::getOpenFileName(tr("Open an existing image"),
                                                   GraphicObject::pixelImageFilter);
    if(!fileName.isEmpty()) {
      if(loadImage(fileName)) {
        imageEdit->setText(fileName);
      }
    }
  }

  void ImageLayerProperties::on_referenceButton_clicked()
  {
    TRACE;
    if(_layerSet.count()!=1) {
      return;
    }
    ImageLayer * l=*_layerSet.begin();
    if(!_referencePoints) {
      _referencePoints=new ImageScalingPoint(this);
      connect(_referencePoints, SIGNAL(apply()), this, SLOT(setScaling()));
      connect(_referencePoints, SIGNAL(destroyed(QObject *)), this, SLOT(referencePointClosed()));
      connect(l, SIGNAL(pointPicked(QPoint)), _referencePoints, SLOT(add(QPoint)));
      _referencePoints->setReferences(l->references());
    }
    l->toggleTrackingAction(true, ImageLayer::Scale);
    _referencePoints->show();
    _referencePoints->raise();
  }

  void ImageLayerProperties::setScaling()
  {
    TRACE;
    if(!_referencePoints || _layerSet.count()!=1) {
      return;
    }
    ImageLayer * l=*_layerSet.begin();
    l->setReferences(_referencePoints->references());
    l->setScaling();
    emit refreshValues();
    l->deepUpdate();
  }

  void ImageLayerProperties::referencePointClosed()
  {
    TRACE;
    _referencePoints=nullptr;
    if(!_layerSet.isEmpty()) {
      ImageLayer * l=*_layerSet.begin();
      l->toggleTrackingAction(false, ImageLayer::Scale);
    }
  }

  void ImageLayerProperties::toggleReferencePoints()
  {
    TRACE;
    if(_layerSet.count()==1) {
      referenceButton->setEnabled(true);
    } else {
      if(_referencePoints) {
        delete _referencePoints;
        _referencePoints=nullptr;
      }
      referenceButton->setEnabled(false);
    }
  }

} // namespace QGpGuiMath
