#include "squid_class.h"
#include "squid_functions.h"
#include <iostream.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <graphics/gfxmacros.h>

#define BLACK 0x0FFFFFFF
#define WHITE 0xFFFFFFFF
#define RMAX 4
#define RMIN 1
#define XOFFSET 30
#define YOFFSET 50
#define WIDTH 640
#define HEIGHT 480

Object *winobj=NULL;

struct Window *win=NULL;
struct RastPort winport_noir;
struct RastPort winport_gris;
struct RastPort winport_blanc;
struct RastPort winport_rouge;
struct RastPort winport_vert;
struct RastPort winport_bleu;
struct RastPort *winport=NULL;
struct IntuiMessage *msg=NULL;
struct AreaInfo areainfo;
struct TmpRas tmpras;

PLANEPTR bitplane;

ULONG noir=0;
ULONG gris=0;
ULONG blanc=0;
ULONG rouge=0;
ULONG vert=0;
ULONG bleu=0;
ULONG color=0;
ULONG input=0L, code=0L;

void Window1_CloseWindow_Event(void)
{
    DoMethod(winobj, WM_CLOSE);
    win=NULL;
    winobj=NULL;
    Emperor_QuitProgram();
}

void Startup(void)
{
    noir = ObtainBestPen(Screen1->ViewPort.ColorMap, BLACK, BLACK, BLACK, OBP_Precision, PRECISION_EXACT, TAG_DONE);
    blanc = ObtainBestPen(Screen1->ViewPort.ColorMap, WHITE, WHITE, WHITE, OBP_Precision, PRECISION_EXACT, TAG_DONE);
    rouge = ObtainBestPen(Screen1->ViewPort.ColorMap, WHITE, BLACK, BLACK, OBP_Precision, PRECISION_EXACT, TAG_DONE);
    vert = ObtainBestPen(Screen1->ViewPort.ColorMap, BLACK, WHITE, BLACK, OBP_Precision, PRECISION_EXACT, TAG_DONE);
    bleu = ObtainBestPen(Screen1->ViewPort.ColorMap, BLACK, BLACK, WHITE, OBP_Precision, PRECISION_EXACT, TAG_DONE);

}

void Shutdown(void)
{
    ReleasePen(Screen1->ViewPort.ColorMap, noir);
    ReleasePen(Screen1->ViewPort.ColorMap, blanc);
    ReleasePen(Screen1->ViewPort.ColorMap, rouge);
    ReleasePen(Screen1->ViewPort.ColorMap, vert);
    ReleasePen(Screen1->ViewPort.ColorMap, bleu);
}

