/***************************************************************************
**
**  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: 2007-10-30
**  Copyright: 2007-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include "LineLayerProperties.h"
#include "LineItem.h"
#include "LineDelegate.h"
#include "LineLayer.h"
#include "AxisWindow.h"
#include "Legend.h"
#include "LegendProperties.h"
#include "LayerLocker.h"

namespace SciFigs {

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

  Full description of class still missing
*/

/*!
  Description of constructor still missing
*/
LineLayerProperties::LineLayerProperties(QWidget * parent)
    : PropertyWidget(parent)
{
  TRACE;
  setupUi(this);

  LineItem * model=new LineItem(this);
  lineTable->setModel(model);
  LineDelegate * del=new LineDelegate(this);
  lineTable->setItemDelegate(del);
  lineTable->setSelectionBehavior(QAbstractItemView::SelectItems);
  lineTable->setSelectionMode(QAbstractItemView::ExtendedSelection);
  lineTable->setEditTriggers(QAbstractItemView::AllEditTriggers);
  lineTable->resizeColumnsToContents();
  Settings::columnWidth(lineTable, "LineLayerProperties");

  connect(del, SIGNAL(dataChanged()), this, SLOT(applyAllSelected()) );

  // Init the action menu
  QMenu * m=new QMenu(this);
  m->setTitle(tr("Actions"));
  m->setTearOffEnabled (true);
  actionsBut->setMenu(m);

  QAction * a;
  a=addLineAction(tr( "&Save" ), tr( "Save current line in a text file" ));
  connect(a, SIGNAL(triggered()), this, SLOT(save()) );
  _removeAction=addLineAction(tr( "&Remove" ), tr( "Remove current line" ));
  connect(_removeAction, SIGNAL(triggered()), this, SLOT(remove()) );

  lineScroll->setMinimum(0);
  lineScroll->setMaximum(0);

  _legendEditor=nullptr;
}

/*!
  Description of destructor still missing
*/
LineLayerProperties::~LineLayerProperties()
{
  TRACE;
  Settings::setColumnWidth(lineTable, "LineLayerProperties");
}

QAction * LineLayerProperties::addLineAction(QString title, QString toolTip)
{
  TRACE;
  QAction * a;
  a=new QAction(title, this);
  a->setToolTip(toolTip);
  actionsBut->menu()->addAction(a);
  return a;
}

void LineLayerProperties::addLayer(LineLayer * layer)
{
  TRACE;
  if(_layerSet.contains(layer)) return;
  _layerSet.insert(layer);
  setLayerList();
  on_currentLayerCombo_currentIndexChanged(0);
}

void LineLayerProperties::removeLayer(LineLayer * layer)
{
  TRACE;
  if(!_layerSet.contains(layer)) return;
  _layerSet.remove(layer);
  setLayerList();
  on_currentLayerCombo_currentIndexChanged(0);
}

bool LineLayerProperties::layerLessThan(const LineLayer * l1, const LineLayer * l2)
{
  QString l1Name, l2Name;
  if(l1->graph()->objectName().isEmpty())
    l1Name="unamed_graph::" + l1->objectName();
  else
    l1Name=l1->graph()->objectName() + "::" + l1->objectName();
  if(l2->graph()->objectName().isEmpty())
    l2Name="unamed_graph::" + l2->objectName();
  else
    l2Name=l2->graph()->objectName() + "::" + l2->objectName();
  return l1Name<l2Name;
}

void LineLayerProperties::setLayerList()
{
  TRACE;
  _layerList.clear();
  for(QSet<LineLayer *>::iterator it=_layerSet.begin();it!=_layerSet.end();it++) {
    _layerList.append(*it);
  }
  std::sort(_layerList.begin(), _layerList.end(), layerLessThan);
  currentLayerCombo->clear();
  for(QList<LineLayer *>::iterator it=_layerList.begin();it!=_layerList.end();it++) {
    LineLayer * layer=*it;
    if(layer->graph()->objectName().isEmpty())
      currentLayerCombo->addItem("unamed_graph::" + layer->objectName());
    else
      currentLayerCombo->addItem(layer->graph()->objectName() + "::" + layer->objectName());
  }
}

LineLayer * LineLayerProperties::currentLayer() const
{
  TRACE;
  int i=currentLayerCombo->currentIndex();
  if(i<_layerList.count() && i>=0) {
    return _layerList[i];
  } else {
    return nullptr;
  }
}

int LineLayerProperties::currentLine() const
{
  TRACE;
  return lineScroll->value();
}

AbstractLine * LineLayerProperties::line(int index) const
{
  TRACE;
  int i=currentLayerCombo->currentIndex();
  if(i<_layerList.count() && i>=0) {
    if(index<_layerList[i]->count()) {
      return _layerList[i]->line(index);
    }
  }
  return nullptr;
}

void LineLayerProperties::remove()
{
  TRACE;
  LineLayer * layer=currentLayer();
  if(!layer) return;
  LayerLocker ll(layer);
  int lineIndex=currentLine();
  if(lineIndex>=0 && lineIndex<layer->count()) {
    layer->removeLine(lineIndex);
    lineScroll->setMaximum(layer->count()-1);
    if(lineIndex>=layer->count()) {
      lineIndex=layer->count()-1;
    }
    lineScroll->setValue(lineIndex);
    layer->deepUpdate();
  }
}

