#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <algorithm>
#include <assert.h>
#include "background.h"

Background::Background()
{
    bg_xmin = 0.0;
    bg_ymin = 0.0;
    bg_lx = 0.0;
    bg_ly = 0.0;
}

Background::Background(double xmin, double ymin, double lx, double ly)
{
    row_pointers = NULL;

    bg_xmin = xmin;
    bg_ymin = ymin;
    bg_lx = lx;
    bg_ly = ly;
}

Background::Background(char* image_name, int type, double xmin, double ymin, double lx, double ly)
{
    char header[8];    // 8 is the maximum size that can be checked
            
    image_type = type;
    bg_xmin = xmin;
    bg_ymin = ymin;
    bg_lx = lx;
    bg_ly = ly;

    /* open file and test for it being a png */
    FILE *fp = fopen(image_name, "rb");
    if (!fp)
        printf("[read_png_file] File %s could not be opened for reading\n", image_name);
    if (!fread(header, 1, 8, fp))
        printf("[read_png_file] File %s can't be read\n", image_name);
//         if (png_sig_cmp(header, 0, 8))
//                 printf("[read_png_file] File %s is not recognized as a PNG file\n", file_name);

    /* initialize stuff */
    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

    if (!png_ptr)
        printf("[read_png_file] png_create_read_struct failed\n");

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
        printf("[read_png_file] png_create_info_struct failed\n");

    if (setjmp(png_jmpbuf(png_ptr)))
        printf("[read_png_file] Error during init_io\n");

    /* initialize stuff */
    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    info_ptr = png_create_info_struct(png_ptr);
    png_init_io(png_ptr, fp);
    png_set_sig_bytes(png_ptr, 8);

//     printf("read infos\n");
    png_read_info(png_ptr, info_ptr);

    width = png_get_image_width(png_ptr, info_ptr);
//     printf("%d\n", width);
    height = png_get_image_height(png_ptr, info_ptr);
//     printf("%d\n", height);
    color_type = png_get_color_type(png_ptr, info_ptr);
    bit_depth = png_get_bit_depth(png_ptr, info_ptr);

    number_of_passes = png_set_interlace_handling(png_ptr);
    png_read_update_info(png_ptr, info_ptr);

    /* read file */
    row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
    for (int y=0; y<height; y++)
        row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));

    png_read_image(png_ptr, row_pointers);

    fclose(fp);
}

double Background::get_size(double *vx)
{
    double size = 0.0;
    int r, g, b, a;
    double ng; 
    png_byte* ptr = NULL;
    
    if (row_pointers == NULL)
    {
        if (vx[0] >= bg_xmin && vx[0] <= (bg_xmin+bg_lx) && vx[1] >= bg_ymin && vx[1] <= (bg_ymin+bg_ly))
        {
            // line
//         size = fabs(vx[0]-(2*bg_xmin+bg_lx)/2.0)/10.;

          // cross
//         size = std::min(fabs(vx[0]-(2*bg_xmin+bg_lx)/2.0), fabs(vx[1]-(2*bg_ymin+bg_ly)/2.0)) / 5.;

            // crosslines
//             int div = 5;
//             const double ddx = bg_lx/(double)div;
//             const double ddy = bg_ly/(double)div;
//             double xx = floor((vx[0]-bg_xmin)/ddx);
//             double yy = floor((vx[1]-bg_ymin)/ddy);
//             size = std::min(std::min(fabs(vx[0]-(bg_xmin+xx*ddx)), fabs(vx[0]-(bg_xmin+(xx+1.0)*ddx))), std::min(fabs(vx[1]-(bg_ymin+yy*ddy)), fabs(vx[1]-(bg_ymin+(yy+1.0)*ddy)))) / 4.;

//             // sin cos
            double xx = ((vx[0]-bg_xmin)/bg_lx)*2.0*M_PI;
            double yy = ((vx[1]-bg_ymin)/bg_ly)*2.0*M_PI;
            size = (cos(xx)+sin(yy))/4.0;

            // circle
//             double xx = vx[0]-(2*bg_xmin+bg_lx)/2.0;
//             double yy = vx[1]-(2*bg_ymin+bg_ly)/2.0;
//             size = (xx*xx + yy*yy - 9.0)/50.0;
	    
        }
    }
    else
    {
        if (vx[0] >= bg_xmin && vx[0] <= (bg_xmin+bg_lx) && vx[1] >= bg_ymin && vx[1] <= (bg_ymin+bg_ly))
        {
            int x = (int)floor( (vx[0]/bg_lx)*(double)width );
            int y = (int)floor( (vx[1]/bg_ly)*(double)height);

            assert(x >= 0 && x < width);
            assert(y >= 0 && y < height);

            png_byte* row = row_pointers[y];

            // Gris = 0,2125 \cdot Rouge + 0,7154 \cdot Vert + 0,0721 \cdot Bleu
            // Gris = 54 * r + 183 * g + 19 * b;

            double cr = 0.2109;
            double cv = 0.7148;
            double cb = 0.0742;

            switch (image_type)
            {
            case 0:
                ptr = &(row[x*3]);
                r = ptr[0];
                g = ptr[1];
                b = ptr[2];
// 	    printf("%d %d %d\n", r, g, b);
                ng = cr * (double)r + cv * (double)g + cb * (double)b;
                break;
            case 1:
                ptr = &(row[x*4]); //--> alpha
                r = ptr[0];
                g = ptr[1];
                b = ptr[2];
                a = ptr[3];    // --> alpha
// 		printf("%d %d %d %d\n", r, g, b, a);
                ng = cr * (double)r + cv*(double)g + cb*(double)b;
                break;
            case 2:
                ptr = &(row[x]);
                ng = (double)ptr[0];
                break;
            }
            size = ng / 256.0;
// 	printf("ng --> %d\n", ng);
// 	    size /= 3.0;
        }
    }
    
    return size;
}

double Background::get_angle(double *vx)
{
    double angle;
    
    double xx = ((vx[0]-bg_xmin)/bg_lx)*0.5*M_PI;
    double yy = ((vx[1]-bg_ymin)/bg_ly)*0.5*M_PI;
    angle = xx;
    return angle/1.;
    return 0.0;
}