/***************************************************************************
**
**  This file is part of waran.
**
**  waran 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.
**
**  waran 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: 2013-04-07
**  Copyright: 2013-2019
**    Marc Wathelet (ISTerre, Grenoble, France)
**
***************************************************************************/

#include "DistanceItem.h"

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

  Full description of class still missing
*/

/*!
  Description of constructor still missing
*/
DistanceItem::DistanceItem(QObject *parent, SortedStringList *pointNames)
  : QAbstractTableModel(parent)
{
  TRACE;
  _pointNames=pointNames;
}

/*!
  Description of destructor still missing
*/
DistanceItem::~DistanceItem()
{
  TRACE;
}

int DistanceItem::rowCount(const QModelIndex&) const
{
  TRACE;
  return _distances.count();
}

int DistanceItem::columnCount(const QModelIndex&) const
{
  TRACE;
  return 4;
}

QVariant DistanceItem::data(const QModelIndex & index, int role) const
{
  TRACE;
  const Distance& d=_distances.at(index.row());
  switch(role) {
  case Qt::EditRole:
  case Qt::DisplayRole:
    switch(index.column()) {
    case 0:
      return d.node1();
    case 1:
      return d.node2();
    case 2:
      return d.measured();
    case 3:
      return d.computed();
    default:
      break;
    }
    break;
  default:
    break;
  }
  return QVariant();
}

bool DistanceItem::setData(const QModelIndex & index, const QVariant & value, int role)
{
  TRACE;
  if(role!=Qt::EditRole) {
    return false;
  }
  Distance& d=_distances[index.row()];
  switch(index.column()) {
  case 0:
    d.setNode1(value.toString());
    emit pointNameChanged();
    return true;
  case 1:
    d.setNode2(value.toString());
    emit pointNameChanged();
    return true;
  case 2:
    d.setMeasured(value.toDouble());
    emit distanceChanged();
    return true;
  default:
    break;
  }
  return false;
}

QVariant DistanceItem::headerData(int section, Qt::Orientation orientation, int role) const
{
  TRACE;
  if(orientation==Qt::Horizontal && role==Qt::DisplayRole) {
    switch(section) {
      case 0: return tr("Point 1");
      case 1: return tr("Point 2");
      case 2: return tr("Measured (m)");
      case 3: return tr("Computed (m)");
      default: break;
    }
  }
  return QVariant();
}

Qt::ItemFlags DistanceItem::flags(const QModelIndex& index) const
{
  TRACE;
  if(index.column()==3) {
    return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
  } else {
    return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
  }
}

QString DistanceItem::nextPointName(const QString& n)
{
  TRACE;
  int i=_pointNames->indexOf(n);
  if(i>-1) {
    i++;
    if(i>=_pointNames->count()) {
      i=0;
    }
    return _pointNames->at(i);
  } else {
    return n;
  }
}

void DistanceItem::add()
{
  TRACE;
  int n=_distances.count();
  beginInsertRows(QModelIndex(), n, n);
  if(n==0) {
    if(_pointNames->count()>=2) {
      _distances.append(Distance(_pointNames->at(0), _pointNames->at(1), 0.0));
    } else {
      _distances.append(Distance());
    }
  } else if(n==1 || _distances.at(n-1).node1()==_distances.at(n-2).node1()) {
    const Distance& d=_distances.last();
    _distances.append(Distance(d.node1(), nextPointName(d.node2()), d.measured()));
  } else if(_distances.at(n-1).node1()==_distances.at(n-2).node2()) {
    const Distance& d=_distances.last();
    _distances.append(Distance(d.node2(), nextPointName(d.node2()), d.measured()));
  } else if(n>=_pointNames->count()-1 && _distances.at(n-1).node2()==nextPointName(_distances.at(n-1).node1())) {
    const Distance& d=_distances.last();
    _distances.append(Distance(d.node2(), nextPointName(d.node2()), d.measured()));
  } else {
    const Distance& d=_distances.last();
    _distances.append(Distance(d));
  }
  endInsertRows();
}

void DistanceItem::remove(int index)
{
  TRACE;
  beginRemoveRows(QModelIndex(), index, index);
  _distances.removeAt(index);
  endRemoveRows();
}

bool DistanceItem::load(const QString& fileName)
{
  QFile f(fileName);
  if(!f.open(QIODevice::ReadOnly)) {
    Message::warning(MSG_ID, tr("Loading distances"), tr("Cannot open file %1 for reading").arg(fileName));
    return false;
  }
  QTextStream s(&f);
  while(!s.atEnd()) {
    QString line=s.readLine();
    Distance d;
    if(d.fromString(StringSection(line))) {
      int n=_distances.count();
      beginInsertRows(QModelIndex(), n, n);
      _distances.append(d);
      _pointNames->insert(d.node1());
      _pointNames->insert(d.node2());
      endInsertRows();
    }
  }
  return true;
}

bool DistanceItem::save(const QString& fileName) const
{
  QFile f(fileName);
  if(!f.open(QIODevice::WriteOnly)) {
    Message::warning(MSG_ID, tr("Saving distances"), tr("Cannot open file %1 for writing").arg(fileName));
    return false;
  }
  QTextStream s(&f);
  for(QList<Distance>::const_iterator it=_distances.begin(); it!=_distances.end(); it++) {
    s << it->toString(20, 'f') << endl;
  }
  return true;
}

