#include "DIPs.h"

#include "Constants.h"

#include "Image.h"



#include <string.h>

#include <stdlib.h>

#include <time.h>

#include <stdio.h>

#include <assert.h>




/* hw2 FILTERS                                  */



/* Black & White */

IMAGE *BlackNWhite(IMAGE *image) {

    assert(image);



    for (int y = 0; y < ImageHeight(image); y++) {

        for (int x = 0; x < ImageWidth(image); x++) {

            int gray = (GetPixelR(image, x, y) +

                        GetPixelG(image, x, y) +

                        GetPixelB(image, x, y)) / 3;



            SetPixelR(image, x, y, gray);
            SetPixelG(image, x, y, gray);
            SetPixelB(image, x, y, gray);

        }

    }

    return image;

}



/* Negative */

IMAGE *Negative(IMAGE *image) {

    assert(image);



    for (int y = 0; y < ImageHeight(image); y++) {

        for (int x = 0; x < ImageWidth(image); x++) {

            SetPixelR(image, x, y, MAX_PIXEL - GetPixelR(image, x, y));

            SetPixelG(image, x, y, MAX_PIXEL - GetPixelG(image, x, y));

            SetPixelB(image, x, y, MAX_PIXEL - GetPixelB(image, x, y));

        }

    }

    return image;

}



/* Color Filter */

IMAGE *ColorFilter(IMAGE *image, int target_r, int target_g, int target_b,

                    int threshold, int replace_r, int replace_g, int replace_b) {

    assert(image);



    for (int y = 0; y < ImageHeight(image); y++) {

        for (int x = 0; x < ImageWidth(image); x++) {

            if (abs(GetPixelR(image, x, y) - target_r) <= threshold &&

                abs(GetPixelG(image, x, y) - target_g) <= threshold &&

                abs(GetPixelB(image, x, y) - target_b) <= threshold) {



                SetPixelR(image, x, y, replace_r);
                SetPixelG(image, x, y, replace_g);
                SetPixelB(image, x, y, replace_b);

            }

        }

    }

    return image;

}



/* Edge Detection */

IMAGE *Edge(IMAGE *image) {

    assert(image);



    int width = ImageWidth(image);

    int height = ImageHeight(image);



    IMAGE *tmp = CopyImage(image);

    assert(tmp);



    for (int y = 1; y < height - 1; y++) {

        for (int x = 1; x < width - 1; x++) {



            int sumR = 8 * GetPixelR(tmp, x, y)

                - GetPixelR(tmp, x-1, y-1) - GetPixelR(tmp, x, y-1) - GetPixelR(tmp, x+1, y-1)

                - GetPixelR(tmp, x-1, y)   - GetPixelR(tmp, x+1, y)

                - GetPixelR(tmp, x-1, y+1) - GetPixelR(tmp, x, y+1) - GetPixelR(tmp, x+1, y+1);



            int sumG = 8 * GetPixelG(tmp, x, y)

                - GetPixelG(tmp, x-1, y-1) - GetPixelG(tmp, x, y-1) - GetPixelG(tmp, x+1, y-1)

                - GetPixelG(tmp, x-1, y)   - GetPixelG(tmp, x+1, y)

                - GetPixelG(tmp, x-1, y+1) - GetPixelG(tmp, x, y+1) - GetPixelG(tmp, x+1, y+1);



            int sumB = 8 * GetPixelB(tmp, x, y)

                - GetPixelB(tmp, x-1, y-1) - GetPixelB(tmp, x, y-1) - GetPixelB(tmp, x+1, y-1)

                - GetPixelB(tmp, x-1, y)   - GetPixelB(tmp, x+1, y)

                - GetPixelB(tmp, x-1, y+1) - GetPixelB(tmp, x, y+1) - GetPixelB(tmp, x+1, y+1);



            sumR = (sumR > 255) ? 255 : (sumR < 0 ? 0 : sumR);

            sumG = (sumG > 255) ? 255 : (sumG < 0 ? 0 : sumG);

            sumB = (sumB > 255) ? 255 : (sumB < 0 ? 0 : sumB);



            SetPixelR(image, x, y, sumR);
            SetPixelG(image, x, y, sumG);
            SetPixelB(image, x, y, sumB);

        }

    }



    DeleteImage(tmp);

    return image;

}



