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

#include "Complex.h"
#include "StringSection.h"
#include "MemoryChecker.h"

namespace QGpCoreTools {

const Complex Complex::null;

/*!
  \class Complex

  Implementation of the complex arithmetics
  
  A useful web site for function of complex numbers is
  http://staff.jccc.net/swilson/mathtopics/complex/functionsofi.htm

  // Get SSE/AVX flags available for compiler
  gcc -march=corei7-avx -dM -E - < /dev/null | egrep "SSE|AVX" | sort

  2017-05-19: comparison between glibc-2.23 and this implementation,
              the multiplication is twice faster with this vectorized
              implementation.
*/

QString Complex::toString(char format, int precision) const
{
  TRACE;
  QString str;
  if(_data.values.re==0.0) {
    if(_data.values.im==0.0) {
      str+=QString::number(_data.values.re, format, precision);
    } else {
      str+=QString::number(_data.values.im, format, precision);
      str+="i";
    }
  } else {
    str+=QString::number(_data.values.re, format, precision);
    if(_data.values.im<0.0) {
      str+=QString::number(_data.values.im, format, precision);
      str+="i";
    } else if(_data.values.im>0.0) {
      str+="+";
      str+=QString::number(_data.values.im, format, precision);
      str+="i";
    }
  }
  return str;
}

bool Complex::fromString(const StringSection& str)
{
  TRACE;
  const QChar * ptr=nullptr;
  StringSection f;
  f=str.nextField(ptr," +");
  if(f.isValid()) _data.values.re=f.toDouble(); else return false;
  f=str.nextField(ptr, " i");
  if(f.isValid()) _data.values.im=f.toDouble(); else return false;
  return true;
}

QTextStream& operator<< (QTextStream& s, const Complex& c)
{
  TRACE;
  s.setRealNumberNotation(QTextStream::SmartNotation);
  s.setRealNumberPrecision(20);
  s << c.re() << " " << c.im();
  return s;
}

QTextStream& operator>> (QTextStream& s, Complex& c)
{
  TRACE;
  double re, im;
  s >> re >> im;
  c.set(re, im);
  return s;
}

QDataStream& operator<< (QDataStream& s, const Complex& c)
{
  TRACE;
  s << c.re() << c.im();
  return s;
}

QDataStream& operator>> (QDataStream& s, Complex& c)
{
  TRACE;
  double re, im;
  s >> re >> im;
  c.set(re, im);
  return s;
}

} // namespace QGpCoreTools
