#include <iostream>
#include "opencv2\opencv.hpp"

using namespace std;
using namespace cv;

class Strategy
{
public:
    //uchar *RGB;
    int mean,_count,k;
    virtual ~Strategy() {}
    virtual Mat process_image(Mat &image) = 0;
};

class Context
{
public:
    Mat ContextInterface(Strategy *pStrategy,Mat &image);
};

class original : public Strategy
{
public:
    virtual ~original() {}

    virtual Mat process_image(Mat &image);
};

class gray : public Strategy
{
public:
    virtual ~gray() {}

    virtual Mat process_image(Mat &image);
};

class threshhold : public Strategy
{
public:
    virtual ~threshhold() {}

    virtual Mat process_image(Mat &image);
};

Mat Context::ContextInterface(Strategy *pStrategy,Mat &image)
{
    return pStrategy->process_image(image);
}

Mat original::process_image(Mat &image)
{
    return image;
}

Mat gray::process_image(Mat &image)
{
    mean=_count=0;
    for(int i=0; i<image.rows; i++)
    {
        for(int j=0; j<image.cols; j++)
        {
            k=0.333*(image.at<Vec3b>(i,j)[2]+image.at<Vec3b>(i,j)[1]+image.at<Vec3b>(i,j)[0]);
            image.at<Vec3b>(i,j)[2]=image.at<Vec3b>(i,j)[1]=image.at<Vec3b>(i,j)[0]=k;
            mean+=k;
            ++_count;
        }
    }
    return image;
}

Mat threshhold::process_image(Mat &image)
{
    for(int i=0; i<image.rows; i++)
    {
        for(int j=0; j<image.cols; j++)
        {
            if(image.at<Vec3b>(i,j)[2]<mean)
            {
                image.at<Vec3b>(i,j)[2]=image.at<Vec3b>(i,j)[1]=image.at<Vec3b>(i,j)[0]=0;
            }
            else
            {
                image.at<Vec3b>(i,j)[2]=image.at<Vec3b>(i,j)[1]=image.at<Vec3b>(i,j)[0]=255;
            }
        }
    }
    return image;
}



int main(void)
{
    Mat image=imread("pic3.png", CV_LOAD_IMAGE_COLOR);   // Read the file
    Context* pContext = new Context();
    Strategy* pStrategy;
    int mean;

    if(! image.data )                              // Check for invalid input
    {
        cout <<  "Could not open or find the image" << std::endl ;
        return -1;
    }

    cout<<image.rows;

    //show original picture
    pStrategy = new original();
    namedWindow( "original", CV_WINDOW_AUTOSIZE );// Create a window for display.
    imshow( "original", pContext->ContextInterface(pStrategy,image) );                   // Show our image inside it.
    delete pStrategy;

    //show gray picture
    pStrategy = new gray();
    namedWindow( "gray", CV_WINDOW_AUTOSIZE );// Create a window for display.
    imshow( "gray", pContext->ContextInterface(pStrategy,image) );                   // Show our image inside it.
    mean=(pStrategy->mean)/(pStrategy->_count);
    delete pStrategy;

    //show threshhold picture
    pStrategy = new threshhold();
    (pStrategy->mean)=mean;
    namedWindow( "threshhold", CV_WINDOW_AUTOSIZE );// Create a window for display.
    imshow( "threshhold", pContext->ContextInterface(pStrategy,image) );                   // Show our image inside it.
    delete pStrategy;

    waitKey(0);                                          // Wait for a keystroke in the window
    return 0;
}