void LineLayerProperties::updateCurrentLayer()
{
  TRACE;
  on_currentLayerCombo_currentIndexChanged(0);
}

void LineLayerProperties::updateCurrentLine()
{
  TRACE;
  on_lineScroll_valueChanged(0);
}

void LineLayerProperties::on_legendBut_clicked()
{
  TRACE;
  if(!currentLayer()) return;
  Legend legend=currentLayer()->legend();
  Dialog * d=new Dialog(this);
  ASSERT(!_legendEditor);
  _legendEditor=new LegendProperties(this);
  _legendEditor->setPropertySections(LegendTable::All);
  d->setMainWidget(_legendEditor, Dialog::TitleClose);
  _legendEditor->setLegend(legend);
  _legendEditor->setReadOnlyText(true);
  Settings::getRect(d, "LineLayerProperties::legend");
  connect(_legendEditor, SIGNAL(touched()), this, SLOT(commitLegend()));
  d->exec();
  Settings::setRect(d, "LineLayerProperties::legend");
  delete d;
  _legendEditor=nullptr;
}

void LineLayerProperties::commitLegend()
{
  TRACE;
  if(_legendEditor) {
    currentLayer()->setLegend(_legendEditor->legend());
    currentLayer()->deepUpdate();
  }
}

void LineLayerProperties::setEnableCurveButtons(bool b)
{
  TRACE;
  legendBut->setEnabled(b);
  actionsBut->setEnabled(b);
  visibleBut->setEnabled(b);
  lineTable->setEnabled(b);
}

void LineLayerProperties::on_currentLayerCombo_currentIndexChanged(int)
{
  TRACE;
  const LineLayer * selectedLayer=currentLayer();
  if(selectedLayer) {
    int n=selectedLayer->count();
    if(n>0)
      lineScroll->setMaximum(selectedLayer->count()-1);
    else
      lineScroll->setMaximum(0);
    _removeAction->setEnabled(selectedLayer->isRemovable());
  }
  lineScroll->setValue(0);
  on_lineScroll_valueChanged(0);
}

void LineLayerProperties::on_lineScroll_valueChanged(int)
{
  TRACE;
  LineItem * item=qobject_cast<LineItem *>(lineTable->model());
  if(!currentLayer()|| currentLayer()->count()==0 ) {
    lineBox->setTitle(tr("No curve defined"));
    item->setLine(nullptr, nullptr);
    setEnableCurveButtons(false);
  } else {
    int i=lineScroll->value();
    lineBox->setTitle(tr("Line %1 of %2").arg(i+1).arg(currentLayer()->count()));
    AbstractLine * l=line(currentLine());
    if(!l) { // Bug encountered in Beirut 20160919
      TRACE_BUG;
      TRACE_BUG_INT(currentLine());
      TRACE_BUG_INT(currentLayer()->count());
      ASSERT(l);
    }
    item->setLine(currentLayer(), l);
    visibleBut->setChecked(l->isVisible());
    setEnableCurveButtons(true);
  }
}

void LineLayerProperties::on_visibleBut_toggled(bool checked)
{
  TRACE;
  AbstractLine * l=line(currentLine());
  if(!l) return;
  if(l->isVisible()!=checked) {
    LineLayer * layer=currentLayer();
    if(layer) {
      LayerLocker ll(layer);
      l->setVisible(checked);
      layer->deepUpdate();
    }
  }
}

void LineLayerProperties::applyAllSelected()
{
  TRACE;
  QAbstractItemModel& model=* lineTable->model();
  QModelIndex curIndex=lineTable->currentIndex();
  QModelIndexList l=lineTable->selectionModel()->selectedRows();
  if(l.count()>1) {
    QVariant val=model.data(curIndex);
    QModelIndex index;
    foreach(index, l) {
      model.setData(model.index(index.row(), curIndex.column()), val);
    }
  }
}

void LineLayerProperties::save()
{
  TRACE;
  QString fileName=Message::getSaveFileName(tr("Save line"), tr("3 column file(*)"));
  if( !fileName.isEmpty()) save3Columns(fileName, lineScroll->value());
}

void LineLayerProperties::save3Columns(QString fileName, int lineIndex)
{
  TRACE;
  QFile f(fileName);
  if( !f.open(QIODevice::WriteOnly) ) {
    Message::warning(MSG_ID, tr("Saving line"),
                          tr("Impossible to access to file"), Message::cancel());
    return ;
  }
  LineLayer * layer=currentLayer();
  AbstractLine& l=*line(lineIndex);
  QTextStream s(&f);
  s << "# x | y | dy" << endl;
  int n=l.count();
  for(int i=0;i < n;i++ ) {
    if(l.isValid(i)) {
      Point p=l.point(i, layer->pointOptions());
      s << p.x() << " " << p.y() << " " << p.z() << endl;
    }
  }
}


} // namespace SciFigs
