#include "Filter2.h"

#include <memory.h>   // memset
#include <iostream.h> // cout

//#include "MStar.h"
#include "MStarList.h"

ClassImp(Filter2);

void Filter2::DrawBox(const int x1, const int y1,
                     const int x2, const int y2,
                     byte *buffer, const int col)
{
    for (int x=x1; x<x2+1; x++)
        for (int y=y1; y<y2+1; y++)
            buffer[y*768+x] = col;
}

void Filter2::MarkPoint(const int x, const int y, byte *buffer, const int col)
{
    DrawBox(x-8, y, x-5, y, buffer, col);
    DrawBox(x, y+5, x, y+8, buffer, col);
    DrawBox(x+5, y, x+8, y, buffer, col);
    DrawBox(x, y-8, x, y-5, buffer, col);
    return;
}

float Filter2::Mean(const byte *buffer, const int offset, int *min, int *max)
{
    double mean = 0.0;

    *min = 0xff;
    *max = 0x00;

    //
    // calculate mean value
    //
    for (int x=offset; x<768-offset; x++)
        for (int y=offset; y<576-offset; y++)
        {
            byte val = buffer[y*768+x];

            mean += val;

            if (val>*max)
                *max = val;

            if (val<*min)
                *min = val;
        }

    mean /= (768-2*offset)*(576-2*offset);

    return mean;
}

float Filter2::SDev(const byte *buffer, const int offset, const double mean)
{
    //
    // calculate sigma
    //
    double sdev=0.0;

    for (int x=offset; x<768-offset; x++)
        for (int y=offset; y<576-offset; y++)
        {
            const float val = mean - buffer[y*768+x];

            sdev += val*val;
        }

    sdev /= (768-2*offset)*(576-2*offset)-1;

    return sqrt(sdev);
}

int Filter2::GetMeanPosition(const byte *bitmap, const int x, const int y,
                             const int box, Double_t &mx, Double_t &my)
{
    unsigned int sumx=0;
    unsigned int sumy=0;

    unsigned int sum=0;

    for (int dx=x-box; dx<x+box+1; dx++)
        for (int dy=y-box; dy<y+box+1; dy++)
        {
            const byte m = bitmap[dy*768+dx]; // desc->buffer[3*(x+y*768)]; //

            sumx += m*dx;
            sumy += m*dy;
            sum  += m;
        }

    mx = (Double_t)sumx/sum;
    my = (Double_t)sumy/sum;

    return (int)my*768 + (int)mx;
}

void Filter2::Execute(MStarList &list, byte *img)
{
    const int offset = 10;

    int max;
    int min;

    const float mean = Mean(img, offset, &min, &max);
    const float sdev = SDev(img, offset, mean);

    const float cut = mean + 2.5*sdev;

    //
    // clean image from noise
    //
    for (int x=0; x<768; x++)
        for (int y=0; y<576; y++)
        {
            if (img[y*768+x]>cut)
                continue;

            //
            // FIXME: Create LOOKUP Table!
            //

            img[y*768+x] = 0;
        }

    //
    // find mean points
    //
    const int maxpnt = 1000; //0x1000;

    int cnt = 0;

    for (int x=offset; x<768-offset; x++)
    {
        for (int y=offset; y<576-offset; y++)
        {
            if (img[x+768*y]==0)
                continue;

            Double_t mx, my;
            GetMeanPosition(img, x, y, 5, mx, my);

            list.Add(mx, my, 0);

            if (cnt++==maxpnt)
                break;
        }
        if (cnt==maxpnt)
        {
            cout << "Error! More than " << maxpnt << " stars found." << endl;
            break;
        }
    }

    //
    // Search first
    //
    list.RemoveTwins(5);

    byte marker[768*576];
    memset(marker, 0, 768*576);

    //
    // Draw marker for found stars into picture
    //
    MStarListIter Next(&list);
    MStar *pos;
    while ((pos=Next()))
    {
        int px = (int)pos->GetX()%768;
        int py = (int)pos->GetY()/768;

        MarkPoint(px, py, marker, 0xff); // color = white
    }

    //
    // Copy markers into image
    //
    for (int x=0; x<768*576; x++)
        if (marker[x])
            img[x]=marker[x];
}

