/******************************************************************************
 * mod_uploader / RFC1867Parser.cpp
 ******************************************************************************
 * Copyright (C) 2004 Tetsuya Kimata <kimata@acapulco.dyndns.org>
 *
 * All rights reserved.
 *
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors be held liable for any
 * damages arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any
 * purpose, including commercial applications, and to alter it and
 * redistribute it freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must
 *    not claim that you wrote the original software. If you use this
 *    software in a product, an acknowledgment in the product
 *    documentation would be appreciated but is not bcktuired.
 *
 * 2. Altered source versions must be plainly marked as such, and must
 *    not be misrepresented as being the original software.
 *
 * 3. This notice may not be removed or altered from any source
 *    distribution.
 *
 * $Id: ThumbnailWriter.cpp 693 2005-09-17 09:23:20Z svn $
 *****************************************************************************/

#include "ThumbnailWriter.h"

#ifdef MAKE_THUMBNAIL
#include "Auxiliary.h"
#include "Misc.h"

#include "apr_file_io.h"
#include "apr_strings.h"

#ifdef WIN32
#undef HAVE_INTTYPES_H
#undef HAVE_STDINT_H
#endif
#undef PACKAGE_BUGREPORT
#undef PACKAGE_NAME
#undef PACKAGE_STRING
#undef PACKAGE_TARNAME
#undef PACKAGE_VERSION
#include <Magick++.h>
#undef PACKAGE_BUGREPORT
#undef PACKAGE_NAME
#undef PACKAGE_STRING
#undef PACKAGE_TARNAME
#undef PACKAGE_VERSION

#ifdef DEBUG
#include <iostream>
#endif

const char ThumbnailWriter::FILE_SUFFIX[]       = "." THUMBNAIL_FILE_TYPE;
const apr_size_t ThumbnailWriter::SIZE_LIMIT    = THUMBNAIL_SIZE_LIMIT;
const apr_size_t ThumbnailWriter::WIDTH_LIMIT   = THUMBNAIL_WIDTH_LIMIT;
const apr_size_t ThumbnailWriter::HEIGHT_LIMIT  = THUMBNAIL_HEIGHT_LIMIT;


/******************************************************************************
 * public メソッド
 *****************************************************************************/
ThumbnailWriter::ThumbnailWriter(apr_pool_t *pool, const char *file_dir,
                                 const char *thumb_dir)
    : pool_(pool),
      file_dir_(file_dir),
      thumb_dir_(thumb_dir)
{

}

void ThumbnailWriter::write(const char *file_path) const
{
    apr_pool_t *pool;

    if (apr_pool_create(&pool, pool_) != APR_SUCCESS) {
        throw "メモリの確保に失敗しました．";
    }

    try {
        apr_size_t read_size;
        void *buffer;

        buffer = read(pool, file_path, &read_size);
        Magick::Blob data(buffer, read_size);
        Magick::Image image(data);
        Magick::Geometry size = image.size();

        if ((size.width() == 0) || (size.height() == 0)) { // 判断基準はこれで良い？
            throw "サムネイル化に対応していない形式のファイルです．";
        }

        calc_size(size);

        image.scale(size);
        image.write(create_thumb_path(pool, thumb_dir_, file_path));

        apr_pool_destroy(pool);
    } catch(Magick::Exception &e) {
        apr_pool_destroy(pool);
        throw e.what();
    } catch(exception &e) {
        apr_pool_destroy(pool);
        throw e.what();
    } catch(const char *) {
        apr_pool_destroy(pool);
        throw;
    }
}

const char *ThumbnailWriter::create_thumb_path(apr_pool_t *pool,
                                               const char *thumb_dir,
                                               const char *file_path)
{
    return apr_pstrcat(pool,
                       thumb_dir, "/", file_path, FILE_SUFFIX, NULL);
}


/******************************************************************************
 * private メソッド
 *****************************************************************************/
void *ThumbnailWriter::read(apr_pool_t *pool, const char *file_path, apr_size_t *size) const
{
    UploadItem::header *header;
    apr_file_t *file;
    apr_size_t read_size;
    void *buffer;

    UploadItemReader reader(pool, file_dir_);
    header = reader.read(file_path, &file);

    if (header->file_size > SIZE_LIMIT) {
        // 面倒だから例外投げちゃいます．
        throw "ファイルが大きすぎます．";
    }

    APR_PALLOC(buffer, void *, pool, header->file_size);

    if ((apr_file_read_full(file, buffer, header->file_size, &read_size) != APR_SUCCESS) ||
        (read_size != header->file_size)) {
        throw "アップロードファイルを読み込めませんでした．";
    }
    apr_file_close(file);

    *size = header->file_size;

    return buffer;
}

void ThumbnailWriter::calc_size(Magick::Geometry &size) const
{
    if ((size.width() <= WIDTH_LIMIT) && (size.height() <= HEIGHT_LIMIT)) {
        return;
    }

    if ((size.width()/size.height()) > (WIDTH_LIMIT/HEIGHT_LIMIT)) {
        if (size.width() > WIDTH_LIMIT) {
            size.height(size.height()*WIDTH_LIMIT/size.width());
            size.width(WIDTH_LIMIT);
        }
    } else {
        if (size.height() > HEIGHT_LIMIT) {
            size.width(size.width()*HEIGHT_LIMIT/size.height());
            size.height(HEIGHT_LIMIT);
        }
    }
}


/******************************************************************************
 * テスト
 *****************************************************************************/
#ifdef DEBUG_ThumbnailWriter

#include "apr_general.h"
#include "apr_file_io.h"

static const char FILE_DIR[]            = "/tmp";

void usage(const char *prog_name)
{
    cerr << "Usage: " << prog_name << " <FILE> <MAGICKDIR>" << endl;
}

int main(int argc, const char * const *argv)
{
    apr_pool_t *pool;

    apr_app_initialize(&argc, &argv, NULL);
    apr_pool_create(&pool, NULL);

    try {
        if (argc != 2) {
            throw "入力用のファイルが指定されていません．";
        }

        ThumbnailWriter writer(pool, dirname_ex(pool, argv[1]), FILE_DIR);
        writer.write(basename_ex(argv[1]));
    } catch(const char *message) {
        cerr << "Error: " << message << endl;
        usage(argv[0]);

        return EXIT_FAILURE;
    }

    apr_terminate();

    return EXIT_SUCCESS;
}
#endif

#endif

// Local Variables:
// mode: c++
// buffer-file-coding-system: euc-japan-dos
// End:
