/***************************************************************************
 *   Copyright (C) 2004 by Armando Navarro Vázquez                         *
 *   qoajnv@usc.es                                                         *
 *                                                                         *
 *   This program 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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program 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 this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "uvspectrum.h"

#include <algorithm>
#include <fstream>
#include <iostream>
#include "irspectrum.h"

#ifndef M_PI
# define M_PI       3.14159265358979323846  // matches value in gcc v2 math.h
#endif

const int NPOINTS=8192;
const std::string jcampversion="4.24";

UVSpectrum::UVSpectrum() : m_spectrumtype(UV) , m_linewidth(20.0)
{
  m_title= "gaussian spectrum";

}

UVSpectrum::~UVSpectrum()
{}

void UVSpectrum::SetLines(std::vector<spectralline>& v,double scale/*=1.0*/)
{
  m_lines.resize(v.size());
  m_lines=v;
  std::vector<spectralline>::iterator fit;

  for(fit=m_lines.begin();fit!=m_lines.end();fit++)
  {
    fit->x*=scale;
  }
  m_sinusoid.clear();
  m_sinusoid.resize(v.size());
  std::vector<CSinusoid>::iterator it;
  std::vector<spectralline>::iterator vit;
  for(it=m_sinusoid.begin(),vit=m_lines.begin();it!=m_sinusoid.end();it++,vit++)
  {
    switch(m_spectrumtype)
    {
    case ECD:
      it->m_zamplitude=it->m_flamplitude=vit->y1; //proportional to rotatory strength
      break;
    case UV:
      it->m_zamplitude=it->m_flamplitude=vit->y0;  //proportional to oscillator strength
    }
    it->m_fldecay=0.5f;
    it->m_flfrequency=vit->x;
    it->m_flphase=0.0f;
    it->m_flt1=0.0f;
    it->m_J=0.0f;
    it->m_multiplicity=1;
    it->InitData(NPOINTS);
  }


}
void UVSpectrum::SetType( SpectrumType type )
{
  m_spectrumtype=type;
  SetLines(m_lines);
}

void UVSpectrum::CalculateSpectrum()
{
  m_data.clear();
  m_data.grow(NPOINTS);

  float max=m_max;
  float min=m_min;
  float width= (max -min);
  std::cout << "width" << width;

  float O1=0.5f*(max-min)+min;
  std::cout << "O1" << O1 << std::endl;
  std::cout << "min=" << m_min << std::endl;
  std::cout << "max=" << m_max << std::endl;
  float fdelta_t=1/width;

  //iterate now through sinusoids
  std::vector<CSinusoid>::iterator it;
  for(it=m_sinusoid.begin();it!=m_sinusoid.end();it++)
  {
    float f=it->m_flfrequency;
    if( m_min < f && m_max > f )
    {
      float freq=it->m_flfrequency-O1;
      float decay=it->m_fldecay;
      float phase=it->m_flphase;
      float angular=2*M_PI*freq;
      float m;

      //gaussian lines
      for (size_t k=0; k<m_data.size(); k++)
      {
        m= k*fdelta_t;
        it->m_fdata[k]=expi<double>(angular*m)*exp(-(m*m)/decay);
        //mult_realfcomplex(exp(-m/decay),expi(angular*m));

      }
      float amplitude=it->m_flamplitude;
      it->m_fdata*=amplitude;
      m_data+=(it->m_fdata);
    }
  }
  //OK we have spectrum in time domain, lets do quadrature and ft
  m_data[0]*=0.5f;
  m_data.quadrature();
  m_data.fft(1);
}

bool UVSpectrum::WriteJCampDX()
{
  std::cout << "min=" << m_min << " max= " << m_max;
  std::ofstream output(m_file.c_str());

  if(!output)
    return false;
  output <<  "##TITLE= " << m_title.c_str() << std::endl;
  output <<  "##JCAMP-DX= " << jcampversion.c_str() << std::endl;
  switch(m_spectrumtype)
  {
  case UV:
    output << "##DATA TYPE= " << "UV SPECTRUM" << std::endl;
    break;
  case ECD:
    output << "##DATA TYPE= " << "ECD SPECTRUM" << std::endl;
    break;
  }
  output << "##ORIGIN= " << "Qryomol converter 0.1" << std::endl;
  output << "##XUNITS= NM" << std::endl;
  output << "##YUNITS= ABSORBANCE" << std::endl;
  output << "##XFACTOR= " << 1.0f << std::endl;
  output << "##YFACTOR= " << 0.01f << std::endl;  //0.01 f should be appropiate
  output << "##FIRSTX= " <<  m_min << std::endl;
  output << "##LASTX= " << m_max << std::endl;
  output << "##NPOINTS= " << NPOINTS << std::endl;

  //Put now the data
  output << "##XYDATA= (X++(Y..Y))" << std::endl;
  float increment=(m_max-m_min)/(NPOINTS-1);
  for (size_t  i=0; i< m_data.size();i++)
  {
    output << m_min+i*increment << "   " << m_data[NPOINTS-1-i].real() << std::endl;

  }

  output << "##END= " << std::endl;

  return true;
}

void UVSpectrum::SetFile(const char* file)
{
  m_file=file;
}


void UVSpectrum::SetLineWidth(float lw)
{
  float t2=1/(M_PI*lw);
  for(std::vector<CSinusoid>::iterator it=m_sinusoid.begin();it!=m_sinusoid.end();++it)
  {

    it->m_fldecay=t2;
  }

}

void UVSpectrum::SetAutoLimits()
{
  //Get the limits of the spectrum
  std::vector<spectralline>::iterator fit;
  float min=1e10f;
  float max=-1e10f;
  for(fit=m_lines.begin();fit!=m_lines.end();fit++)
  {
    if(fit->x >max)
      max=fit->x;
    if(fit->x < min)
      min=fit->x;
  }

  min*=0.9f;
  max*=1.1f;

  m_min=min;
  m_max=max;
}

