/***************************************************************************
**
**  This file is part of geopsy.
**
**  geopsy 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.
**
**  geopsy 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: 2019-08-30
**  Copyright: 2019
**    Marc Wathelet (ISTerre, Grenoble, France)
**
***************************************************************************/

#include <GeopsyGui.h>

#include "Engine.h"
#include "SeismicEventView.h"
#include "SeismicEventDelegate.h"

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

  Full description of class still missing
*/

/*!
  Description of constructor still missing
*/
SeismicEventView::SeismicEventView(QWidget * parent)
  : QTableView(parent)
{
  TRACE;

  _menu=new QMenu(this);
  setContextMenuPolicy(Qt::DefaultContextMenu);

  SeismicEventDelegate * delegate=new SeismicEventDelegate(this);
  setItemDelegate(delegate);
  connect(delegate, SIGNAL(dataChanged()), this, SLOT(applyAllSelected()));

  SeismicEventItem * model=new SeismicEventItem(this);
  model->setDatabase(Engine::instance()->database(this));
  setModel(model);
  setSelectionBehavior(QAbstractItemView::SelectRows);
  setSelectionMode(QAbstractItemView::ExtendedSelection);
  setEditTriggers(QAbstractItemView::DoubleClicked);
  setSortingEnabled(true);
}

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

inline SeismicEventItem * SeismicEventView::model() const
{
  return static_cast<SeismicEventItem *>(QTableView::model());
}

bool SeismicEventView::event(QEvent *event)
{
  TRACE;
  if(event->type()==QEvent::Polish) {
    resizeColumnsToContents();
    // Not OK in the constructor because object name not yet set
    Settings::columnWidth(this, "SeismicEventView");
  }
  return QTableView::event(event);
}

void SeismicEventView::applyAllSelected()
{
  TRACE;
  QAbstractItemModel& m=*model();
  QModelIndex curIndex=currentIndex();
  QModelIndexList l=selectionModel()->selectedRows();
  if(l.count()>1) {
    QVariant val=m.data(curIndex);
    QModelIndex index;
    if(curIndex.column()>=5) { // Selecting all with same time and position
                               // makes this action crashing
      foreach(index, l) {
        m.setData(m.index(index.row(), curIndex.column()), val);
      }
    }
  }
}

void SeismicEventView::addActions()
{
  TRACE;
}

QList<SeismicEvent *> SeismicEventView::getSelection() const
{
  TRACE;
  QList<SeismicEvent *> sel;
  int n=model()->rowCount(QModelIndex());
  for(int i=0; i<n; i++) {
    QModelIndex m=model()->index(i, 0, QModelIndex());
    if(selectionModel()->isSelected(m)) {
      sel.append(model()->at(i));
    }
  }
  return sel;
}

void SeismicEventView::contextMenuEvent(QContextMenuEvent * e)
{
  TRACE;
  _menu->clear();
  QList<SeismicEvent *> sel=getSelection();
  bool hasLockedItems=false;
  for(QList<SeismicEvent *>::iterator it=sel.begin(); it!=sel.end(); it++) {
    if((*it)->isLocked()) {
      hasLockedItems=true;
      break;
    }
  }

  _menu->addAction(tr("Add"), this, SLOT(addEvent()));
  if(!sel.isEmpty() && !hasLockedItems) {
    _menu->addAction(tr("Remove"), this, SLOT(removeEvents()));
  }
  _menu->addSeparator();
  _menu->addAction(tr("Import"), this, SLOT(importEvents()));
  if(!sel.isEmpty()) {
    _menu->addAction(tr("Export"), this, SLOT(exportEvents()));
  }
  _menu->popup(viewport()->mapToGlobal(e->pos()));
}

void SeismicEventView::addEvent()
{
  TRACE;
  int col=0;
  int i=currentIndex().row();
  SeismicEvent e;
  if(i>=0) {
    e=*model()->at(i);
    DateTime t=e.time();
    t.addMinutes(1);
    e.setTime(t);
    Point p=e.position();
    p.setX(p.x()+1.0);
    e.setPosition(p);
    col=currentIndex().column();
  }
  model()->dataBase()->seismicEvents()->add(e);
  i=model()->rowCount(QModelIndex())-1;
  setCurrentIndex(model()->index(i, col));
}

void SeismicEventView::removeEvents()
{
  TRACE;
  QList<SeismicEvent *> toRemove=getSelection();
  SeismicEventTable * events=model()->dataBase()->seismicEvents();
  for(int i=toRemove.count()-1; i>=0; i--) {
    events->remove(*toRemove.at(i));
  }
}

void SeismicEventView::importEvents()
{
  TRACE;
  QString fileName=Message::getOpenFileName(tr("Import seimsic events"),
                                            tr("Seismic events (*.evt)"));
  if(!fileName.isEmpty()) {
    QFile f(fileName);
    if(f.open(QIODevice::ReadOnly)) {
      QTextStream s(&f);
      LineParser lp;
      bool ok=true;
      DateTime time;
      int lineNumber=0;
      SeismicEventTable * events=model()->dataBase()->seismicEvents();
      SeismicEvent event;
      while(!s.atEnd() && ok) {
        QString buf=s.readLine();
        lineNumber++;
        if(!buf.isEmpty() && buf[0]!='#') {
          lp.setString(buf);

          QString timeS=lp.toString(0, ok);
          if(!ok || !time.fromString(timeS, DateTime::defaultFormat)) {
            App::log(tr("Error reading time specification at line %1\n").arg(lineNumber));
            ok=false;
          }
          event.setTime(time);

          QString utmS=lp.toString(1, ok);
          if(!ok) {
            App::log(tr("Error reading utm zone at line %1\n").arg(lineNumber));
          }
          UtmZone utm;
          utm.fromString(utmS);
          event.setUtmZone(utm);

          event.setPosition(Point(lp.toDouble(2, ok), lp.toDouble(3, ok), lp.toDouble(4, ok)));
          if(!ok) {
            App::log(tr("Error reading coordinates at line %1\n").arg(lineNumber));
          }

          QString typeS=lp.toString(5, ok);
          event.setType(SeismicEvent::type(typeS, &ok));
          if(!ok) {
            App::log(tr("Error reading type at line %1\n").arg(lineNumber));
          }

          event.setForce(Point(lp.toDouble(6, ok), lp.toDouble(7, ok), lp.toDouble(8, ok)));
          if(!ok) {
            App::log(tr("Error reading force at line %1\n").arg(lineNumber));
          }
          if(ok) {
            events->add(event);
          }
        }
      }
      if(!ok) {
        Message::warning(MSG_ID, tr("Import seimsic events"),
                         tr("Error reading file '%1'. See log for details.")
                         .arg(fileName));
      }
    }
  }
}

void SeismicEventView::exportEvents()
{
  TRACE;
  QList<SeismicEvent *> toExport=getSelection();
  if(toExport.isEmpty()) {
    return;
  }
  QString fileName=Message::getSaveFileName(tr("Export seismic events"),
                                            tr("Seismic events (*.evt)"));
  if(!fileName.isEmpty()) {
    QFile f(fileName);
    if(f.open(QIODevice::WriteOnly)) {
      QTextStream s(&f);
      int n=toExport.count();
      for(int i=0; i<n; i++) {
        const SeismicEvent * event=toExport.at(i);
        s << event->time().toString(DateTime::defaultFormat) << " "
          << event->utmZone().toString() << " "
          << event->position().toString() << " "
          << SeismicEvent::type(event->type()) << " "
          << event->force().toString() << "\n";
      }
    } else {
      Message::warning(MSG_ID, tr("Export seimsic events"),
                       tr("Error writring to file '%1'.")
                       .arg(fileName));
    }
  }
}

