/***************************************************************************
                          ESAC.h  -  description
                             -------------------
    begin                : Sam Nov 22 2003
    copyright            : (C) 2003 by klaus frieler
    email                : kgf@omniversum.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/
#ifndef _LIBMELODY_ESAC_H
#define _LIBMELODY_ESAC_H

#include "types.h"
#include "Melody.h"
#include "Vector.h"

enum ToneMark{OUT = 0, OCT, DIG, ACC, PRO, CARET, TUPSTART, TUPEND };

class EsACDecoder{
public:
   
public:
   EsACDecoder(const string& data): m_sData(data), m_melody(0), m_tempo(500), m_cut(0.0), m_iLengthBase(1){}
   EsACDecoder():m_sData(""), m_melody(0), m_tempo(500), m_cut(0.0), m_iPhraseIdx(0), m_iLengthBase(1){}
   ~EsACDecoder(){}

   void        setData(const string& data){ m_sData = data;}
   bool        parse();
   Melody*     getMelody(){ return m_melody;}

   bool        parseMelody();   
   Vector      getSegments();
   void        setTempo(double tempo){ m_tempo = tempo;}
   void        setCut(double cut){ m_cut = cut;}
   void        setPhraseIndex(uint idx){ m_iPhraseIdx = idx;}
   
   string      getErrText(){return m_sErrText;}

protected:
   string      m_sData;
   string      m_sCollection;
   string      m_sTitle;
   string      m_sRegion;
   string      m_sSource;
   string      m_sKeyData;
   string      m_sID;
   string      m_sKey;
   vector<string> m_signatures;
   uint        m_nUnit;
   string      m_sMel;
   string      m_sFunction;
   Melody*     m_melody;
   double      m_tempo;
   double      m_cut;
   uint        m_iPhraseIdx;
   string      m_sErrText;
   Vector      m_segments;
   uint        m_iLengthBase;

   Signature   getSignature(uint idx);
   void        createCommonSignature();
 
   string      token(const string& str, uint num, const char delim);
   char        getNextNonWS(const string& str, uint idx = 0)const;
   bool        hasTriplets(const string &str)const { 
      return (str.find( '(' ) != string::npos) || (str.find(')') != string::npos); 
   }
   bool        hasQuintuplets(const string &str)const { 
      return (str.find( '<' ) != string::npos) || (str.find('>') != string::npos); 
   }
   bool        hasSeptlets(const string &str)const { 
      return (str.find( '{' ) != string::npos) || (str.find('}') != string::npos); 
   }
   string      trimLeft(const string& str)const;
   string      trimRight(const string& str)const;
   string      getVal(const char *key);
   double      getLength(uint length);
   uint        getTicks(uint length);

   uint        getMIDIPitch(uint digit, uint sign, int octave);
   Tone        createTone(uint digit, int sign, int octave, uint length);
   void        dumpMelody();
   double      guessTempo(double timbase = 500.);
   uint        getBarLength();
   void        setErrText(const char* txt){ m_sErrText = txt;}

   bool        isDigit(char c) const      { return ((c>='0' && c<='8')) ? true: false;}
   bool        isOctaver(char c)const     { return (c=='+' || c=='-') ? true: false;}
   bool        isAccidential(char c)const        { return (c=='b' || c<='#') ? true: false;}
   bool        isProlongation(char c)const{ return (c=='_' || c=='.') ? true: false;}
   bool        isEnd(char c)const         { return (c=='/') ? true: false;}
   bool        isWS(char c)const          { return (c==' ' || c=='\t' || c=='\n' || c== '\r') ? true: false;}
   bool        isBarSep(char c)const          { return (c==' '|| c == '|') ? true: false;}
   bool        isCR(char c)const          { return (c=='\n' || c== '\r') ? true: false;}
   bool        isCaret(char c)const       { return (c=='^');}
   bool        isTripletStart(char c)const { return (c=='(');}
   bool        isTripletEnd(char c)const   { return (c==')');}
   bool        isQuintupletStart(char c)const { return (c=='<');}
   bool        isQuintupletEnd(char c)const   { return (c=='>');}
   bool        isSeptletStart(char c)const { return (c=='{');}
   bool        isSepletEnd(char c)const   { return (c=='}');}
   bool        isUndefined(char c)const   { return  c == '?';}
   bool        isTupletStart(char c)const   { return (c=='(' || c=='<' || c=='{');}
   bool        isTupletEnd(char c)const   { return (c==')' || c=='>' || c=='}');}
};

class EsACEncoder{
public:
   static string begin, end, rest, flat, sharp, prolong_under, prolong_dot;
   static string caret, undefined, space, nl, octup, octdown, header, footer;
   static const char *heptatonic[12];
   
public:
   EsACEncoder(const Melody& melody, const string& name):m_mel(melody), m_sName(name), m_sErrText("")
   {}
   ~EsACEncoder(){}
   
   string   encode();
   string   getErrText() const { return m_sErrText;}
   string   getKeyEntry() const;
   string   getMelEntry();
   void     setBoundaries(const Vector &boundaries){m_boundaries = boundaries;}
protected:
   Melody   m_mel;
   string   m_sName;
   string   m_sErrText;
   Vector   m_boundaries;
   string   getEsACToneByMIDIPitch(const int pitch, const int key) const;
   string   getProlongation(const uint unitDuration) const;
   string   getExtendedProlongation(const uint unitDuration, const uint start, const uint unitsPerBar, uint &barCount) const;
   string   createTriplet(const uint i, const iData& pitches, const uint pitchOffset, const iData &iois, const uint unitsPerBar, uint& counter, uint &barCount);
   void     testSegmenter();
   void     testTemperley();//TO BE REMOVED
   void     testPlainLBDM();//TO BE REMOVED
   void     testRefinedLBDM();//TO BE REMOVED
   void     testHybrid();//TO BE REMOVED
};
#endif
