/**
 * @file llimagejpeg.cpp
 *
 * $LicenseInfo:firstyear=2002&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "linden_common.h"
#include "stdtypes.h"

#include "llimagejpeg.h"

#include "llerror.h"
#include "llexception.h"

jmp_buf LLImageJPEG::sSetjmpBuffer ;
LLImageJPEG::LLImageJPEG(S32 quality)
:   LLImageFormatted(IMG_CODEC_JPEG),
    mOutputBuffer( NULL ),
    mOutputBufferSize( 0 ),
    mEncodeQuality( quality ) // on a scale from 1 to 100
{
}

LLImageJPEG::~LLImageJPEG()
{
    llassert( !mOutputBuffer ); // Should already be deleted at end of encode.
    delete[] mOutputBuffer;
}

bool LLImageJPEG::updateData()
{
    resetLastError();

    LLImageDataLock lock(this);

    // Check to make sure that this instance has been initialized with data
    if (!getData() || (0 == getDataSize()))
    {
        setLastError("Uninitialized instance of LLImageJPEG");
        return false;
    }

    ////////////////////////////////////////
    // Step 1: allocate and initialize JPEG decompression object

    // This struct contains the JPEG decompression parameters and pointers to
    // working space (which is allocated as needed by the JPEG library).
    struct jpeg_decompress_struct cinfo;
    cinfo.client_data = this;

    struct jpeg_error_mgr jerr;
    cinfo.err = jpeg_std_error(&jerr);

    // Customize with our own callbacks
    jerr.error_exit =       &LLImageJPEG::errorExit;            // Error exit handler: does not return to caller
    jerr.emit_message =     &LLImageJPEG::errorEmitMessage;     // Conditionally emit a trace or warning message
    jerr.output_message =   &LLImageJPEG::errorOutputMessage;   // Routine that actually outputs a trace or error message

    //
    //try/catch will crash on Mac and Linux if LLImageJPEG::errorExit throws an error
    //so as instead, we use setjmp/longjmp to avoid this crash, which is the best we can get. --bao
    //
    if(setjmp(sSetjmpBuffer))
    {
        jpeg_destroy_decompress(&cinfo);
        return false;
    }
    try
    {
        // Now we can initialize the JPEG decompression object.
        jpeg_create_decompress(&cinfo);

        ////////////////////////////////////////
        // Step 2: specify data source
        // (Code is modified version of jpeg_stdio_src();
        if (cinfo.src == NULL)
        {
            cinfo.src = (struct jpeg_source_mgr *)
                (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT,
                sizeof(struct jpeg_source_mgr));
        }
        cinfo.src->init_source  =       &LLImageJPEG::decodeInitSource;
        cinfo.src->fill_input_buffer =  &LLImageJPEG::decodeFillInputBuffer;
        cinfo.src->skip_input_data =    &LLImageJPEG::decodeSkipInputData;
        cinfo.src->resync_to_restart = jpeg_resync_to_restart; // For now, use default method, but we should be able to do better.
        cinfo.src->term_source =        &LLImageJPEG::decodeTermSource;

        cinfo.src->bytes_in_buffer =    getDataSize();
        cinfo.src->next_input_byte =    getData();

        ////////////////////////////////////////
        // Step 3: read file parameters with jpeg_read_header()
        jpeg_read_header( &cinfo, true );

        // Data set by jpeg_read_header
        setSize(cinfo.image_width, cinfo.image_height, 3); // Force to 3 components (RGB)

        /*
        // More data set by jpeg_read_header
        cinfo.num_components;
        cinfo.jpeg_color_space; // Colorspace of image
        cinfo.saw_JFIF_marker;      // true if a JFIF APP0 marker was seen
        cinfo.JFIF_major_version;   // Version information from JFIF marker
        cinfo.JFIF_minor_version;  //
        cinfo.density_unit;     // Resolution data from JFIF marker
        cinfo.X_density;
        cinfo.Y_density;
        cinfo.saw_Adobe_marker; // true if an Adobe APP14 marker was seen
        cinfo.Adobe_transform;     // Color transform code from Adobe marker
        */
    }
    catch (int)
    {
        jpeg_destroy_decompress(&cinfo);

        return false;
    }
    ////////////////////////////////////////
    // Step 4: Release JPEG decompression object
    jpeg_destroy_decompress(&cinfo);

    return true;
}

