/*
 * imageutils.cpp
 *
 * (c) 2003,2008-2009 by Jeremy Bowman <jmbowman@alum.mit.edu>
 *
 * 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.
 */

/** @file imageutils.cpp
 * Source file for ImageUtils
 */

#include <QBuffer>
#include <QFile>
#include <QFileInfo>
#include <QImageReader>
#include <QImageWriter>
#include "imageeditor.h"
#include "imageutils.h"
#include "../database.h"

/**
 * Constructor.
 */
ImageUtils::ImageUtils()
{

}

/**
 * Load an image from a database field.
 *
 * @param db The database to load from
 * @param rowId The ID of the row to load from
 * @param colName The name of the column to load from
 * @param format The format of the image to load ("JPEG" or "PNG")
 * @return The loaded image
 */
QImage ImageUtils::load(Database *db, int rowId, const QString &colName,
                        const QString &format)
{
    QByteArray data = db->getBinaryField(rowId, colName);
    QBuffer buffer(&data);
    QImageReader reader(&buffer, format.toLower().toLatin1());
    buffer.open(QIODevice::ReadOnly);
    QImage image = reader.read();
    buffer.close();
    return image;
}

/**
 * Load an image from a file, in the process shrinking it if originally
 * larger than about 800 x 600.
 *
 * @param path Path to the file to be loaded
 * @param resized Pointer to the boolean which will indicate if the image had
 *                to be resized when loaded
 */
QImage ImageUtils::load(const QString &path, bool *resized)
{
    QImageReader reader(path);
    format = reader.format().toUpper();
    if (format != "JPEG" && format != "PNG") {
        error = ImageEditor::tr("Unsupported image format");
        return QImage();
    }
    QSize size = reader.size();
    int width = size.width();
    int height = size.height();
    // Scale the image down so as to not swamp devices with limited memory when
    // loaded (only works for JPEGs, big PNG images will be rejected)
    int scaleDenom = 1;
    *resized = false;
    while (width * height > 800 * 600) {
        scaleDenom *= 2;
        // I doubt if many people have 6400 x 4800 images, but it's probably
        // only a matter of time before digital cameras get there...
        if (scaleDenom > 8 || format != "JPEG") {
            error = ImageEditor::tr("Image is too large to import");
            return QImage();
        }
        width /= 2;
        height /= 2;
        *resized = true;
    }
    reader.setScaledSize(QSize(width, height));
    return reader.read();
}

/**
 * Get the format of the last loaded image, "JPEG" or "PNG".
 *
 * @return The image's format
 */
QString ImageUtils::getFormat() const
{
    return format;
}

/**
 * Get the error message (if any) generated by the last attempt to load a file.
 *
 * @return The error message, which may be empty
 */
QString ImageUtils::getErrorMessage() const
{
    return error;
}

/**
 * Convert an image to an array of bytes suitable for storage in a
 * database field.
 *
 * @param image The image to be converted
 * @param format The format of the image, "JPEG" or "PNG"
 * @param path The path to the file from which the image was loaded
 * @param changed True if the image has been resized or rotated
 * @return An array of bytes to save in the database as the image
 */
QByteArray ImageUtils::getImageData(QImage image, const QString &format,
                               const QString &path, bool changed)
{
    if (!changed) {
        QFile file(path);
        file.open(QIODevice::ReadOnly);
        QByteArray data = file.readAll();
        file.close();
        return data;
    }
    else {
        QByteArray data;
        QBuffer buffer(&data);
        QImageWriter writer(&buffer, format.toLower().toLatin1());
        buffer.open(QIODevice::WriteOnly);
        writer.write(image);
        buffer.close();
        return data;
    }
}

/**
 * Derive the directory in which exported images are to be stored based on
 * the path to the main exported file.
 *
 * @param filePath The path to the exported file
 */
void ImageUtils::setExportPaths(const QString &filePath)
{
    QFileInfo info(filePath);
    // Put image files in the same directory as the CSV/XML file
    imageAbsPath = info.absolutePath() + "/";
    imageRelPath = "";
}

/**
 * Export the image in a database field to a file.
 *
 * @param db The database to export from
 * @param rowId The ID of the row to export from
 * @param columnName The name of the column to export from
 * @param format The image format to save as, "JPEG" or "PNG"
 * @return The relative path to the exported image file
 */
QString ImageUtils::exportImage(Database *db, int rowId,
                                const QString &columnName,
                                const QString &format)
{
    if (format.isEmpty()) {
        return "";
    }
    QString suffix;
    if (format == "JPEG") {
        suffix = ".jpg";
    }
    else {
        suffix = ".png";
    }
    QString nameRoot = columnName + QString("_%1").arg(rowId);
    QString filename = nameRoot + suffix;
    int counter = 0;
    while (QFile::exists(imageAbsPath + filename)) {
        filename = nameRoot + QString("_%1").arg(counter) + suffix;
        counter++;
    }
    QByteArray data = db->getBinaryField(rowId, columnName);
    if (data.size() == 0) {
        return "";
    }
    QFile file(imageAbsPath + filename);
    file.open(QIODevice::WriteOnly);
    file.write(data);
    file.close();
    return imageRelPath + filename;
}
