/***************************************************************************
**
**  This file is part of GeopsyCore.
**
**  GeopsyCore 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.
**
**  GeopsyCore 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: 2018-11-06
**  Copyright: 2018-2019
**    Marc Wathelet (ISTerre, Grenoble, France)
**
***************************************************************************/

#include "SeismicEvent.h"

namespace GeopsyCore {

  const QString SeismicEvent::xmlSeismicEventTag="SeismicEvent";

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

    Full description of class still missing
  */

  /*!
    Description of constructor still missing
  */
  SeismicEvent::SeismicEvent()
    : _time(QDate(2000, 1, 1), 0.0, 0.0)
  {
    TRACE;
    _type=Hammer;
    _force=Point(0.0, 0.0, -1.0);
    _lock=0;
  }

  SeismicEvent::SeismicEvent(const SeismicEvent& o)
  {
    TRACE;
    _position=o._position;
    _utmZone=o._utmZone;
    _time=o._time;
    _type=o._type;
    _force=o._force;
    _lock=0;
  }

  SeismicEvent::~SeismicEvent()
  {
    ASSERT(_lock==0);
  }

  void SeismicEvent::operator=(const SeismicEvent& o)
  {
    TRACE;
    _position=o._position;
    _utmZone=o._utmZone;
    _time=o._time;
    _type=o._type;
    _force=o._force;
  }

  bool SeismicEvent::operator==(const SeismicEvent& o) const
  {
    return _position==o._position &&
           _utmZone==o._utmZone &&
           _time==o._time &&
           _type==o._type &&
           _force==o._force;
  }

  bool SeismicEvent::isSamePosition(const SeismicEvent& o) const
  {
    return _position==o._position &&
           _utmZone==o._utmZone;
  }

  QString SeismicEvent::name(int posPrec, int timePrec) const
  {
    static const QString format(tr("(%1) @ %2"));
    return format
        .arg(_position.toString(posPrec, 'f'))
        .arg(_time.toString("hh:mm:ssz", timePrec));
  }

  QStringList SeismicEvent::userTypes()
  {
    QStringList l;
    l << tr("Hammer")
      << tr("Explosion")
      << tr("WeightDrop")
      << tr("Steps")
      << tr("Earthquake");
    std::sort(l.begin(), l.end());
    return l;
  }

  QString SeismicEvent::userType(Type t)
  {
    TRACE;
    switch(t) {
    case Hammer:
      break;
    case Explosion:
      return tr("Explosion");
    case WeightDrop:
      return tr("WeightDrop");
    case Steps:
      return tr("Steps");
    case Earthquake:
      return tr("Earthquake");
    }
    return tr("Hammer");
  }

  SeismicEvent::Type SeismicEvent::userType(QString t, bool * ok)
  {
    TRACE;
    t=t.toLower();
    if(t==tr("hammer")) {
    } else if(t==tr("explosion")) {
      return Explosion;
    } else if(t==tr("weightdrop")) {
      return WeightDrop;
    } else if(t==tr("steps")) {
      return Steps;
    } else if(t==tr("earthquake")) {
      return Earthquake;
    } else if(ok) {
      *ok=false;
    }
    return Hammer;
  }

  QString SeismicEvent::type(Type t)
  {
    TRACE;
    switch(t) {
    case Hammer:
      break;
    case Explosion:
      return "Explosion";
    case WeightDrop:
      return "WeightDrop";
    case Steps:
      return "Steps";
    case Earthquake:
      return "Earthquake";
    }
    return "Hammer";
  }

  SeismicEvent::Type SeismicEvent::type(QString t, bool * ok)
  {
    TRACE;
    if(t.count()>2) {
      t=t.toLower();
      switch(t.at(2).unicode()) {
      case 'm':
        if(t=="hammer") {
          return Hammer;
        }
        break;
      case 'p':
        if(t=="explosion") {
          return Explosion;
        }
        break;
      case 'i':
        if(t=="weightdrop") {
          return WeightDrop;
        }
        break;
      case 'e':
        if(t=="steps") {
          return Steps;
        }
        break;
      case 'r':
        if(t=="earthquake") {
          return Earthquake;
        }
        break;
      default:
        break;
      }
    }
    if(ok) {
      *ok=false;
    }
    return Hammer;
  }

  void SeismicEvent::xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const
  {
    TRACE;
    Q_UNUSED(context)
    writeProperty(s, "Position", _position.toString(15));
    writeProperty(s, "UtmZone", _utmZone.toString());
    writeProperty(s, "Time", _time.toString(DateTime::defaultFormat, 15));
    writeProperty(s, "Type", type(_type));
    writeProperty(s, "Force", _force.toString(15));
  }

  XMLMember SeismicEvent::xml_member(XML_MEMBER_ARGS)
  {
    Q_UNUSED(attributes)
    Q_UNUSED(context)
    if(tag.size()>2) {
      switch (tag[2].unicode()) {
      case 's':
        if(tag=="Position") return XMLMember(0);
        break;
      case 'm':
        if(tag=="Time") return XMLMember(1);
        else if(tag=="UtmZone") return XMLMember(4);
        break;
      case 'p':
        if(tag=="Type") return XMLMember(2);
        break;
      case 'r':
        if(tag=="Force") return XMLMember(3);
        break;
      default:
        break;
      }
    }
    return XMLMember(XMLMember::Unknown);
  }

  bool SeismicEvent::xml_setProperty(XML_SETPROPERTY_ARGS)
  {
    Q_UNUSED(context)
    Q_UNUSED(tag)
    Q_UNUSED(attributes)
    switch (memberID) {
    case 0:
      return _position.fromString(content.toString());
    case 1:
      return _time.fromString(content.toString(), DateTime::defaultFormat);
    case 2: {
        bool ok=true;
        Type t=type(content.toString(), &ok);
        if(ok) {
          _type=t;
          return true;
        } else {
          return false;
        }
      }
    case 3:
      return _force.fromString(content.toString());
    case 4:
      _utmZone.fromString(content.toString());
      return true;
    default:
      return false;
    }
  }

  bool SeismicEvent::lessThan(const SeismicEvent * e1, const SeismicEvent * e2)
  {
    if(e1->time()<e2->time()) {
      return true;
    } else if(e1->time()==e2->time()) {
      return e1->position()<e2->position();
    } else {
      return false;
    }
  }

} // namespace GeopsyCore