// Initialize source --- called by jpeg_read_header
// before any data is actually read.
void LLImageJPEG::decodeInitSource( j_decompress_ptr cinfo )
{
    // no work necessary here
}

// Fill the input buffer --- called whenever buffer is emptied.
boolean LLImageJPEG::decodeFillInputBuffer( j_decompress_ptr cinfo )
{
//  jpeg_source_mgr* src = cinfo->src;
//  LLImageJPEG* self = (LLImageJPEG*) cinfo->client_data;

    // Should never get here, since we provide the entire buffer up front.
    ERREXIT(cinfo, JERR_INPUT_EMPTY);

    return true;
}

// Skip data --- used to skip over a potentially large amount of
// uninteresting data (such as an APPn marker).
//
// Writers of suspendable-input applications must note that skip_input_data
// is not granted the right to give a suspension return.  If the skip extends
// beyond the data currently in the buffer, the buffer can be marked empty so
// that the next read will cause a fill_input_buffer call that can suspend.
// Arranging for additional bytes to be discarded before reloading the input
// buffer is the application writer's problem.
void LLImageJPEG::decodeSkipInputData (j_decompress_ptr cinfo, long num_bytes)
{
    jpeg_source_mgr* src = cinfo->src;
//  LLImageJPEG* self = (LLImageJPEG*) cinfo->client_data;

    src->next_input_byte += (size_t) num_bytes;
    src->bytes_in_buffer -= (size_t) num_bytes;
}

void LLImageJPEG::decodeTermSource (j_decompress_ptr cinfo)
{
  // no work necessary here
}


