#ifndef _CHORDS_H
#define _CHORDS_H
#include <string>

#include "Types.h"
typedef vector<uint> PitchSet;
typedef vector<PitchSet> PitchSetList;
typedef vector< pair<uint, double> > WeightedPitchSet;

struct ChordsAnalyzerParameter
{
   uint m_dummy; 
};
typedef enum{
   eChordGender_unknown  = 0, 
   eChordGender_nc, 
   eChordGender_1, 
   eChordGender_2, 
   eChordGender_3, 
   eChordGender_4, 
   eChordGender_5, 
   eChordGender_6,    
   eChordGender_7, 
   eChordGender_maj, 
   eChordGender_min, 
   eChordGender_dim, 
   eChordGender_aug, 
   eChordGender_maj7, 
   eChordGender_dom7, 
   eChordGender_min7, 
   eChordGender_minmaj7, 
   eChordGender_halfdim, 
   eChordGender_fulldim, 
   eChordGender_aug7, 
   eChordGender_augmaj7, 
   eChordGender_dimmaj7, 
   eChordGender_fourths, 
   eChordGender_fifths 
}eChordGender;

class ChordsAnalyzerResult
{
public: 
   ChordsAnalyzerResult(){}
   ChordsAnalyzerResult(const ChordsAnalyzerResult& rhs){
      Init(rhs.m_sThirdsChain, rhs.m_extensions, rhs.m_root,rhs.m_bass, rhs.m_weight); 
   }
   ChordsAnalyzerResult& operator= (const ChordsAnalyzerResult& rhs)
   {
      Init(rhs.m_sThirdsChain, rhs.m_extensions, rhs.m_root,rhs.m_bass, rhs.m_weight); 
      return *this;
   }
   void  Init(
               const std::string &sThirdsChain, 
               const PitchSet &extensions, 
               const int root,
               const int bass,
               double weight
              )
   {
      Clear();
      m_sThirdsChain = sThirdsChain;
      m_extensions = extensions;
      m_chordGender = eChordGender_unknown;
      m_root = root;
      m_bass = bass;
      m_weight = weight;
   }
   void  Clear()
   { 
      m_sThirdsChain = "";
      m_extensions.clear();
      m_chordGender = eChordGender_unknown;
      m_root = (uint)-1;
      m_bass = (uint)-1;
      m_weight = 0.0;
   }
   std::string   ToString();

protected:
   std::string       m_sThirdsChain;
   PitchSet          m_extensions;
   eChordGender      m_chordGender;
   uint              m_bass;
   uint              m_root;
   double            m_weight; 
   eChordGender      getChordGender();
};

typedef vector<ChordsAnalyzerResult> ChordList;

class PitchSetPreprocessor
{
public:
   PitchSetPreprocessor(): m_weight(1), m_maxWeight(2){}
   void  Init(const PitchSet& pitchset);
   WeightedPitchSet& GetWeightedPitchSet(){ return m_wps; }
   std::string ToString();
protected:
private:
   WeightedPitchSet m_wps;
   double m_weight;
   double m_maxWeight;
};

typedef enum { eThirdType_minor = 0, eThirdType_major} eThirdType;

class ThirdsTree
{
public:
   ThirdsTree(): m_pc(-1), m_octaveSet(0), m_maxLength(0), m_minorLen(0), m_majorLen(0), m_minor(0), m_major(0){}
   ThirdsTree(const uint pc, const unsigned short octaveSet): 
      m_pc(pc), 
      m_octaveSet(octaveSet), 
      m_maxLength(0), 
      m_minorLen(0),
      m_majorLen(0), 
      m_minor(0), 
      m_major(0)
      {}
   
   ~ThirdsTree()
   {
      if(m_minor) delete m_minor;
      if(m_major) delete m_major;
   }
   void Add(ThirdsTree *node, eThirdType type);

   uint           GetCount()     const;
   uint           GetMaxLength() const {return m_maxLength;}
   stringlist     GetLongestSubTrees() const;
   stringlist     GetSubTrees(const uint max) const;
   stringlist     ToStringList() const;
   std::string    ToString() const;

private:
   uint        m_pc;
   uint        m_octaveSet;
   uint        m_maxLength;
   uint        m_minorLen;
   uint        m_majorLen;
   ThirdsTree *m_minor;
   ThirdsTree *m_major;

};


class ChordsAnalyzer{

public: 
   ChordsAnalyzer(){}
   ChordsAnalyzer(const ChordsAnalyzerParameter* pParam):m_pParameter(pParam){}
   ~ChordsAnalyzer(){}
   void Init();
   void SetParameter(const ChordsAnalyzerParameter* pParam){m_pParameter = pParam;}
   ChordList Analyze(const WeightedPitchSet& wps);
protected:

private:
   const ChordsAnalyzerParameter *m_pParameter;
   uint                           m_collection[12];
   uint                           m_bass;

   void  setCollection(const WeightedPitchSet& wps);
   void  clearCollection(){ memset(m_collection, 0, sizeof(m_collection));}
   ThirdsTree*  getThirdsChains(uint collection[12], uint basePitch);
   PitchSet     getUpperStructure(const std::string& thirds, const uint basePitch);
   PitchSet     getChordNotes(const std::string& thirds, const uint basePitch);
};


#endif
