/***************************************************************************
*   KBlocks, a falling blocks game for KDE                                *
*   Copyright (C) 2010 University Freiburg                                *
*                                                                         *
*   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 KBLOCKSAIFEATURE_H
#define KBLOCKSAIFEATURE_H

#include "KBlocksAITypeDefine.h"
#include "EvaluationInterface.h"

#include "../KBlocksField.h"
#include "../KBlocksPiece.h"

/*******************************************************
****   Feature  List   ********************************
*******************************************************/

enum FeatureEnumeration
{
    FEATURE_MAX_HEIGHT,
    FEATURE_HOLES_COUNT,
    FEATURE_CLOSED_HOLES_COUNT,
    FEATURE_WELLS_COUNT,
    FEATURE_AVERAGE_HEIGHT,
    FEATURE_AVERAGE_HEIGHT_DIFFERENT,            
    FEATURE_MAX_HEIGHT_DIFFERENT,            
    FEATURE_KONTUR_COUNT,
    FEATURE_MAX_KONTUR_LENGTH,    
    FEATURE_BLOCKS_COUNT,
    FEATURE_BLOCKS_OVER_HOLES_COUNT,
    FEATURE_WEIGHTED_BLOCKS_COUNT,
    FEATURE_ROW_TRANSITION_COUNT,
    FEATURE_COLUMN_TRANSITION_COUNT,  
    FEATURE_MAX_WELL_DEPTH,
    FEATURE_NARROW_COUNT,
    FEATURE_PREDICTION_COUNT,
    FEATURE_COUNT
};

enum SpecialFeatureEnumeration
{
    FEATURE_REMOVE_LINES,
    FEATURE_LANDING_HEIGHT
};

double getFeature(const FeatureEnumeration, KBlocksField*);
const char * getFeatureName(const FeatureEnumeration);
double getSpecialFeature(const SpecialFeatureEnumeration, KBlocksField*, KBlocksField*, KBlocksPiece*);
void update_board_signature(KBlocksField * field);
void set_ground_line(int);

