/***************************************************************************
 *   Copyright (C) 2004 by Armando Navarro-Vazquez                         *
 *   uscqoanv@cesga.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 <fstream>
#include <iostream>

#include <qfileinfo.h>
#include <qdir.h>
#include <qstringlist.h>

#include "brukerparser.h"
#include "nmrfile.h"
#include "tokenizer.h"
#include "spectrum.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "nmrspectrum.h"

// decimation table from //http://www.boc.chem.uu.nl/static/local/prospectnd/dmx_digital_filters.html
const float dspfvs10[21]=
  {
    44.75, 33.5, 66.625, 59.0833f,68.5625f,
    60.3750f, 69.5313f, 61.0208f, 70.0156f, 61.3438f, 70.2578f, 61.5052f,
    70.3789f, 61.5859f, 70.4395f, 61.6263f, 70.4697f, 61.6465f, 70.4849f,
    61.6566f,70.4924f
  };

const float dspfvs11[21]=
  {
    46.00f, 36.5f, 48.0f, 50.1667f, 53.25f, 69.5f,
    72.25f, 70.1667f, 72.75f, 70.5f, 73.0f, 70.6667f, 72.5f, 71.3333f,
    72.25f, 71.6667f, 72.125f, 71.8333f, 72.0625f, 71.9167f,72.0313f
  };

const float dspfvs12[13]=
  {
    46.311f, 36.53f, 47.87f, 50.229f, 53.289f,69.551f,
    71.6f, 70.184f, 72.138f, 70.528f, 72.348f, 70.7f, 72.524f
  };

BrukerParser::BrukerParser(QString& file)
    : SpectrumParser(file)
{
  //Build decimation table
  m_decim[0]=2;
  for(int i=1;i<21;i++)
  {
    m_decim[i]= m_decim[i-1]+(1<<((i-1)/2));
    //std::cout << decim[i]<<std::endl;
  }
}


BrukerParser::~BrukerParser()
{}

Spectrum* BrukerParser::ParseFile()
{
  NMRSpectrum* spectrum= new NMRSpectrum();
  QFileInfo finfo(m_file);
  if( !finfo.isReadable() ) return false;

  std::ifstream re;
  std::ifstream im;
  std::ifstream sfid;
  std::ifstream acqus;
  QString root=m_file;
  NMRFile::NMRFileType ftype;
  if( finfo.isDir() )
  {
    QStringList flist=finfo.dir(true).entryList();
    QStringList::Iterator it;
    for(it=flist.begin();it!=flist.end();it++)
    {
      if( (*it) == "fid" || (*it) == "1i" || (*it) == "1r" )
        break;
    }



    if( (*it) == "fid" ) ftype=NMRFile::BrukerFID;
    else if ( (*it) == "1i" || (*it) == "1r" )
    {
      ftype=NMRFile::BrukerSpectrum;
      int k=root.find("/pdata");
      root.setLength(k);
    }
    else return 0; //oops, some problem

  }
  else if( finfo.isFile() )
  {
    if ( finfo.fileName() == "1i" || finfo.fileName() == "1r" )
    {
      int k=root.find("/pdata");
      root.setLength(k);
      ftype=NMRFile::BrukerSpectrum;
      spectrum->SetDataType(NMRSpectrum::SPECTRUM);
    }
    else if(  finfo.fileName() == "fid" )
    {
      int k=root.find("/fid");
      root.setLength(k);
      ftype=NMRFile::BrukerFID;
      spectrum->SetDataType(NMRSpectrum::FID);
    }
    else return 0;


  }
  else return 0;

  //Open now the streams
  QString file;
  switch ( ftype  )
  {
  case NMRFile::BrukerSpectrum:
    file=root+"/pdata/1/1r";
    re.open(file.toLatin1());
    file=root+"/pdata/1/1i";
    im.open(file.toLatin1());
    break;
  case NMRFile::BrukerFID:
    file=root+"/fid";
    sfid.open(file.toLatin1());
    break;
  default:
    break;

  }
  file=root+"/acqus";
  acqus.open(file.toLatin1());

  int npoints;

  //fid.SetType(eBruker);
  std::string line;
  int dec,dsp;
  bool bByteSwap;

  spectrum->SetSequential(false); //complex spectra by default
  //First count the atoms
  while(std::getline(acqus,line))
  {
    StringTokenizer token(line," =<>"); //in some bruker files appears as "##PROPERTY=value" without space
    if(token.size())
    {
      std::string uctoken=token[0];
      StringTokenizer::toupper(uctoken);

      if(uctoken=="##$AQ_MOD")
      {
        if(atoi(token[1].c_str())==2)
          spectrum->SetSequential(true);
      }
      if(uctoken=="##$BYTORDA")
        bByteSwap=(bool)atoi(token[1].c_str());
      if(uctoken=="##$DECIM")
        dec=atoi(token[1].c_str());
      if(uctoken=="##$DSPFVS")
        dsp=atoi(token[1].c_str());
      if(uctoken=="##$TD")
        npoints=atoi(token[1].c_str());
      if(uctoken=="##$O1")
        spectrum->SetO1(atof(token[1].c_str()));
      if(uctoken=="##$SW_H")
        spectrum->SetSW(atof(token[1].c_str()));
      if(uctoken=="##$SFO1")
        spectrum->SetField(atof(token[1].c_str()));
      if(uctoken=="##NUC1")
        spectrum->SetNucleus(token[1].c_str());
    }
  }
  npoints/=2;
  //fid.CalculateAQ();
  int nTemp[2*npoints];
  short stemp[2*npoints];
  fidarray& data=spectrum->Data();
  data.resize(npoints);
  data.resize(npoints);
  // fread (nTemp, sizeof(int), 2*npoints, fid);



  if( ftype== NMRFile::BrukerFID) //fid
  {
    sfid.read((char*)nTemp,2*npoints*4);
    register int i,j;
    float f=GetFilterPoints(dec,dsp);
    int delay=(int)f;






    for (i = 0, j = 0; i < npoints; i++)
    {

      if(bByteSwap)
        ByteSwap<int>(&nTemp[j]);
      data[i].real() =  (float) nTemp[j];
      j++;
      if(bByteSwap)
        ByteSwap<int>(&nTemp[j]);
      data[i].imag() = (float) nTemp[j];

      j++;
    }

    data.shift(delay);
    spectrum->SetDataType(NMRSpectrum::FID);

  }

  if( ftype == NMRFile::BrukerSpectrum)
  {
    re.read((char*)nTemp,npoints*4);
    im.read((char*)&nTemp[npoints],npoints*4);
    for(register int i=0;i<npoints;i++)
    {
      if(bByteSwap)
      {
        ByteSwap<int>(&nTemp[i]);
        ByteSwap<int>(&nTemp[npoints+i]);
      }
      if( i < 10 )
      std::cout << nTemp[i] << std::endl;
      data[i].real()=(float)nTemp[i];

      data[i].imag()=(float)nTemp[npoints+i];

    }

    spectrum->SetDataType(NMRSpectrum::SPECTRUM);

  }

  return spectrum;

}

float BrukerParser::GetFilterPoints(int dec, int dsp)
{

  if ((dec > 1) && (dsp >= 10) && (dsp <= 12))
  {
    short	index;
    const float* f;

    for (index = 0; index < 21; index++)
      if (m_decim[index] == dec)		// looking for the right index
        break;
    switch (dsp)
    {
    case 10: f = dspfvs10;
      break;
    case 11: f = dspfvs11;
      break;
    case 12: f = dspfvs12;
      break;
    }
    if (index < 21)
      return f[index];
    else return 0;
  }
  return 0;

}
