/*! \file
 * implementation functions for class qwavheader
 */

# include <string.h>         // memmove

# include "qwavheader.hh"
# include "qexception.hh"
# include "qmisc.hh"
# include "endian.hh"

#ifdef NLS
  # include <locale.h>
  # include <libintl.h>
  # define _(s) gettext (s)
#else
  # define _(s) (s)
#endif


const u_int32_t qwavheader::HEADERSIZE = sizeof(struct wavheader);


qwavheader::qwavheader (caddr_t p, u_int32_t wavlength) {

  header = new wavheader(p);
  mappedheader = (struct wavheader *)p;

  valid();

  if (wavlength)
    validLength(wavlength);
}

qwavheader::~qwavheader()
{
  delete header;
}

void qwavheader::remap(caddr_t p) {
  mappedheader = (struct wavheader *)p;
  header->headerCopy(p);
}


u_int32_t qwavheader::setSamples(u_int32_t n) {

 // protegir-la d'abusos... 
  header->datalength = n*header->bytespersample;
  header->rifflength = header->datalength+36;

  mappedheader->datalength = htolel(header->datalength);
  mappedheader->rifflength = htolel(header->rifflength);

#ifdef QVERBOSE
  cerr << "sample number set to " << n << endl;
#endif

  return getSamples();
}


u_int32_t qwavheader::addSamples(int increment) {
  
 // protegir-la d'abusos...
  setSamples(getSamples()+increment);

  return getSamples();
}


u_int32_t qwavheader::getSamples() {
  return header->datalength / header->bytespersample;
}


bool qwavheader::compatible (const qwavheader &other) {

  return (header->channels == other.header->channels)  &&
       (header->samplerate == other.header->samplerate);
}


bool qwavheader::valid () {
    
  if (!strcmpn(header->riff,"RIFF",4) ||
      !strcmpn(header->wave,"WAVE",4) ||
      !strcmpn(header->fmt_,"fmt ",4) ||
      !strcmpn(header->data,"data",4) ||
      (header->fmtlength!=16        ) ||
      (header->format!=1            )) {

    throw qexception(__PRETTY_FUNCTION__,_("header format error"));
  }

  if ( (header->channels!=2 && header->channels!=1) ||
       (header->samplerate>48000 || header->samplerate<8000) ||
       (header->bytespersample!=1 &&
        header->bytespersample!=2 &&
        header->bytespersample!=4) )

    throw qexception(__PRETTY_FUNCTION__,_("header value error"));

 // caldria comprovar que bitspersample=bytespersample*channels*8
 // caldria comprovar que bytespersec=bytespersample*samplerate
 
  return true;
}


bool qwavheader::validLength (u_int32_t length) {

  if ((header->datalength != length-44) || (header->rifflength != length-8))
    throw qexception(__PRETTY_FUNCTION__,_("length mismatch"));

  return true;
}


u_int32_t qwavheader::getMsDuration() { 
  return 1000ULL*header->datalength/(header->bytespersample*header->samplerate); 
} 

u_int32_t qwavheader::getSampleRate() { return header->samplerate; } 
u_int32_t qwavheader::getChannels() { return header->channels; } 


u_int32_t qwavheader::getOffset (qvf &vf) { 

  return getSample(vf)*getBytesPerSample()+HEADERSIZE;
}


u_int32_t qwavheader::getOffset (u_int32_t sample) { 
 // assegurar que sample in (1..getSamples())
  return HEADERSIZE+(sample-1)*header->bytespersample; 
}


u_int32_t qwavheader::getSample (qvf &vf) { 

  u_int32_t sample;

  switch (vf.getFormat()) {

    case qvf::BYTES: sample = vf.getValue()/getBytesPerSample(); break;
    case qvf::KBYTES: sample = (vf.getValue()*1024)/getBytesPerSample(); break;
    case qvf::MBYTES: sample = (vf.getValue()*1024*1024)/getBytesPerSample(); break;

    case qvf::MILLISECONDS: sample = (1ULL*vf.getValue()*getSampleRate())/1000; break;
    case qvf::SECONDS: sample = vf.getValue()*getSampleRate(); break;
    case qvf::MINUTES: sample = 60*vf.getValue()*getSampleRate(); break;

    case qvf::SPECIFIC: sample = vf.getValue(); break;

    default:
      throw qexception(__PRETTY_FUNCTION__,
              string(_("format not recognized: "))+char2string(vf.getFormat()));
  }

  if (sample<1 || sample>getSamples())
    throw qexception(__PRETTY_FUNCTION__,string(_("sample out of range: "))+uint2string(sample));
  // i si poséssim el qvf, millor

  return sample;
}

u_int32_t qwavheader::getBitsPerSample() { return header->bitspersample; }
u_int32_t qwavheader::getBytesPerSample() { return header->bytespersample; }
bool qwavheader::getStereo() { return header->channels==2; }

void qwavheader::wavheader::headerCopy(caddr_t p)
{
  memmove(this, p, HEADERSIZE);

#if __BYTE_ORDER != __LITTLE_ENDIAN
  rifflength = letohl(rifflength);
  fmtlength = letohl(fmtlength);
  format = letohs(format);
  channels = letohs(channels);
  samplerate = letohl(samplerate);
  bytespersec = letohl(bytespersec);
  bytespersample = letohs(bytespersample);
  bitspersample = letohs(bitspersample);
  datalength = letohl(datalength);
#endif

}