// Returns true when done, whether or not decode was successful.
bool LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
{
    llassert_always(raw_image);

    resetLastError();

    LLImageDataLock lockIn(this);
    LLImageDataLock lockOut(raw_image);

    // Check to make sure that this instance has been initialized with data
    if (!getData() || (0 == getDataSize()))
    {
        setLastError("LLImageJPEG trying to decode an image with no data!");
        return true;  // done
    }

    S32 row_stride = 0;
    U8* raw_image_data = NULL;

    ////////////////////////////////////////
    // Step 1: allocate and initialize JPEG decompression object

    // This struct contains the JPEG decompression parameters and pointers to
    // working space (which is allocated as needed by the JPEG library).
    struct jpeg_decompress_struct cinfo;

    struct jpeg_error_mgr jerr;
    cinfo.err = jpeg_std_error(&jerr);

    // Customize with our own callbacks
    jerr.error_exit =       &LLImageJPEG::errorExit;            // Error exit handler: does not return to caller
    jerr.emit_message =     &LLImageJPEG::errorEmitMessage;     // Conditionally emit a trace or warning message
    jerr.output_message =   &LLImageJPEG::errorOutputMessage;   // Routine that actually outputs a trace or error message

    //
    //try/catch will crash on Mac and Linux if LLImageJPEG::errorExit throws an error
    //so as instead, we use setjmp/longjmp to avoid this crash, which is the best we can get. --bao
    //
    if(setjmp(sSetjmpBuffer))
    {
        jpeg_destroy_decompress(&cinfo);
        return true; // done
    }
    try
    {
        // Now we can initialize the JPEG decompression object.
        jpeg_create_decompress(&cinfo);

        ////////////////////////////////////////
        // Step 2: specify data source
        // (Code is modified version of jpeg_stdio_src();
        if (cinfo.src == NULL)
        {
            cinfo.src = (struct jpeg_source_mgr *)
                (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT,
                sizeof(struct jpeg_source_mgr));
        }
        cinfo.src->init_source  =       &LLImageJPEG::decodeInitSource;
        cinfo.src->fill_input_buffer =  &LLImageJPEG::decodeFillInputBuffer;
        cinfo.src->skip_input_data =    &LLImageJPEG::decodeSkipInputData;
        cinfo.src->resync_to_restart = jpeg_resync_to_restart; // For now, use default method, but we should be able to do better.
        cinfo.src->term_source =        &LLImageJPEG::decodeTermSource;
        cinfo.src->bytes_in_buffer =    getDataSize();
        cinfo.src->next_input_byte =    getData();

        ////////////////////////////////////////
        // Step 3: read file parameters with jpeg_read_header()

        jpeg_read_header(&cinfo, true);

        // We can ignore the return value from jpeg_read_header since
        //   (a) suspension is not possible with our data source, and
        //   (b) we passed true to reject a tables-only JPEG file as an error.
        // See libjpeg.doc for more info.

        setSize(cinfo.image_width, cinfo.image_height, 3); // Force to 3 components (RGB)

        if (!raw_image->resize(getWidth(), getHeight(), getComponents()))
        {
            throw std::bad_alloc();
        }
        raw_image_data = raw_image->getData();


        ////////////////////////////////////////
        // Step 4: set parameters for decompression
        cinfo.out_color_components = 3;
        cinfo.out_color_space = JCS_RGB;


        ////////////////////////////////////////
        // Step 5: Start decompressor

        jpeg_start_decompress(&cinfo);
        // We can ignore the return value since suspension is not possible
        // with our data source.

        // We may need to do some setup of our own at this point before reading
        // the data.  After jpeg_start_decompress() we have the correct scaled
        // output image dimensions available, as well as the output colormap
        // if we asked for color quantization.
        // In this example, we need to make an output work buffer of the right size.

        // JSAMPLEs per row in output buffer
        row_stride = cinfo.output_width * cinfo.output_components;

        ////////////////////////////////////////
        // Step 6: while (scan lines remain to be read)
        //           jpeg_read_scanlines(...);

        // Here we use the library's state variable cinfo.output_scanline as the
        // loop counter, so that we don't have to keep track ourselves.

        // Move pointer to last line
        raw_image_data += row_stride * (cinfo.output_height - 1);

        while (cinfo.output_scanline < cinfo.output_height)
        {
            // jpeg_read_scanlines expects an array of pointers to scanlines.
            // Here the array is only one element long, but you could ask for
            // more than one scanline at a time if that's more convenient.

            jpeg_read_scanlines(&cinfo, &raw_image_data, 1);
            raw_image_data -= row_stride;  // move pointer up a line
        }

        ////////////////////////////////////////
        // Step 7: Finish decompression
        jpeg_finish_decompress(&cinfo);

        ////////////////////////////////////////
        // Step 8: Release JPEG decompression object
        jpeg_destroy_decompress(&cinfo);
    }

    catch (std::bad_alloc&)
    {
        setLastError( "Out of memory");
        jpeg_destroy_decompress(&cinfo);
        return true; // done
    }

    catch (int)
    {
        jpeg_destroy_decompress(&cinfo);
        return true; // done
    }

    // Check to see whether any corrupt-data warnings occurred
    if( jerr.num_warnings != 0 )
    {
        // TODO: extract the warning to find out what went wrong.
        setLastError( "Unable to decode JPEG image.");
        return true; // done
    }

    return true;
}


// Initialize destination --- called by jpeg_start_compress before any data is actually written.
// static
void LLImageJPEG::encodeInitDestination ( j_compress_ptr cinfo )
{
  LLImageJPEG* self = (LLImageJPEG*) cinfo->client_data;

  cinfo->dest->next_output_byte = self->mOutputBuffer;
  cinfo->dest->free_in_buffer = self->mOutputBufferSize;
}


