/***************************************************************************
                          MetricTree.h  -  description
                             -------------------
    begin                : Don Aug 14 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 METRICTREE_H
#define METRICTREE_H

#include "Types.h"
enum eBeatType{ eBeat_unknown = -1, eBeat_secondary, eBeat_primary};

struct MetricLeaf{
   MetricLeaf(uint val, vector<uint>& metric, MetricLeaf *pNode = 0, MetricLeaf *pLeft = 0, MetricLeaf *pRight = 0)
      : m_val(val), m_pLeft (pLeft), m_pRight(pRight), m_pNode(pNode), m_sName("")
   {
      metricStruct = metric;
      metricStruct.push_back(val);
      setName();
      //cout<<"New leaf with val = "<<val<<" name = "<<m_sName<<" ("<<getPointer(this)<<")"<<endl;
   }
   ~MetricLeaf()
   {
      metricStruct.clear();
      if(m_pLeft){
         delete m_pLeft;
         m_pLeft = 0;
       }
       if(m_pRight){
           delete m_pRight;
         m_pRight = 0;
       }
       //cerr<<"Deleted node "<<m_sName<<" ("<<getPointer(this)<<")"<<endl;
   }

   bool              buildTree(uint val, vector<MetricLeaf*>& endLeaves);
   void              setName();
   string            getName(){ return m_sName;}
   char *            getPointer(void *p);
   void              dumpSubTree();
   uint              getLeafCount();
   uint              m_val;

   MetricLeaf       *m_pLeft;
   MetricLeaf       *m_pRight;
   MetricLeaf       *m_pNode;
   string            m_sName;
   vector<uint>      metricStruct;
   vector<uint>      getPrimaryBeats();
   vector<uint>      getSecondaryBeats();
};

class MetricTree
{
public:
   MetricTree():m_pHead(0){}
   MetricTree(const uint val):m_val(val), m_pHead(0){ buildTree(val); }

   ~MetricTree()
   {
      if (m_pHead) {
         delete m_pHead;
         m_pHead = 0;
      }
   }
   void           buildTree(const uint val);
   uint           getLeafCount();
   uint           getEndLeafCount(){ return m_EndLeaves.size();}
   void           dumpTree();
   vector<uint>   getPrimaryBeats(uint ndx);
   vector<uint>   getSecondaryBeats(uint ndx);
   eBeatType      getBeatType(uint val);
   uint           getVal(){return m_val;}
protected:
   uint                m_val;
   MetricLeaf         *m_pHead;   
   vector<MetricLeaf*> m_EndLeaves;
};

class MetricTree2
{
public:
   MetricTree2(const uint nCount, const uint nVal = 0):m_nSize(nCount), m_nVal(nVal)
   { 
      //cout<<"Created tree size  = "<<m_nSize<<" offset= "<<m_nVal<<endl;
      buildTree();
   }
   ~MetricTree2()
   { 
      for(uint i = 0; i<m_pNodes.size(); ++i){
         if(m_pNodes[i]) delete m_pNodes[i];
         m_pNodes[i] = 0;
      }
   }
   void           dump()const;
   uint           getVal()const{return m_nVal;}
   uint           getSize()const{return m_nSize;}
   uint           getBeatLevel(const uint beat)const;
   eBeatType      getBeatType(const uint beat)const;
   uint           getDepth()const;
   uint           getMainDivision()const{ return m_pNodes.size();}
   uint           getMinUnit()const;
protected:
   uint                 m_nSize;
   uint                 m_nVal;
   vector<MetricTree2*> m_pNodes;

   vector<uint>   getMinimalPartition(const uint val);
   void           buildTree();
   uint           count(const uint val)const;

};
void testMetricTree2();
#endif
