/***************************************************************************
**
**  This file is part of QGpCompatibility.
**
**  QGpCompatibility 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.
**
**  QGpCompatibility 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: 2004-10-21
**  Copyright: 2004-2019
**    Marc Wathelet
**    Marc Wathelet (ULg, Liège, Belgium)
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include <math.h>

#include <QGpCoreTools.h>
#include "CompatModalFrequency.h"

namespace QGpCompatibility {

/*!
  \class CompatModalFrequency CompatModalFrequency.h
  \brief Vector of double to store frequency samples and abstract modal object
  
*/

const QString CompatModalFrequency::xmlModalFrequencyTag="ModalFrequency";

CompatModalFrequency::CompatModalFrequency()
{
  TRACE;
  _nRayleighModes=0;
}

void CompatModalFrequency::operator=(CompatModalFrequency& o)
{
  TRACE;
  QVector<double>::operator=(o);
  _nRayleighModes=o._nRayleighModes;
}

void CompatModalFrequency::setFrequencies(QVector<double>& values)
{
  TRACE;
  if(nOmegas()==(int)values.size()) {
    for(int i=0;i<nOmegas();i++) omega(i)=2*M_PI*values[i];
  }
  else App::log(tr("Number of frequency do not match in %1, at line %2\n").arg(__FILE__).arg(__LINE__) );
  ASSERT (at(0)<at(nOmegas()-1));
}

/*!
  \fn CompatModalFrequency::addRayleighModes()
  if there are Love modes, the task is a bit more complex...
*/

/*!
  Because Love modes are located at the end, there is nothing else to do than adding new modes
*/
void CompatModalFrequency::addLoveModes(int nNewModes)
{
  TRACE;
  if(nNewModes==0) return;
  setNModes(nModes()+nNewModes);
}

/*!
  Make sure that all samples of samples are included in this sample set. If a sample already exists nothing is
  performed. If not, an invalid sample is added.
*/
void CompatModalFrequency::insertOmegas(const CompatModalFrequency& o)
{
  TRACE;
  int nf2Add=o.nOmegas();
  int i=0;
  for(int i2Add=0;i2Add<nf2Add;i2Add++) {
    double f2Add=o.omega(i2Add);
    while(i<nOmegas() && omega(i)<f2Add) i++;
    if(i>=nOmegas()) {
      append(f2Add);
      addInvalid();
    } else if(omega(i)>f2Add) {
      insert(i,f2Add);
      insertInvalidAt(i);
      i++;
    }
  }
}

bool CompatModalFrequency::isSameOmegas(const CompatModalFrequency& o) const
{
  TRACE;
  if(nOmegas()!=o.nOmegas()) return false;
  for(int i=0;i<nOmegas();i++) {
    if(omega(i)!=o.omega(i)) return false;
  }
  return true;
}

QVector<double> * CompatModalFrequency::frequencies() const
{
  QVector<double> * list=new QVector<double>;
  list->reserve(nOmegas());
  double fac=0.5/M_PI;
  for(int i=0;i<nOmegas();i++)
    list->push_back(omega(i)*fac);
  return list;
}

QDataStream& operator<<(QDataStream& s, const CompatModalFrequency& p)
{
  TRACE;
  s << p.nRayleighModes();
  int nf=p.nOmegas();
  s << nf;
  for(int i=0;i<nf;i++) s << p.omega(i);
  return s;
}

QDataStream& operator>>(QDataStream& s, CompatModalFrequency& p)
{
  TRACE;
  int nRm;
  s >> nRm;
  p.setNRayleighModes(nRm);
  int nf;
  s >> nf;
  p.setNOmegas(nf);
  for(int i=0;i<nf;i++) s >> p.omega(i);
  return s;
}

void CompatModalFrequency::xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const
{
  TRACE;
  Q_UNUSED(context)
  writeProperty(s, "nRayleighModes",_nRayleighModes);
  QString tmp;
  tmp+=s.indent();
  tmp+="<values>\n";
  int n=count();
  for(int i=0;i<n;i++) {
    tmp+=s.indent();
    tmp+="    ";
    tmp+=QString::number(at(i));
    tmp+="\n";
  }
  tmp+=s.indent();
  tmp+="</values>";
  s << tmp << endl;
}

XMLMember CompatModalFrequency::xml_member(XML_MEMBER_ARGS)
{
  TRACE;
  Q_UNUSED(attributes)
  Q_UNUSED(context)
  if(tag=="values") return XMLMember(0);
  else if(tag=="val") return XMLMember(1);
  else if(tag=="DoubleVector") {
    App::log(tr("## WARNING ## : old style for list of frequencies, replace\n"
                "<DoubleVector>\n"
                "   <val>f1</val>\n"
                "   <val>f2</val>\n"
                "   ...\n"
                " </DoubleVector>\n"
                "by\n"
                "<val>f1</val>\n"
                "<val>f2</val>\n"
                "  ...\n"));
    return XMLMember(XMLMember::Unknown);
  } else if(tag=="nRayleighModes") return XMLMember(2);
  else return XMLMember(XMLMember::Unknown);
}

bool CompatModalFrequency::xml_setProperty(XML_SETPROPERTY_ARGS)
{
  TRACE;
  Q_UNUSED(tag)
  Q_UNUSED(attributes)
  Q_UNUSED(context)
  switch (memberID) {
  case 0: {
      const QChar * ptr=0;
      static const QString sep=" \n\t\r";
      StringSection f;
      clear();
      while(true) {
        f=content.nextField(ptr, sep, true);
        if(f.isValid()) append(f.toDouble()); else break;
      }
    }
    return true;
  case 1:
    append(content.toDouble());
    return true;
  case 2:
    _nRayleighModes=content.toInt();
    return true;
  default:
    return false;
  }
}

} // namespace QGpCompatibility
