/*
 *  Libjpeg interface routines.
 *  We support JPEG decompress interface only.
 */
#include <t_services.h>
#include "lcd.h"
#include "./jpeg/jpeglib.h"
#include "ff.h"
#include "kernel_id.h"
#include "mempool.h"

/*
 *  For better decompress speed and less required memory,
 *  We limit the JPEG image display are to PIC_WIDTH X PIC_HEIGHT.
 */
#define	PIC_WIDTH	240
#define	PIC_HEIGHT	180

struct jpeg_error_mgr jerr;
struct jpeg_error_mgr *jpeg_jsp_error (struct jpeg_error_mgr * err);

struct jpeg_decompress_struct dcinfo;

static FIL jpeg_file;

FIL *open_jpeg_file(char *fname)
{
    FRESULT result;

    result = f_open(&jpeg_file, fname, FA_READ);
    if (result != FR_OK) {
        cons_printf("failed to open JPEG file %s.\n", fname);
        return NULL;
    }
    return &jpeg_file;
}

void close_jpeg_file(FIL *fptr)
{
    f_close(fptr);
}

static int exp_mode = 1;

int expand_jpeg(char *fname, int mode)
{
    SYSTIM time1, time2;
    int fsize;
    int denom, scale;
    FIL *fptr;
    JSAMPARRAY buffer;
    int row_stride;
    int xoffset, yoffset;
    int maxw, maxh;

    if ((exp_mode == 0) && (mode >= 0))
        return 0;

    pool_init();
    fptr = open_jpeg_file(fname);
    if (!fptr)
        return 1;
    get_tim(&time1);
    dcinfo.err = jpeg_jsp_error(&jerr);
    jpeg_create_decompress(&dcinfo);
    jpeg_fatfs_src(&dcinfo, fptr);

    jpeg_read_header(&dcinfo, TRUE);
    maxw = maxh = 100;
    if (mode > 0) {
        maxw = PIC_WIDTH * 8;
        maxh = PIC_HEIGHT * 8;
    }
    if ((dcinfo.image_width > maxw) || (dcinfo.image_height > maxh)) {
        /* Image is too big */
        jpeg_destroy_decompress(&dcinfo);
        close_jpeg_file(fptr);
        return 0;
    }
    dcinfo.scale_denom = dcinfo.scale_num = 8;
    denom = 8;
    for (scale = 8; scale > 1; scale--) {
        if (dcinfo.image_width / denom * scale <= PIC_WIDTH)
            break;
    }
    while (dcinfo.image_height/denom * scale > PIC_HEIGHT) {
        scale--;
    }
    if (scale > 0) {
        dcinfo.scale_num = scale;
        dcinfo.out_color_space = JCS_RGB;
        dcinfo.dct_method = JDCT_ISLOW;
        jpeg_calc_output_dimensions(&dcinfo);
        syslog(LOG_NOTICE, "%d x %d --> %d x %d",
                dcinfo.image_width, dcinfo.image_height,
                dcinfo.output_width, dcinfo.output_height);
        xoffset = yoffset = 0;
        if (dcinfo.output_width != PIC_WIDTH || dcinfo.output_height != PIC_HEIGHT) {
            if (mode > 0) {
                /* Center the picture */
                xoffset = (PIC_WIDTH - dcinfo.output_width) >> 1;
                yoffset = (PIC_HEIGHT - dcinfo.output_height) >> 1;
                /* Past background with black color */
                lcd_reset_window();
                lcd_fill_rect(0, 0, PIC_WIDTH, PIC_HEIGHT, C_BLACK);
            } else {
                lcd_reset_window();
                xoffset = AIMAGE_X;
                yoffset = AIMAGE_Y;
            }
        }
        jpeg_start_decompress(&dcinfo);

        row_stride = dcinfo.output_width * dcinfo.output_components;
        buffer = (*dcinfo.mem->alloc_sarray)((j_common_ptr)&dcinfo, JPOOL_IMAGE, row_stride, 1);
        while (dcinfo.output_scanline < dcinfo.output_height) {
            jpeg_read_scanlines(&dcinfo, buffer, 1);
            if (mode >= 0) {
                draw_lcd_line(buffer[0], xoffset, yoffset + dcinfo.output_scanline, dcinfo.output_width);
            }
        }
        pool_stat();

        jpeg_finish_decompress(&dcinfo);
    }
    jpeg_destroy_decompress(&dcinfo);
    get_tim(&time2);
    close_jpeg_file(fptr);
    syslog(LOG_NOTICE, "Took %d ms.", time2 - time1);
    return 1;
}

void expand_command(int argc, char **argv)
{
    char *fname;

    fname = "/PIC001.JPG";
    if (argc > 1) {
        fname = argv[1];
    }
    if (strncmp(fname, "start", 5) == 0) {
        exp_mode = 1;
    } else if (strncmp(fname, "stop", 4) == 0) {
        exp_mode = 0;
    } else {
        expand_jpeg(fname, -1);
    }
}

#ifdef USE_SLIDE
static DIR	Dir_Object;
static FILINFO finfo;

void slide_command(int argc, char **argv)
{
    FRESULT result;
    char *fn;

    lcd_clear_screen(0);
    result = f_opendir(&Dir_Object, "/");
    if (result != FR_OK) {
        cons_printf("f_opendir --> RESULT = %d\n", result);
        return;
    }

#if _USE_LFN
    finfo.lfname = lfn;
    finfo.lfsize = sizeof(lfn);
#endif
    while ((f_readdir(&Dir_Object, &finfo) == FR_OK) &&
                finfo.fname[0]) {
#if _USE_LFN
        fn = *finfo.lfname? finfo.lfname : finfo.fname;
#else
        fn = finfo.fname;
#endif
        if (!(finfo.fattrib & AM_DIR)) {
            expand_jpeg(fn, 1);
            dly_tsk(1000 * 3);
        }
    }
    lcd_clear_screen(0);
}
#endif