/*******************************************************
****   Feature     ************************************
*******************************************************/
class Evaluation_Max_Height: public EvaluationInterface
{
public:
    double evaluate(KBlocksField*);
    static Evaluation_Max_Height* instance()
    {
        if(_instance == 0)
        {
            _instance = new Evaluation_Max_Height();
        }
        return _instance;
    }
    CLASSNAME(Evaluation_Max_Height)
private:
    Evaluation_Max_Height(){}
    ~Evaluation_Max_Height(){}
    static Evaluation_Max_Height* _instance;
};
//------------------------------------------------------
class  Evaluation_Holes_Count: public EvaluationInterface
{
public:
    double evaluate(KBlocksField*);
    static Evaluation_Holes_Count* instance()
    {
        if(_instance == 0)
        {
            _instance = new Evaluation_Holes_Count();
        }
        return _instance;
    }
    CLASSNAME(Evaluation_Holes_Count)
private:
    Evaluation_Holes_Count(){}
    ~Evaluation_Holes_Count(){}
    static Evaluation_Holes_Count* _instance;
};
//------------------------------------------------------
class  Evaluation_Average_Height: public EvaluationInterface
{
public:
    double evaluate(KBlocksField*);
    static Evaluation_Average_Height* instance()
    {
        if(_instance == 0)
        {
            _instance = new Evaluation_Average_Height();
        }
        return _instance;
    }
    CLASSNAME(Evaluation_Average_Height)
private:
    Evaluation_Average_Height(){}
    ~Evaluation_Average_Height(){}
    static Evaluation_Average_Height* _instance;
};
//------------------------------------------------------
class  Evaluation_Max_Height_Difference: public EvaluationInterface
{
public:
    double evaluate(KBlocksField*);
    static Evaluation_Max_Height_Difference* instance()
    {
        if(_instance == 0)
        {
            _instance = new Evaluation_Max_Height_Difference();
        }
        return _instance;
    }
    CLASSNAME(Evaluation_Max_Height_Difference)
private:
    Evaluation_Max_Height_Difference(){}
    ~Evaluation_Max_Height_Difference(){}
    static Evaluation_Max_Height_Difference* _instance;
};  
//------------------------------------------------------
class  Evaluation_Average_Height_Difference: public EvaluationInterface
{
public:
    double evaluate(KBlocksField*);
    static Evaluation_Average_Height_Difference* instance()
    {
        if(_instance == 0)
        {
            _instance = new Evaluation_Average_Height_Difference();
        }
        return _instance;
    }
    CLASSNAME(Evaluation_Average_Height_Difference)
private:
    Evaluation_Average_Height_Difference(){}
    ~Evaluation_Average_Height_Difference(){}
    static Evaluation_Average_Height_Difference* _instance;
};  
//------------------------------------------------------
class  Evaluation_Kontur_Count: public EvaluationInterface
{
public:
    double evaluate(KBlocksField*);
    static Evaluation_Kontur_Count* instance()
    {
        if(_instance == 0)
        {
            _instance = new Evaluation_Kontur_Count();
        }
        return _instance;
    }
    CLASSNAME(Evaluation_Kontur_Count)
private:
    Evaluation_Kontur_Count(){}
    ~Evaluation_Kontur_Count(){}
    static Evaluation_Kontur_Count* _instance;
};
//------------------------------------------------------
class  Evaluation_Max_Kontur_Length: public EvaluationInterface
{
public:
    double evaluate(KBlocksField*);
    static Evaluation_Max_Kontur_Length* instance()
    {
        if(_instance == 0)
        {
            _instance = new Evaluation_Max_Kontur_Length();
        }
        return _instance;
    }
    CLASSNAME(Evaluation_Max_Kontur_Length)
private:
    Evaluation_Max_Kontur_Length(){}
    ~Evaluation_Max_Kontur_Length(){}
    static Evaluation_Max_Kontur_Length* _instance;
};
//------------------------------------------------------
class  Evaluation_Closed_Holes_Count: public EvaluationInterface
{
public:
    double evaluate(KBlocksField*);
    static Evaluation_Closed_Holes_Count* instance()
    {
        if(_instance == 0)
        {
            _instance = new Evaluation_Closed_Holes_Count();
        }
        return _instance;
    }
    CLASSNAME(Evaluation_Closed_Holes_Count)
private:
    Evaluation_Closed_Holes_Count(){}
    ~Evaluation_Closed_Holes_Count(){}
    static Evaluation_Closed_Holes_Count* _instance;
};
//------------------------------------------------------
class  Evaluation_Wells_Count: public EvaluationInterface
{
public:
    double evaluate(KBlocksField*);
    static Evaluation_Wells_Count* instance()
    {
        if(_instance == 0)
        {
            _instance = new Evaluation_Wells_Count();
        }
        return _instance;
    }
    CLASSNAME(Evaluation_Wells_Count)
private:
    Evaluation_Wells_Count(){}
    ~Evaluation_Wells_Count(){}
    static Evaluation_Wells_Count* _instance;
};
//------------------------------------------------------
class  Evaluation_Blocks_Count: public EvaluationInterface
{
public:
    double evaluate(KBlocksField*);
    static Evaluation_Blocks_Count* instance()
    {
        if(_instance == 0)
        {
            _instance = new Evaluation_Blocks_Count();
        }
        return _instance;
    }
    CLASSNAME(Evaluation_Blocks_Count)
private:
    Evaluation_Blocks_Count(){}
    ~Evaluation_Blocks_Count(){}
    static Evaluation_Blocks_Count* _instance;
};
//------------------------------------------------------
class  Evaluation_Blocks_Over_Holes_Count: public EvaluationInterface
{
public:
    double evaluate(KBlocksField*);
    static Evaluation_Blocks_Over_Holes_Count* instance()
    {
        if(_instance == 0)
        {
            _instance = new Evaluation_Blocks_Over_Holes_Count();
        }
        return _instance;
    }
    CLASSNAME(Evaluation_Blocks_Over_Holes_Count)
private:
    Evaluation_Blocks_Over_Holes_Count(){}
    ~Evaluation_Blocks_Over_Holes_Count(){}
    static Evaluation_Blocks_Over_Holes_Count* _instance;
};
//------------------------------------------------------
class Evaluation_Weighted_Blocks_Count:public EvaluationInterface
{
public:
    double evaluate(KBlocksField*);
    static Evaluation_Weighted_Blocks_Count* instance()
    {
        if(_instance == 0)
        {
            _instance = new Evaluation_Weighted_Blocks_Count();
        }
        return _instance;
    }
    CLASSNAME(Evaluation_Weighted_Blocks_Count)
private:
    Evaluation_Weighted_Blocks_Count(){}
    ~Evaluation_Weighted_Blocks_Count(){}
    static Evaluation_Weighted_Blocks_Count* _instance;
};
//------------------------------------------------------
class Evaluation_Row_Transition_Count:public EvaluationInterface
{
public:
    double evaluate(KBlocksField*);
    static Evaluation_Row_Transition_Count* instance()
    {
        if(_instance == 0)
        {
            _instance = new Evaluation_Row_Transition_Count();
        }
        return _instance;
    }
    CLASSNAME(Evaluation_Row_Transition_Count)
private:
    Evaluation_Row_Transition_Count(){}
    ~Evaluation_Row_Transition_Count(){}
    static Evaluation_Row_Transition_Count* _instance;
};
//------------------------------------------------------
class Evaluation_Column_Transition_Count:public EvaluationInterface
{
public:
    double evaluate(KBlocksField*);
    static Evaluation_Column_Transition_Count* instance()
    {
        if(_instance == 0)
        {
            _instance = new Evaluation_Column_Transition_Count();
        }
        return _instance;
    }
    CLASSNAME(Evaluation_Column_Transition_Count)
private:
    Evaluation_Column_Transition_Count(){}
    ~Evaluation_Column_Transition_Count(){}
    static Evaluation_Column_Transition_Count* _instance;
};
//------------------------------------------------------
class Evaluation_Narrow_Count:public EvaluationInterface
{
public:
    double evaluate(KBlocksField*);
    static Evaluation_Narrow_Count* instance()
    {
        if(_instance == 0)
        {
            _instance = new Evaluation_Narrow_Count();
        }
        return _instance;
    }
    CLASSNAME(Evaluation_Narrow_Count)
private:
    Evaluation_Narrow_Count(){}
    ~Evaluation_Narrow_Count(){}
    static Evaluation_Narrow_Count* _instance;
};
//------------------------------------------------------
class Evaluation_Prediction_Count:public EvaluationInterface
{
public:
    double evaluate(KBlocksField*);
    static Evaluation_Prediction_Count* instance()
    {
        if(_instance == 0)
        {
            _instance = new Evaluation_Prediction_Count();
        }
        return _instance;
    }
    CLASSNAME(Evaluation_Prediction_Count)
private:
    Evaluation_Prediction_Count(){}
    ~Evaluation_Prediction_Count(){}
    static Evaluation_Prediction_Count* _instance;
};
//------------------------------------------------------
class Evaluation_Max_Well_Depth:public EvaluationInterface
{
public:
    double evaluate(KBlocksField*);
    static Evaluation_Max_Well_Depth* instance()
    {
        if(_instance == 0)
        {
            _instance = new Evaluation_Max_Well_Depth();
        }
        return _instance;
    }
    CLASSNAME(Evaluation_Max_Well_Depth)
private:
    Evaluation_Max_Well_Depth(){}
    ~Evaluation_Max_Well_Depth(){}
    static Evaluation_Max_Well_Depth* _instance;
};

//# SPECIAL FEATURE #######################################
class Evaluation_Remove_Lines:public SpecialEvaluationInterface
{
public:
    double evaluate(KBlocksField*);
    static Evaluation_Remove_Lines* instance()
    {
        if(_instance == 0)
        {
            _instance = new Evaluation_Remove_Lines();
        }
        return _instance;
    }
    CLASSNAME(Evaluation_Remove_Lines)
private:
    Evaluation_Remove_Lines(){}
    ~Evaluation_Remove_Lines(){}
    static Evaluation_Remove_Lines* _instance;
};
//------------------------------------------------------
class Evaluation_Landing_Height:public SpecialEvaluationInterface
{
public:
    double evaluate(KBlocksField*);
    static Evaluation_Landing_Height* instance()
    {
        if(_instance == 0)
        {
            _instance = new Evaluation_Landing_Height();
        }
        return _instance;
    }
    CLASSNAME(Evaluation_Landing_Height)
private:
    Evaluation_Landing_Height(){}
    ~Evaluation_Landing_Height(){}
    static Evaluation_Landing_Height* _instance;
};

#endif //KBLOCKSAIFEATURE_H
