#include <loadjpeg.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <stdlib.h>
#include <stdint.h>
extern "C" {
#include <mjpegdec.h>
}


#define USE_MMAP


Image loadJpegFile(const char *filename)
{
//    printf("loading file\n");
    int data_size = 0;
    FILE *f = fopen(filename, "r");
    fseek(f, 0, SEEK_END);
    data_size = ftell(f);
    fseek(f, 0, SEEK_SET);
    printf("size is %i bytes\n", data_size);
    fclose(f);
    
    assert( data_size < 2000000 );

#ifdef USE_MMAP
    int fd = open(filename, O_RDONLY);
    uint8_t *data = (uint8_t *)mmap(0, data_size, PROT_READ, MAP_SHARED, fd, 0);
#else
    uint8_t *data = (uint8_t *)malloc(data_size);
    if ( fread(data, 1, data_size, f) != data_size )
        printf("error reading it all in\n");
#endif

//    printf("read in %i bytes of jpeg file\n", data_size);
    int i;
    for(i=0;i<256;i++)
        ff_cropTbl[i + MAX_NEG_CROP] = i;
    for(i=0;i<MAX_NEG_CROP;i++) {
        ff_cropTbl[i] = 0;
        ff_cropTbl[i + MAX_NEG_CROP + 256] = 255;
    }
    AVCodecContext *avctx = (AVCodecContext*)malloc(sizeof(AVCodecContext));
    memset(avctx, 0, sizeof(AVCodecContext));
    MJpegDecodeContext *s = (MJpegDecodeContext*)malloc(sizeof(MJpegDecodeContext));
    memset(s, 0, sizeof(MJpegDecodeContext));
    avctx->priv_data = s;
    ff_mjpeg_decode_init(avctx);
//    printf("init\n");

    ff_mjpeg_decode_frame(avctx, 0, 0, data, data_size);
//    printf("decoded\n");

/*
    ff_mjpeg_decode_end(avctx);
    free(data);
    fseek(f, 0, SEEK_SET);
    data = (uint8_t *)malloc(data_size);
    if ( fread(data, 1, data_size, f) != data_size )
        printf("error reading it all in\n");
    //memset(s, 0, sizeof(MJpegDecodeContext));
    //memset(avctx, 0, sizeof(AVCodecContext));
    ff_mjpeg_decode_init(avctx);
    printf("read in %i bytes of jpeg file\n", data_size);
    ff_mjpeg_decode_frame(avctx, 0, 0, data, data_size);
    printf("decoded\n");
*/
    assert(s->width < 4096);
    assert(s->height < 4096);

    AVPicture YuvPic = *(AVPicture*)&s->picture;
    AVPicture pic;
    assert( (s->width*s->height*4) < 5000000 );
    pic.data[0] = (unsigned char *)malloc(s->width*s->height*4);
    pic.linesize[0] = s->width*4;
    pic.width = s->width;
    pic.height = s->height;
    if ( avctx->pix_fmt == PIX_FMT_YUVJ444P )
        yuvj444p_to_rgb32(&pic, &YuvPic, s->width, s->height);
    else if ( avctx->pix_fmt == PIX_FMT_YUVJ420P )
        yuvj420p_to_rgb32(&pic, &YuvPic, s->width, s->height);
    else
        printf("unknown color format\n");
//    printf("color converted\n");

    ff_mjpeg_decode_end(avctx);
    free(s);
    free(avctx);
#ifdef USE_MMAP
    munmap(data, data_size);
    close(fd);
#else
    free(data);
#endif
    free(YuvPic.data[0]);
    free(YuvPic.data[1]);
    free(YuvPic.data[2]);
    Image img(pic.width, pic.height, pic.data[0], Format_ARGB_8888, pic.linesize[0]);
    return img;
}