void Button1_GadgetUp_Event(void)
{
    int s=0, x=0, y=0, cx=0, cy=0, i=0, j=0, r=0, r_diff=0, temp=0, r_temp=0,
    mousex=0, mousey=0, diametre=0, countmax=0, maxx=0, maxy=0, color=0,
    temp_x=0, temp_y=0, cx_min=0, cy_min=0, nbrx=0, nbry=0, target=0, ii=0,
    min=0, iii=0, iiii=0, squid_selected=0, total=0;
    float norm=0.0;
    srand((unsigned) time (NULL));
    total=(WIDTH*HEIGHT*5)/2;

    Cell *C = (Cell*) malloc (squid_cell*sizeof(Cell));    
    //float *D = (float*) malloc (sizeof(float));
    //int *ID = (int*) malloc (sizeof(int));

    if(C==NULL)
    {
        cout <<"erreur d'allocation\n";
    }
    else
    {
        s = 0;
        diametre = 2*RMAX;
        xsize=(diametre*int(ceil(sqrt(squid_cell))));
        ysize=xsize;
        xsize=xsize+XOFFSET;
        UWORD buffer[(WIDTH*HEIGHT*5)/2];
        Emperor_SetGadgetAttr(String2, inttostring(xsize));
        Emperor_SetGadgetAttr(String3, inttostring(ysize));
        Emperor_SetGadgetAttr(String1, "click on the output window");

        winobj = (Object*) WindowObject,
            WA_Left,    100,
            WA_Top,     100,
            WA_Width,   xsize,
            WA_Height,  ysize,
            WA_DragBar, TRUE,
            //WA_Title,   "Sortie graphique",
            WA_PubScreen, Screen1,
            //WA_CloseGadget,  TRUE,
            WA_DepthGadget, TRUE,
            WA_SuperBitMap, TRUE,
            WA_IDCMP,  IDCMP_GADGETDOWN | IDCMP_GADGETUP | IDCMP_GADGETHELP | IDCMP_MENUPICK | IDCMP_MENUHELP | IDCMP_CLOSEWINDOW | IDCMP_ACTIVEWINDOW | IDCMP_INACTIVEWINDOW | IDCMP_RAWKEY | IDCMP_VANILLAKEY | IDCMP_MOUSEBUTTONS | IDCMP_MOUSEMOVE | IDCMP_NEWSIZE | IDCMP_CHANGEWINDOW | IDCMP_SIZEVERIFY | IDCMP_REFRESHWINDOW | IDCMP_INTUITICKS,
            WA_RMBTrap, TRUE,
        EndWindow;
        win = RA_OpenWindow (winobj);
        winport_noir = *win->RPort;
        winport_gris = *win->RPort;
        winport_blanc = *win->RPort;
        winport_rouge = *win->RPort;
        winport_vert = *win->RPort;
        winport_bleu = *win->RPort;
        winport = win->RPort;
        gris = ReadPixel(&winport_gris, 10, 10);
        SetAPen( &winport_gris, gris );
        SetAPen( &winport_noir, noir );
        SetAPen( &winport_blanc, blanc );
        SetAPen( &winport_rouge, rouge );
        SetAPen( &winport_vert, vert );
        SetAPen( &winport_bleu, bleu );
        SetGadgetAttrs(Integer1, Window1, NULL, GA_Disabled, TRUE, TAG_DONE);
        SetGadgetAttrs(Label1, Window1, NULL, GA_Disabled, TRUE, TAG_DONE);
        SetGadgetAttrs(Button1, Window1, NULL, GA_Disabled, TRUE, TAG_DONE);
        SetGadgetAttrs(Button2, Window1, NULL, GA_Disabled, TRUE, TAG_DONE);

        InitArea(&areainfo, buffer, HEIGHT);
        bitplane = AllocRaster(WIDTH, HEIGHT);
        if(bitplane==NULL)
        {
            cout <<"erreur du bitplane" <<endl;
        }
        InitTmpRas(&tmpras, bitplane, RASSIZE(WIDTH, HEIGHT));
        winport_noir.AreaInfo=&areainfo;
        winport_noir.TmpRas=&tmpras;
        winport_gris.AreaInfo=&areainfo;
        winport_gris.TmpRas=&tmpras;
        winport_blanc.AreaInfo=&areainfo;
        winport_blanc.TmpRas=&tmpras;
        winport_rouge.AreaInfo=&areainfo;
        winport_rouge.TmpRas=&tmpras;
        winport_vert.AreaInfo=&areainfo;
        winport_vert.TmpRas=&tmpras;
        winport_bleu.AreaInfo=&areainfo;
        winport_bleu.TmpRas=&tmpras;

        for(y = 0; y < ysize-(YOFFSET/2); y += diametre)
        {
            for(x = 0; x < xsize-(XOFFSET/2); x += diametre)
            {
                if(s==squid_cell)
                {
                    goto stop;
                }                
                C[s].set_cx(x);
                C[s].set_cy(y);
                r_temp=(rand()%(RMAX+1));
                C[s].set_r_temp(r_temp);
                C[s].set_ID(s);
                color=rand()%5;
                C[s].set_color(color);
                switch(color)
                {
                    case 0:
                        winport=&winport_noir;
                        break;
                    case 1:
                        winport=&winport_blanc;
                        break;
                    case 2:
                        winport=&winport_rouge;
                        break;
                    case 3:
                        winport=&winport_vert;
                        break;
                    case 4:
                        winport=&winport_bleu;
                        break;
                    default:
                        break;
                }
                AreaCircle(winport, C[s].get_cx()+(XOFFSET/2), C[s].get_cy()+(YOFFSET/2), RMIN);
                AreaEnd(winport);
                s++;
            }
        }
        stop:

        //cout <<"allocation de " <<s <<" objets effectuée\n";
        //cout <<"la mémoire utilisée est de " <<s*sizeof(Cell) <<" octets\n";

        do
        {
            for(s=0; s<squid_cell; s++)
            {
                if(C[s].get_update())
                {
                    Cell *C_selected = (Cell*) malloc (sizeof(Cell));
                    if(C_selected==NULL)
                    {
                        cout <<"erreur d'allocation" <<endl;
                    }
                    else
                    {
                        color=C[s].get_color();
                        switch(color)
                        {
                            case 0:
                                winport=&winport_noir;
                                break;
                            case 1:
                                winport=&winport_blanc;
                                break;
                            case 2:
                                winport=&winport_rouge;
                                break;
                            case 3:
                                winport=&winport_vert;
                                break;
                            case 4:
                                winport=&winport_bleu;
                                break;
                            default:
                                break;
                        }

                        ii=0;
                        for(i=0; i<squid_cell; i++)
                        {
                            if(C[i].get_color()==color)
                            {
                                temp_x=C[i].get_cx()-C[s].get_cx();      //obligé d'utiliser un intermédiaire sinon bug
                                temp_y=C[i].get_cy()-C[s].get_cy();      //idem
                                norm = sqrt ( (temp_x*temp_x) + (temp_y*temp_y) );
                                C[i].set_distance(norm);
                                C_selected[ii]=C[i];
                                ii++;
                                C_selected = (Cell*) realloc (C_selected, (ii+1)*sizeof(Cell));
                            }
                        }
                        squid_selected=ii;

                        for(i=0; i<squid_selected-1; i++)
                        {
                            Cell temp;
                            if(C_selected[i].get_distance()>C_selected[i+1].get_distance())
                            {
                                temp=C_selected[i];
                                C_selected[i]=C_selected[i+1];
                                C_selected[i+1]=temp;
                                for(ii=i; ii>=1; ii--)
                                {
                                    if(C_selected[ii-1].get_distance()<C_selected[ii].get_distance())
                                    {
                                        goto escape;
                                    }
                                    else
                                    {
                                        temp=C_selected[ii-1];
                                        C_selected[ii-1]=C_selected[ii];
                                        C_selected[ii]=temp;
                                    }
                                }
                                escape:
                            }
                        }

                        for(r=RMIN; r<=RMAX; r++)
                        {
                            for(i=0; i<squid_selected; i++)
                            {
                                AreaCircle(&winport_gris, C_selected[i].get_cx()+(XOFFSET/2), C_selected[i].get_cy()+(YOFFSET/2), r-1);
                                AreaEnd(&winport_gris);
                                if(r!=RMAX)
                                {
                                    AreaCircle(winport, C_selected[i].get_cx()+(XOFFSET/2), C_selected[i].get_cy()+(YOFFSET/2), r);
                                    AreaEnd(winport);
                                }
                                else
                                {
                                    goto arriere;
                                }
                            }
                        }
                        arriere:
                        for(r=RMAX-1; r>=RMIN; r--)
                        {
                            for(i=0; i<squid_selected; i++)
                            {
                                AreaCircle(&winport_gris, C_selected[i].get_cx()+(XOFFSET/2), C_selected[i].get_cy()+(YOFFSET/2), r+1);
                                AreaEnd(&winport_gris);
                                AreaCircle(winport, C_selected[i].get_cx()+(XOFFSET/2), C_selected[i].get_cy()+(YOFFSET/2), r);
                                AreaEnd(winport);
                            }
                        }
                        C[s].set_update(FALSE);
                    }
                    free(C_selected);
                }
            }
            while(msg = (struct IntuiMessage*) GetMsg(win->UserPort))
            {
                switch(msg->Class)
                {
                    case IDCMP_MOUSEBUTTONS:
                        switch (msg->Code)
                        {
                            case SELECTDOWN:
                                mousex=win->MouseX-(XOFFSET/2);
                                mousey=win->MouseY-(YOFFSET/2);
                                cx_min=1000;
                                cy_min=1000;
                                for(s=0; s<squid_cell; s++)
                                {
                                    temp_x = (mousex-C[s].get_cx());
                                    temp_y = (mousey-C[s].get_cy());
                                    temp_x = (temp_x < 0 ? -temp_x : temp_x);
                                    temp_y = (temp_y < 0 ? -temp_y : temp_y);
                                    if((temp_x<=cx_min) && (temp_y<=cy_min))
                                    {
                                        cx_min=temp_x;
                                        cy_min=temp_y;
                                        target=s
                                    }
                                }
                                C[target].set_update(TRUE);
                                break;
                            case SELECTUP:
                                break;
                            default:
                                break;
                        }
                    default:
                        break;
                }
            }
        }
        while(!IO_boucle());
        interruption:
        DoMethod(winobj, WM_CLOSE);
        win=NULL;
        winobj=NULL;        
        FreeRaster(bitplane, WIDTH, HEIGHT);
        free(C);
        SetGadgetAttrs(Integer1, Window1, NULL, GA_Disabled, FALSE, TAG_DONE);
        SetGadgetAttrs(Label1, Window1, NULL, GA_Disabled, FALSE, TAG_DONE);
        SetGadgetAttrs(Button1, Window1, NULL, GA_Disabled, FALSE, TAG_DONE);
        SetGadgetAttrs(Button2, Window1, NULL, GA_Disabled, FALSE, TAG_DONE);
    }
}

void Integer1_GadgetUp_Event(void)
{
    squid_cell = atoi(Emperor_GetGadgetAttr(Integer1));
}

void Button2_GadgetUp_Event(void)
{
    squid_cell = 10;
    SetGadgetAttrs(Integer1, Window1, NULL, INTEGER_Number, 10, TAG_DONE);
}

void Button3_GadgetUp_Event(void)
{
}
