/***************************************************************************
                          Segmnter2.h  -  description
                             -------------------
    begin                : Di Feb 15 2005
    copyright            : (C) 2005 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_SEGMENTER2_H
#define _LIBMELODY_SEGMENTER2_H

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

namespace Segmenter{
using namespace Transformations;
class BoundaryBase
{
public:
   BoundaryBase(const Melody *pMel): m_pMel(pMel), m_dFactor(1.0){};
   BoundaryBase(const Melody *pMel, const double factor): m_pMel(pMel), m_dFactor(factor){};
   virtual ~BoundaryBase(){};

   void              setMelody(const Melody* pMel){ m_pMel = pMel;}
   const Melody*     getMelody()const{ return m_pMel;}

   virtual MRESULT   getBoundaryStrengths(Vector& ret)const= 0;
   virtual MRESULT   getBoundaryStrengths(Vector& ret, const uint start, uint end)const = 0;

   virtual bool      isValid()const{ return m_pMel != 0 ;}
   virtual uint      size()const{ if(isValid()) return (uint)m_pMel->size(); return 0;}

   void              setFactor(const double factor){ m_dFactor = factor;}

protected:
   const Melody *    m_pMel;
   double            m_dFactor;

};

class BoundaryCluster:public BoundaryBase
{
public:
   BoundaryCluster(const Melody *pMel): BoundaryBase(pMel){}
   virtual ~BoundaryCluster(){}
   
   virtual bool      isValid()const;
   virtual uint      size()const{ if(isValid()) return (uint)m_bounds[0]->getMelody()->size(); return 0;}
   void              add(const BoundaryBase* pBase){ m_bounds.push_back(pBase);}
   void              clear(){ m_bounds.clear();}
   
   virtual MRESULT   getBoundaryStrengths(Vector& ret)const= 0;
   virtual MRESULT   getBoundaryStrengths(Vector& ret,const uint start, uint end)const = 0;

protected:
   vector<const BoundaryBase*> m_bounds;
};

class LinearBoundaryCluster:public BoundaryCluster
{
public:
   LinearBoundaryCluster(const Melody *pMel): BoundaryCluster(pMel){}
   virtual ~LinearBoundaryCluster(){}
   
   virtual MRESULT getBoundaryStrengths(Vector& ret)const;
   virtual MRESULT getBoundaryStrengths(Vector& ret, const uint start, uint end)const;

protected:
};

class TemperleyGapScore: public BoundaryBase
{
public:
   TemperleyGapScore(const Melody* pMel);

   virtual  MRESULT getBoundaryStrengths(Vector& ret)const;
   virtual  MRESULT getBoundaryStrengths(Vector& ret,const uint start, uint end)const;

protected:
   Vector         m_gapScores;
   MRESULT        calcGapScores();
};

class TemperleyLengthBoundary: public BoundaryBase
{
public:
   TemperleyLengthBoundary(const Melody* pMel, const double optimalLength=10.0) : BoundaryBase(pMel), m_dOptimalLength(optimalLength)
   {}

   void     setOptimalLength(const double length){ m_dOptimalLength = length;}

   virtual  MRESULT getBoundaryStrengths(Vector& ret)const;
   virtual  MRESULT getBoundaryStrengths(Vector& ret,const uint start, uint end)const;

protected:
   double    m_dOptimalLength;
};


class MetricParallelBoundary: public BoundaryBase
{
public:
   MetricParallelBoundary(const Melody* pMel, double dPhase3, double dPhase4) : BoundaryBase(pMel), m_dPhase3(dPhase3), m_dPhase4(dPhase4)
   {}
   void     setParams(const double dPhase3, const double dPhase4){ m_dPhase3 = dPhase3; m_dPhase4 = dPhase4;}

   virtual  MRESULT getBoundaryStrengths(Vector& ret)const;
   virtual  MRESULT getBoundaryStrengths(Vector& ret,const uint start, uint end)const;

protected:
   double   m_dPhase3, m_dPhase4;

   double   getPhasePenalty(const Tone& tone1, const Tone& tone2)const;
};


class LBDMBase: public BoundaryBase
{
public:
   LBDMBase(const Melody* pMel, Transformation *pInterval);

   virtual  bool     isValid()const{ return BoundaryBase::isValid() && m_pInterval != 0;}

   virtual  MRESULT  getBoundaryStrengths(Vector& ret)const;
   virtual  MRESULT  getBoundaryStrengths(Vector& ret, const uint start, uint end)const;
   
   MRESULT  setTransformation(Transformation *pInterval){ m_pInterval = pInterval; return setIntervals();}

protected:
   Vector               m_boundaries;
   Transformation      *m_pInterval;
   Vector               m_intervals;

   MRESULT              setIntervals();
   virtual MRESULT      calcBoundaries()=0;

private:

};

class PlainLBDM: public LBDMBase
{
public:
   PlainLBDM(const Melody *pMel,  Transformation *pInterval, const double dBonus, const double dLarger, const double dDiff):
      LBDMBase(pMel, pInterval), m_dBonus(dBonus),  m_dDiff(dDiff), m_dLarger(dLarger)
      {  calcBoundaries(); }
   void     setParameter(const double dBonus, const double dDiff, const double dLarger){ m_dBonus = dBonus; m_dLarger = dLarger; m_dDiff = dDiff; calcBoundaries();}
   //virtual  MRESULT getBoundaryStrengths(Vector& ret)const;
   //virtual  MRESULT getBoundaryStrengths(Vector& ret, const uint start, uint end)const;

protected:
   double   m_dBonus, m_dDiff, m_dLarger ;

   int      getIntervalRelation(const double d1, const double d2) const;
   MRESULT  calcBoundaries();

};

class RefinedLBDM: public LBDMBase
{
public:
   RefinedLBDM(const Melody *pMel,  Transformation *pInterval): LBDMBase(pMel, pInterval)
   { calcBoundaries(); }
   /*
   virtual  MRESULT getBoundaryStrengths(Vector& ret)const;
   virtual  MRESULT getBoundaryStrengths(Vector& ret, const uint start, uint end)const;
   */
