/*
    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) 2013  PCMan <email>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/


#include "loadimagejob.h"
#include "mainwindow.h"
#include <QImageReader>
#include <QBuffer>
#include <qvarlengtharray.h>
#include <libexif/exif-loader.h>

using namespace LxImage;

LoadImageJob::LoadImageJob(MainWindow* window, FmPath* filePath):
  Job(),
  mainWindow_(window),
  path_(fm_path_ref(filePath)) {
}

LoadImageJob::~LoadImageJob() {
  fm_path_unref(path_);
}

// This is called from the worker thread, not main thread
bool LoadImageJob::run() {
  GFile* gfile = fm_path_to_gfile(path_);
  GFileInputStream* fileStream = g_file_read(gfile, cancellable_, &error_);
  g_object_unref(gfile);

  if(fileStream) { // if the file stream is successfually opened
    QBuffer imageBuffer;
    GInputStream* inputStream = G_INPUT_STREAM(fileStream);
    while(!g_cancellable_is_cancelled(cancellable_)) {
      char buffer[4096];
      gssize readSize = g_input_stream_read(inputStream,
                                            buffer, 4096,
                                            cancellable_, &error_);
      if(readSize == -1 || readSize == 0) // error or EOF
        break;
      // append the bytes read to the image buffer
        imageBuffer.buffer().append(buffer, readSize);
    }
    g_input_stream_close(inputStream, NULL, NULL);

    // FIXME: maybe it's a better idea to implement a GInputStream based QIODevice.
    if(!error_ && !g_cancellable_is_cancelled(cancellable_)) { // load the image from buffer if there are no errors
      image_ = QImage::fromData(imageBuffer.buffer());

      if(!image_.isNull()) { // if the image is loaded correctly
        // check if this file is a jpeg file
        // FIXME: can we use FmFileInfo instead if it's available?
        const char* basename = fm_path_get_basename(path_);
        char* mime_type = g_content_type_guess(basename, NULL, 0, NULL);
        if(mime_type && strcmp(mime_type, "image/jpeg") == 0) { // this is a jpeg file
          // use libexif to extract additional info embedded in jpeg files
          ExifLoader *exif_loader = exif_loader_new();
          // write image data to exif loader
          exif_loader_write(exif_loader, (unsigned char*)imageBuffer.data().constData(), (unsigned int)imageBuffer.size());
          ExifData *exif_data = exif_loader_get_data(exif_loader);
          exif_loader_unref(exif_loader);
          if(exif_data) {
            /* reference for EXIF orientation tag:
            * http://www.impulseadventure.com/photo/exif-orientation.html */
            ExifEntry* orient_ent = exif_data_get_entry(exif_data, EXIF_TAG_ORIENTATION);
            if(orient_ent) { /* orientation flag found in EXIF */
              gushort orient;
              ExifByteOrder bo = exif_data_get_byte_order(exif_data);
              /* bo == EXIF_BYTE_ORDER_INTEL ; */
              orient = exif_get_short (orient_ent->data, bo);
              qreal rotate_degrees = 0.0;
              switch(orient) {
                case 1: /* no rotation */
                  break;
                case 8:
                  rotate_degrees = 270.0;
                  break;
                case 3:
                  rotate_degrees = 180.0;
                  break;
                case 6:
                  rotate_degrees = 90.0;
                  break;
              }
              // rotate the image according to EXIF orientation tag
              if(rotate_degrees != 0.0) {
                QTransform transform;
                transform.rotate(rotate_degrees);
                image_ = image_.transformed(transform, Qt::SmoothTransformation);
              }
              // TODO: handle other EXIF tags as well
            }
            exif_data_unref(exif_data);
          }
        }
        g_free(mime_type);
      }
    }
  }
  return false;
}

// this function is called from main thread only
void LoadImageJob::finish() {
  // only do processing if the job is not cancelled
  if(!g_cancellable_is_cancelled(cancellable_)) {
    mainWindow_->onImageLoaded(this);
  }
}
