#include "mycvfloodfill.h"

mycvClassFloodFill::mycvClassFloodFill(uchar aActVal, uchar aNewVal)
{
    mActVal = aActVal;
    mNewVal = aNewVal;
}

mycvClassFloodFill::mycvClassFloodFill()
{
    mActVal = 0;
    mNewVal = 0;
}

mycvClassFloodFill::~mycvClassFloodFill()
{

}

void mycvClassFloodFill::FloodFill(Mat &aDst, Point aP, uint &aVol, sPoints4 &aSize)
{
   if(aDst.at<uchar>(aP.x, aP.y) == mActVal)
   {
       aDst.at<uchar>(aP.x, aP.y) = mNewVal;

       // increase vol
       aVol++;

       // Actualize size of area
       if(aSize.cornerLU.x > aP.x)aSize.cornerLU.x = aP.x;
       if(aSize.cornerLU.y > aP.y)aSize.cornerLU.y = aP.y;
       if(aSize.cornerPD.x < aP.x)aSize.cornerPD.x = aP.x;
       if(aSize.cornerPD.y < aP.y)aSize.cornerPD.y = aP.y;

       aP.x++;
       if(aP.x < aDst.rows)FloodFill(aDst, aP, aVol, aSize);
       aP.x-=2;
       if(aP.x >= 0)FloodFill(aDst, aP, aVol, aSize);
       aP.x++;
       aP.y++;
       if(aP.y < aDst.cols && aP.x >= 0)FloodFill(aDst, aP, aVol, aSize);
       aP.y-=2;
       if(aP.y >= 0 && aP.x >= 0)FloodFill(aDst, aP, aVol, aSize);
   }
}

void mycvClassFloodFill::FloodFill2(Mat &aDst, Point aP, uint &aVol, sPoints4 &aSize)
{
    int c = aDst.cols;
    int r = aDst.rows;
    vector<Point> stack;
    stack.push_back(aP);
    while(!stack.empty())
    {
        Point actP = (Point)stack.back();   // get last elem
        stack.pop_back();                   // remove last elem from stack

        // check borders
        if (actP.y < 0 || actP.y > c - 1 || actP.x < 0 || actP.x > r - 1)
                    continue;

        if(aDst.at<uchar>(actP.x, actP.y) == mActVal)
        {
            aVol++; // increase volume
            aDst.at<uchar>(actP.x, actP.y) = mNewVal; // set new color
            // Actualize size of area
            if(aSize.cornerLU.x > actP.x)aSize.cornerLU.x = actP.x;
            if(aSize.cornerLU.y > actP.y)aSize.cornerLU.y = actP.y;
            if(aSize.cornerPD.x < actP.x)aSize.cornerPD.x = actP.x;
            if(aSize.cornerPD.y < actP.y)aSize.cornerPD.y = actP.y;

            stack.push_back(Point(actP.x+1, actP.y));
            stack.push_back(Point(actP.x-1, actP.y));
            stack.push_back(Point(actP.x, actP.y+1));
            stack.push_back(Point(actP.x, actP.y-1));
        }
    }
}

void mycvClassFloodFill::mycvRemoveHigherObjects(const Mat &aSrc, Mat &aDst, uint aMaxVol, uint maxX, uint maxY, uint minX, uint minY, uint aMinVol)
{
    Mat pom = aSrc.clone();

    for(int i = 1 ; i < aSrc.rows - 1 ; i++)
    {
        for(int j = 1 ; j < aSrc.cols - 1 ; j++)
        {
            // Find white pixel
            if(pom.at<uchar>(i, j) > 125)
            {
                // Fill actual area with 1
                uint vol = 0;
                sPoints4 areaSize;
                areaSize.cornerLU.x = std::numeric_limits<int>::max();
                areaSize.cornerLU.y = std::numeric_limits<int>::max();
                mActVal = pom.at<uchar>(i, j);
                mNewVal = 1;
                FloodFill2(pom, Point(i, j), vol, areaSize);
                mActVal = 1;
                mNewVal = 0;
                if(vol >= aMaxVol && aMaxVol > 0)
                {
                    FloodFill2(pom, Point(i, j), vol, areaSize);
                }
                else if(vol < aMinVol)
                {
                    FloodFill2(pom, Point(i, j), vol, areaSize);
                }
                else if((((areaSize.cornerPD.x - areaSize.cornerLU.x) > (int)maxY && maxY != 0) || \
                        ((areaSize.cornerPD.y - areaSize.cornerLU.y) > (int)maxX) && maxX != 0))
                {
                    FloodFill2(pom, Point(i, j), vol, areaSize);
                }
                else if((areaSize.cornerPD.x - areaSize.cornerLU.x) < (int)minY || \
                        (areaSize.cornerPD.y - areaSize.cornerLU.y) < (int)minX)
                {
                    FloodFill2(pom, Point(i, j), vol, areaSize);
                }
            }
        }
    }
    // Ones back to value 255
    Mat lookUpTable(1, 256, CV_8U);
    uchar* p = lookUpTable.data;
    p[0] = 0;
    p[1] = 255;
    LUT(pom, lookUpTable, aDst);
}
