#include <stdio.h>
#include <stdlib.h>

#define HEADER_SIZE 54
#define WIDTH_POS 18 
#define HEIGHT_POS 22

typedef struct pixel_st {
    unsigned char B;
    unsigned char G;
    unsigned char R;
} PIXEL;

FILE *safe_fopen(char *, char *);
unsigned examine_header(FILE *, unsigned char *);
void read_bitmap(FILE *, PIXEL *, int);
void to_grayscale(PIXEL *, int);
void write_bitmap(FILE *, unsigned char *, PIXEL *, int);

int main(int argc, char **argv) {
    FILE *pin_bmp, *pres_bmp;

    if(argc != 3) {
        puts("Example call: ./a.out in.bmp out.bmp");
        exit(EXIT_FAILURE);
    }

    pin_bmp = safe_fopen(argv[1], "rb");
    unsigned char header[HEADER_SIZE];
    unsigned size = examine_header(pin_bmp, header);

    PIXEL pixels[size];
    read_bitmap(pin_bmp, pixels, size);
    fclose(pin_bmp);

    to_grayscale(pixels, size);

    pres_bmp = safe_fopen(argv[2], "wb");
    write_bitmap(pres_bmp, header, pixels, size);
    fclose(pres_bmp);

    return EXIT_SUCCESS;
}

FILE *safe_fopen(char *name, char *mode) {
    FILE *pf = fopen(name, mode);

    if(pf == NULL) {
        printf("File %s could not be opened!\n", name);
        exit(EXIT_FAILURE);
    }

    return pf;
}

unsigned examine_header(FILE *pin, unsigned char *header) {
    fread(header, sizeof(unsigned char), HEADER_SIZE, pin);

    unsigned width = *(unsigned *) &header[WIDTH_POS];
    unsigned height = *(unsigned *) &header[HEIGHT_POS];

    return width * height;
}

void read_bitmap(FILE *pin_bmp, PIXEL *pixels, int size) {
    fread(pixels, sizeof(PIXEL), size, pin_bmp);
}

void to_grayscale(PIXEL *pixels, int size) {
    int i;
    unsigned char avg;

    for(i = 0;i < size;i++) {
        avg = (pixels[i].B + pixels[i].G + pixels[i].R) / 3;

        pixels[i].B = avg;
        pixels[i].G = avg;
        pixels[i].R = avg;
    }
}

void write_bitmap(FILE *pres_bmp, unsigned char *header, PIXEL *pixels, int size) {
    fwrite(header, sizeof(unsigned char), HEADER_SIZE, pres_bmp);
    fwrite(pixels, sizeof(PIXEL), size, pres_bmp);
}