//  Empty the output buffer --- called whenever buffer fills up.
//
//  In typical applications, this should write the entire output buffer
//  (ignoring the current state of next_output_byte & free_in_buffer),
//  reset the pointer & count to the start of the buffer, and return true
//  indicating that the buffer has been dumped.
//
//  In applications that need to be able to suspend compression due to output
//  overrun, a false return indicates that the buffer cannot be emptied now.
//  In this situation, the compressor will return to its caller (possibly with
//  an indication that it has not accepted all the supplied scanlines).  The
//  application should resume compression after it has made more room in the
//  output buffer.  Note that there are substantial restrictions on the use of
//  suspension --- see the documentation.
//
//  When suspending, the compressor will back up to a convenient restart point
//  (typically the start of the current MCU). next_output_byte & free_in_buffer
//  indicate where the restart point will be if the current call returns false.
//  Data beyond this point will be regenerated after resumption, so do not
//  write it out when emptying the buffer externally.

boolean LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo )
{
  LLImageJPEG* self = (LLImageJPEG*) cinfo->client_data;

  // Should very rarely happen, since our output buffer is
  // as large as the input to start out with.

  // Double the buffer size;
  S32 new_buffer_size = self->mOutputBufferSize * 2;
  U8* new_buffer = new(std::nothrow) U8[ new_buffer_size ];
  if (!new_buffer)
  {
    self->setLastError("Out of memory in LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo )");
    LLTHROW(LLContinueError("Out of memory in LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo )"));
  }
  memcpy( new_buffer, self->mOutputBuffer, self->mOutputBufferSize );   /* Flawfinder: ignore */
  delete[] self->mOutputBuffer;
  self->mOutputBuffer = new_buffer;

  cinfo->dest->next_output_byte = self->mOutputBuffer + self->mOutputBufferSize;
  cinfo->dest->free_in_buffer = self->mOutputBufferSize;
  self->mOutputBufferSize = new_buffer_size;

  return true;
}

//  Terminate destination --- called by jpeg_finish_compress
//  after all data has been written.  Usually needs to flush buffer.
//
//  NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
//  application must deal with any cleanup that should happen even
//  for error exit.
void LLImageJPEG::encodeTermDestination( j_compress_ptr cinfo )
{
    LLImageJPEG* self = (LLImageJPEG*) cinfo->client_data;

    LLImageDataLock lock(self);

    S32 file_bytes = (S32)(self->mOutputBufferSize - cinfo->dest->free_in_buffer);
    self->allocateData(file_bytes);

    memcpy( self->getData(), self->mOutputBuffer, file_bytes ); /* Flawfinder: ignore */
}

// static
void LLImageJPEG::errorExit( j_common_ptr cinfo )
{
    //LLImageJPEG* self = (LLImageJPEG*) cinfo->client_data;

    // Always display the message
    (*cinfo->err->output_message)(cinfo);

    // Let the memory manager delete any temp files
    jpeg_destroy(cinfo);

    // Return control to the setjmp point
    longjmp(sSetjmpBuffer, 1) ;
}

// Decide whether to emit a trace or warning message.
// msg_level is one of:
//   -1: recoverable corrupt-data warning, may want to abort.
//    0: important advisory messages (always display to user).
//    1: first level of tracing detail.
//    2,3,...: successively more detailed tracing messages.
// An application might override this method if it wanted to abort on warnings
// or change the policy about which messages to display.
// static
void LLImageJPEG::errorEmitMessage( j_common_ptr cinfo, int msg_level )
{
  struct jpeg_error_mgr * err = cinfo->err;

  if (msg_level < 0)
  {
      // It's a warning message.  Since corrupt files may generate many warnings,
      // the policy implemented here is to show only the first warning,
      // unless trace_level >= 3.
      if (err->num_warnings == 0 || err->trace_level >= 3)
      {
          (*err->output_message) (cinfo);
      }
      // Always count warnings in num_warnings.
      err->num_warnings++;
  }
  else
  {
      // It's a trace message.  Show it if trace_level >= msg_level.
      if (err->trace_level >= msg_level)
      {
          (*err->output_message) (cinfo);
      }
  }
}