/* Vertical Mirror */

IMAGE *VMirror(IMAGE *image) {

    assert(image);



    int height = ImageHeight(image);



    for (int y = 0; y < height / 2; y++) {

        for (int x = 0; x < ImageWidth(image); x++) {

            int yy = height - 1 - y;



            unsigned char r = GetPixelR(image, x, y);

            unsigned char g = GetPixelG(image, x, y);

            unsigned char b = GetPixelB(image, x, y);



            SetPixelR(image, x, y, GetPixelR(image, x, yy));

            SetPixelG(image, x, y, GetPixelG(image, x, yy));

            SetPixelB(image, x, y, GetPixelB(image, x, yy));



            SetPixelR(image, x, yy, r);
            SetPixelG(image, x, yy, g);
            SetPixelB(image, x, yy, b);

        }

    }

    return image;

}




/* PART 2: ASSIGNMENT 3  */



/* Shuffle */

IMAGE *Shuffle(IMAGE *image) {

    assert(image);



    int width = ImageWidth(image);

    int height = ImageHeight(image);

    int block_width = width / SHUFF_WIDTH_DIV;

    int block_height = height / SHUFF_HEIGHT_DIV;



    srand(time(NULL));



    for (int i = 0; i < SHUFF_NUM; i++) {

        int block1 = rand() % (SHUFF_WIDTH_DIV * SHUFF_HEIGHT_DIV);

        int block2 = rand() % (SHUFF_WIDTH_DIV * SHUFF_HEIGHT_DIV);



        int x1 = (block1 % SHUFF_WIDTH_DIV) * block_width;

        int y1 = (block1 / SHUFF_WIDTH_DIV) * block_height;



        int x2 = (block2 % SHUFF_WIDTH_DIV) * block_width;

        int y2 = (block2 / SHUFF_WIDTH_DIV) * block_height;



        for (int y = 0; y < block_height; y++) {

            for (int x = 0; x < block_width; x++) {

                unsigned char r = GetPixelR(image, x1 + x, y1 + y);

                unsigned char g = GetPixelG(image, x1 + x, y1 + y);

                unsigned char b = GetPixelB(image, x1 + x, y1 + y);



                SetPixelR(image, x1 + x, y1 + y, GetPixelR(image, x2 + x, y2 + y));

                SetPixelG(image, x1 + x, y1 + y, GetPixelG(image, x2 + x, y2 + y));

                SetPixelB(image, x1 + x, y1 + y, GetPixelB(image, x2 + x, y2 + y));



                SetPixelR(image, x2 + x, y2 + y, r);
                SetPixelG(image, x2 + x, y2 + y, g);
                SetPixelB(image, x2 + x, y2 + y, b);

            }

        }

    }



    return image;

}



/* Add Border */

IMAGE *AddBorder(IMAGE *image, char color[SLEN], int border_width) {

    assert(image);



    int r = 0, g = 0, b = 0;



    if (strcmp(color, "black") == 0)       { r = g = b = 0;   }

    else if (strcmp(color, "white") == 0)  { r = g = b = 255; }

    else if (strcmp(color, "red") == 0)    { r = 255; g = 0;   b = 0;   }

    else if (strcmp(color, "green") == 0)  { r = 0;   g = 255; b = 0;   }

    else if (strcmp(color, "blue") == 0)   { r = 0;   g = 0;   b = 255; }

    else if (strcmp(color, "yellow") == 0) { r = 255; g = 255; b = 0;   }

    else if (strcmp(color, "cyan") == 0)   { r = 0;   g = 255; b = 255; }

    else if (strcmp(color, "pink") == 0)   { r = 255; g = 0;   b = 255; }



    for (int y = 0; y < ImageHeight(image); y++) {

        for (int x = 0; x < ImageWidth(image); x++) {

            if (x < border_width || x >= ImageWidth(image) - border_width ||

                y < border_width || y >= ImageHeight(image) - border_width) {

                SetPixelR(image, x, y, r);
                SetPixelG(image, x, y, g);
                SetPixelB(image, x, y, b);

            }

        }

    }



    return image;

}