protected:
   double   alpha(double x, double y) const;
   MRESULT  calcBoundaries();
};

class SegmenterBase
{
public:
   SegmenterBase(const BoundaryBase* pBoundary = 0): m_pBoundary(pBoundary){};
   virtual ~SegmenterBase(){}

   void     setBoundary(const BoundaryBase *pBoundary){ m_pBoundary = pBoundary;}

   virtual  MRESULT  analyze(Vector& ret)const=0;
   
protected:
   const BoundaryBase*  m_pBoundary;

};

class LocalMaxima : public SegmenterBase
{
public:
   LocalMaxima(const BoundaryBase* pBoundary): SegmenterBase(pBoundary){};
   virtual ~LocalMaxima(){}

   virtual  MRESULT   analyze(Vector& ret)const;

protected:

};

class LocalMaximaMaxima : public SegmenterBase
{
public:
   LocalMaximaMaxima(const BoundaryBase* pBoundary): SegmenterBase(pBoundary){};
   virtual ~LocalMaximaMaxima(){}

   virtual  MRESULT   analyze(Vector& ret)const;

protected:

};
class TemperleyDPA: public SegmenterBase
{
public:
   TemperleyDPA(const BoundaryBase* pBoundary, const uint iTestLength = 20, bool bUseOverallLengthPenalty = true): SegmenterBase(pBoundary), m_iTestLength(iTestLength), m_bUseOverallLengthPenalty(bUseOverallLengthPenalty){};
   virtual ~TemperleyDPA(){}

   virtual  MRESULT  analyze(Vector& ret)const;

protected:
   uint     m_iTestLength;
   bool     m_bUseOverallLengthPenalty;

};
}
#endif