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

#include <jpeglib.h>

#include "simplewidget.h"
#include "_jpeg.h"
#include "_types.h"

/* Enables or disables debug output */
#ifdef __DEBUG
#define __D(fmt, args...) fprintf(stderr, "JPEG Debug: " fmt, ## args)
#else
#define __D(fmt, args...)
#endif

#define __E(fmt, args...) fprintf(stderr, "JPEG Error: " fmt, ## args)


int jpeg_create(char *filename, _simplejpeg *jpegp)
{
    struct jpeg_decompress_struct cinfo;
    FILE * infile;
    JSAMPARRAY buffer;
    int pos;
    int row_stride;
    struct jpeg_error_mgr jerr;
    int x;
    unsigned short *dst;
    int r, g, b;

    infile = fopen(filename, "rb");

    if (infile == NULL) {
        __E("Failed to open image file [%s]\n", filename);
        return SIMPLEWIDGET_FAILURE;
    }

    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_decompress(&cinfo);
    jpeg_stdio_src(&cinfo, infile);
    jpeg_read_header(&cinfo, TRUE);

    jpeg_start_decompress(&cinfo);

    row_stride = cinfo.output_width * cinfo.output_components;

    buffer = (*cinfo.mem->alloc_sarray)
             ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);

    jpegp->bufp = malloc(row_stride * cinfo.output_height * 2 / 3);
    jpegp->w = cinfo.output_width;
    jpegp->h = cinfo.output_height;

    if (jpegp->bufp == NULL) {
        __E("Failed to allocate memory for jpeg image\n");
        return SIMPLEWIDGET_FAILURE;
    }

    dst = jpegp->bufp;

    while (cinfo.output_scanline < cinfo.output_height) {
        jpeg_read_scanlines(&cinfo, (JSAMPARRAY) buffer, 1);

        for (x = 0; x < cinfo.output_width; x++) {
//            __D("buffer[0][%d] = %#x\n", x, buffer[0][x]);
            if (cinfo.output_components == 1) { // Grayscale
                r = buffer[0][x] * (1<<5) / (1<<8);
                g = buffer[0][x] * (1<<6) / (1<<8);
                b = buffer[0][x] * (1<<5) / (1<<8);
            }
            else {                              // RGB
                pos = x * cinfo.output_components;
                r = buffer[0][pos + 0] * (1<<5) / (1<<8);
                g = buffer[0][pos + 1] * (1<<6) / (1<<8);
                b = buffer[0][pos + 2] * (1<<5) / (1<<8);
            }

            dst[x] = b | (g << 5) | (r << 11);
        }

        dst += cinfo.output_width;
    }

    jpeg_finish_decompress(&cinfo);
    fclose(infile);

    return SIMPLEWIDGET_SUCCESS;
}

int jpeg_show(_simplejpeg *jpegp, _simplescreen *scrp, int x, int y)
{
    __u16 *dst = scrp->bufp + y * scrp->w + x;
    __u16 *src = jpegp->bufp;
    int i, j;

    for (j=0; j<scrp->h && j<jpegp->h; j++) {
        for (i=0; i<scrp->w && i<jpegp->w; i++) {
            dst[i] = src[i];
        }
        dst += scrp->w;
        src += jpegp->w;
    }
    return SIMPLEWIDGET_SUCCESS;
}

int jpeg_delete(_simplejpeg *jpegp)
{
    free(jpegp->bufp);

    return SIMPLEWIDGET_SUCCESS;
}