// static
void LLImageJPEG::errorOutputMessage( j_common_ptr cinfo )
{
    // Create the message
    char buffer[JMSG_LENGTH_MAX];   /* Flawfinder: ignore */
    (*cinfo->err->format_message) (cinfo, buffer);

    std::string error = buffer ;
    LLImage::setLastError(error);

    bool is_decode = (cinfo->is_decompressor != 0);
    LL_WARNS() << "LLImageJPEG " << (is_decode ? "decode " : "encode ") << " failed: " << buffer << LL_ENDL;
}

bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
{
    llassert_always(raw_image);

    resetLastError();

    LLImageDataSharedLock lockIn(raw_image);
    LLImageDataLock lockOut(this);

    switch( raw_image->getComponents() )
    {
    case 1:
    case 3:
        break;
    default:
        setLastError("Unable to encode a JPEG image that doesn't have 1 or 3 components.");
        return false;
    }

    setSize(raw_image->getWidth(), raw_image->getHeight(), raw_image->getComponents());

    // Allocate a temporary buffer big enough to hold the entire compressed image (and then some)
    // (Note: we make it bigger in emptyOutputBuffer() if we need to)
    delete[] mOutputBuffer;
    mOutputBufferSize = getWidth() * getHeight() * getComponents() + 1024;
    mOutputBuffer = new(std::nothrow) U8[ mOutputBufferSize ];
    if (mOutputBuffer == NULL)
    {
        mOutputBufferSize = 0;
        setLastError("Failed to allocate output buffer");
        return false;
    }

    const U8* raw_image_data = NULL;
    S32 row_stride = 0;

    ////////////////////////////////////////
    // Step 1: allocate and initialize JPEG compression object

    // This struct contains the JPEG compression parameters and pointers to
    // working space (which is allocated as needed by the JPEG library).
    struct jpeg_compress_struct cinfo;
    cinfo.client_data = this;

    // We have to set up the error handler first, in case the initialization
    // step fails.  (Unlikely, but it could happen if you are out of memory.)
    // This routine fills in the contents of struct jerr, and returns jerr's
    // address which we place into the link field in cinfo.
    struct jpeg_error_mgr jerr;
    cinfo.err = jpeg_std_error(&jerr);

    // Customize with our own callbacks
    jerr.error_exit =       &LLImageJPEG::errorExit;            // Error exit handler: does not return to caller
    jerr.emit_message =     &LLImageJPEG::errorEmitMessage;     // Conditionally emit a trace or warning message
    jerr.output_message =   &LLImageJPEG::errorOutputMessage;   // Routine that actually outputs a trace or error message

    //
    //try/catch will crash on Mac and Linux if LLImageJPEG::errorExit throws an error
    //so as instead, we use setjmp/longjmp to avoid this crash, which is the best we can get. --bao
    //
    if( setjmp(sSetjmpBuffer) )
    {
        // If we get here, the JPEG code has signaled an error.
        // We need to clean up the JPEG object, close the input file, and return.
        jpeg_destroy_compress(&cinfo);
        delete[] mOutputBuffer;
        mOutputBuffer = NULL;
        mOutputBufferSize = 0;
        return false;
    }

    try
    {

        // Now we can initialize the JPEG compression object.
        jpeg_create_compress(&cinfo);

        ////////////////////////////////////////
        // Step 2: specify data destination
        // (code is a modified form of jpeg_stdio_dest() )
        if( cinfo.dest == NULL)
        {
            cinfo.dest = (struct jpeg_destination_mgr *)
                (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT,
                sizeof(struct jpeg_destination_mgr));
        }
        cinfo.dest->next_output_byte =      mOutputBuffer;      // => next byte to write in buffer
        cinfo.dest->free_in_buffer =        mOutputBufferSize;  // # of byte spaces remaining in buffer
        cinfo.dest->init_destination =      &LLImageJPEG::encodeInitDestination;
        cinfo.dest->empty_output_buffer =   &LLImageJPEG::encodeEmptyOutputBuffer;
        cinfo.dest->term_destination =      &LLImageJPEG::encodeTermDestination;

        ////////////////////////////////////////
        // Step 3: set parameters for compression
        //
        // First we supply a description of the input image.
        // Four fields of the cinfo struct must be filled in:

        cinfo.image_width = getWidth();     // image width and height, in pixels
        cinfo.image_height = getHeight();

        switch( getComponents() )
        {
        case 1:
            cinfo.input_components = 1;     // # of color components per pixel
            cinfo.in_color_space = JCS_GRAYSCALE; // colorspace of input image
            break;
        case 3:
            cinfo.input_components = 3;     // # of color components per pixel
            cinfo.in_color_space = JCS_RGB; // colorspace of input image
            break;
        default:
            setLastError("Unable to encode a JPEG image that doesn't have 1 or 3 components.");
            return false;
        }

        // Now use the library's routine to set default compression parameters.
        // (You must set at least cinfo.in_color_space before calling this,
        // since the defaults depend on the source color space.)
        jpeg_set_defaults(&cinfo);

        // Now you can set any non-default parameters you wish to.
        jpeg_set_quality(&cinfo, mEncodeQuality, true );  // limit to baseline-JPEG values

        ////////////////////////////////////////
        // Step 4: Start compressor
        //
        // true ensures that we will write a complete interchange-JPEG file.
        // Pass true unless you are very sure of what you're doing.

        jpeg_start_compress(&cinfo, true);

        ////////////////////////////////////////
        // Step 5: while (scan lines remain to be written)
        //            jpeg_write_scanlines(...);

        // Here we use the library's state variable cinfo.next_scanline as the
        // loop counter, so that we don't have to keep track ourselves.
        // To keep things simple, we pass one scanline per call; you can pass
        // more if you wish, though.

        row_stride = getWidth() * getComponents();  // JSAMPLEs per row in image_buffer

        // NOTE: For compatibility with LLImage, we need to invert the rows.
        raw_image_data = raw_image->getData();

        const U8* last_row_data = raw_image_data + (getHeight()-1) * row_stride;

        JSAMPROW row_pointer[1];                // pointer to JSAMPLE row[s]
        while (cinfo.next_scanline < cinfo.image_height)
        {
            // jpeg_write_scanlines expects an array of pointers to scanlines.
            // Here the array is only one element long, but you could pass
            // more than one scanline at a time if that's more convenient.

            //Ugly const uncast here (jpeg_write_scanlines should take a const* but doesn't)
            //row_pointer[0] = (JSAMPROW)(raw_image_data + (cinfo.next_scanline * row_stride));
            row_pointer[0] = (JSAMPROW)(last_row_data - (cinfo.next_scanline * row_stride));

            jpeg_write_scanlines(&cinfo, row_pointer, 1);
        }

        ////////////////////////////////////////
        //   Step 6: Finish compression
        jpeg_finish_compress(&cinfo);

        // After finish_compress, we can release the temp output buffer.
        delete[] mOutputBuffer;
        mOutputBuffer = NULL;
        mOutputBufferSize = 0;

        ////////////////////////////////////////
        //   Step 7: release JPEG compression object
        jpeg_destroy_compress(&cinfo);
    }

    catch(int)
    {
        jpeg_destroy_compress(&cinfo);
        delete[] mOutputBuffer;
        mOutputBuffer = NULL;
        mOutputBufferSize = 0;
        return false;
    }

    return true;
}