/*                                                            -*- C -*-
 * Copyright (c) 1998-2006  Motoyuki Kasahara
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the project nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include "ebzip.h"
#include "ebutils.h"

#include "getumask.h"
#include "makedir.h"
#include "strlist.h"

/*
 * Unexported function.
 */
static int ebzip_zip_book_eb(EB_Book *book, const char *out_top_path,
    const char *book_path, EB_Subbook_Code *subbook_list, int subbook_count);
static int ebzip_zip_book_epwing(EB_Book *book, const char *out_top_path,
    const char *book_path, EB_Subbook_Code *subbook_list, int subbook_count);


/*
 * Compress files in `book' and output them under `out_top_path'.
 * If it succeeds, 0 is returned.  Otherwise -1 is returned.
 */
int
ebzip_zip_book(const char *out_top_path, const char *book_path,
    char subbook_name_list[][EB_MAX_DIRECTORY_NAME_LENGTH + 1],
    int subbook_name_count)
{
    EB_Book book;
    EB_Error_Code error_code;
    EB_Subbook_Code subbook_list[EB_MAX_SUBBOOKS];
    EB_Subbook_Code subbook_code;
    int subbook_count;
    int result;
    int i;

    eb_initialize_book(&book);

    /*
     * Bind a book.
     */
    error_code = eb_bind(&book, book_path);
    if (error_code != EB_SUCCESS) {
	fprintf(stderr, "%s: %s\n", invoked_name,
	    eb_error_message(error_code));
	fflush(stderr);
	return -1;
    }

    /*
     * For each targe subbook, convert a subbook-names to a subbook-codes.
     * If no subbook is specified by `--subbook'(`-S'), set all subbooks
     * as the target.
     */
    if (subbook_name_count == 0) {
	error_code = eb_subbook_list(&book, subbook_list, &subbook_count);
	if (error_code != EB_SUCCESS) {
	    fprintf(stderr, "%s: %s\n", invoked_name,
		eb_error_message(error_code));
	    fflush(stderr);
	    return -1;
	}
    } else {
	subbook_count = 0;
	for (i = 0; i < subbook_name_count; i++) {
	    error_code = find_subbook(&book, subbook_name_list[i],
		&subbook_code);
	    if (error_code != EB_SUCCESS) {
		fprintf(stderr, _("%s: unknown subbook name `%s'\n"),
		    invoked_name, subbook_name_list[i]);
		return -1;
	    }
	    subbook_list[subbook_count++] = subbook_code;
	}
    }

    /*
     * Compress the book.
     */
    if (book.disc_code == EB_DISC_EB) {
	result = ebzip_zip_book_eb(&book, out_top_path, book_path,
	    subbook_list, subbook_count);
    } else {
	result = ebzip_zip_book_epwing(&book, out_top_path, book_path,
	    subbook_list, subbook_count);
    }

    eb_finalize_book(&book);

    return result;
}


/*
 * Internal function for `zip_book'.
 * This is used to compress an EB book.
 */
static int
ebzip_zip_book_eb(EB_Book *book, const char *out_top_path,
    const char *book_path, EB_Subbook_Code *subbook_list, int subbook_count)
{
    EB_Subbook *subbook;
    String_List string_list;
    char in_path_name[PATH_MAX + 1];
    char out_sub_path[PATH_MAX + 1];
    char out_path_name[PATH_MAX + 1];
    char catalog_file_name[EB_MAX_FILE_NAME_LENGTH];
    char language_file_name[EB_MAX_FILE_NAME_LENGTH];
    mode_t out_directory_mode;
    Zip_Speedup speedup;
    Zio_Code in_zio_code;
    int i;

    /*
     * If `out_top_path' and/or `book_path' represents "/", replace it
     * to an empty string.
     */
    if (strcmp(out_top_path, "/") == 0)
	out_top_path++;
    if (strcmp(book_path, "/") == 0)
	book_path++;

    /*
     * Initialize variables.
     */
    out_directory_mode = 0777 ^ get_umask();
    eb_load_all_subbooks(book);
    string_list_initialize(&string_list);

    /*
     * Compress a book.
     */
    for (i = 0; i < subbook_count; i++) {
	subbook = book->subbooks + subbook_list[i];

	/*
	 * Make an output directory for the current subbook.
	 */
	eb_compose_path_name(out_top_path, subbook->directory_name,
	    out_sub_path);
	if (!ebzip_test_flag
	    && make_missing_directory(out_sub_path, out_directory_mode) < 0)
	    goto failed;

	/*
	 * Compress START file.
	 */
	in_zio_code = zio_mode(&subbook->text_zio);

	eb_compose_path_name2(book->path, subbook->directory_name,
	    subbook->text_file_name, in_path_name);
	eb_compose_path_name2(out_top_path, subbook->directory_name,
	    subbook->text_file_name, out_path_name);
	eb_fix_path_name_suffix(out_path_name, EBZIP_SUFFIX_EBZ);

	if (in_zio_code != ZIO_INVALID
	    && !string_list_find(&string_list, in_path_name)) {
	    ebzip_initialize_zip_speedup(&speedup);
	    if (ebzip_set_zip_speedup(&speedup, in_path_name, in_zio_code,
		subbook->index_page) < 0)
		goto failed;
	    if (ebzip_zip_start_file(out_path_name, in_path_name, in_zio_code,
		subbook->index_page, &speedup) < 0)
		goto failed;
	    ebzip_finalize_zip_speedup(&speedup);
	    string_list_add(&string_list, in_path_name);
	}
    }

    /*
     * Compress a language file.
     */
    if (eb_find_file_name(book->path, "language", language_file_name)
	== EB_SUCCESS) {
	eb_compose_path_name(book->path, language_file_name, in_path_name);
	eb_compose_path_name(out_top_path, language_file_name, out_path_name);
	eb_path_name_zio_code(in_path_name, ZIO_PLAIN, &in_zio_code);
	eb_fix_path_name_suffix(out_path_name, EBZIP_SUFFIX_EBZ);
	if (ebzip_zip_file(out_path_name, in_path_name, in_zio_code, NULL) < 0)
	    goto failed;
    }

    /*
     * Copy CATALOG file.
     */
    if (eb_find_file_name(book->path, "catalog", catalog_file_name)
	== EB_SUCCESS) {
	eb_compose_path_name(book->path, catalog_file_name, in_path_name);
	eb_compose_path_name(out_top_path, catalog_file_name, out_path_name);
	eb_path_name_zio_code(in_path_name, ZIO_PLAIN, &in_zio_code);
	if (ebzip_copy_file(out_path_name, in_path_name) < 0)
	    goto failed;
    }

    string_list_finalize(&string_list);
    return 0;

    /*
     * An error occurs...
     */
  failed:
    string_list_finalize(&string_list);
    return -1;
}


/*
 * Internal function for `zip_book'.
 * This is used to compress an EPWING book.
 */
static int
ebzip_zip_book_epwing(EB_Book *book, const char *out_top_path,
    const char *book_path, EB_Subbook_Code *subbook_list, int subbook_count)
{
    EB_Subbook *subbook;
    String_List string_list;
    EB_Font *font;
    char in_path_name[PATH_MAX + 1];
    char out_sub_path[PATH_MAX + 1];
    char out_path_name[PATH_MAX + 1];
    char catalogs_file_name[EB_MAX_FILE_NAME_LENGTH];
    mode_t out_directory_mode;
    Zip_Speedup speedup;
    Zio_Code in_zio_code;
    int i, j;

    /*
     * If `out_top_path' and/or `book_path' represents "/", replace it
     * to an empty string.
     */
    if (strcmp(out_top_path, "/") == 0)
	out_top_path++;
    if (strcmp(book_path, "/") == 0)
	book_path++;

    /*
     * Initialize variables.
     */
    out_directory_mode = 0777 ^ get_umask();
    eb_load_all_subbooks(book);
    string_list_initialize(&string_list);

    /*
     * Compress a book.
     */
    for (i = 0; i < subbook_count; i++) {
	subbook = book->subbooks + subbook_list[i];

	/*
	 * Make an output directory for the current subbook.
	 */
	eb_compose_path_name(out_top_path, subbook->directory_name,
	    out_sub_path);
	if (!ebzip_test_flag
	    && make_missing_directory(out_sub_path, out_directory_mode) < 0)
	    goto failed;

	/*
	 * Make `data' sub directory for the current subbook.
	 */
	eb_compose_path_name2(out_top_path, subbook->directory_name,
	    subbook->data_directory_name, out_sub_path);
	if (!ebzip_test_flag
	    && make_missing_directory(out_sub_path, out_directory_mode) < 0)
	    goto failed;

	/*
	 * Compress HONMON/HONMON2 file.
	 */
	in_zio_code = zio_mode(&subbook->text_zio);
	eb_compose_path_name3(book->path, subbook->directory_name,
	    subbook->data_directory_name, subbook->text_file_name,
	    in_path_name);
	eb_compose_path_name3(out_top_path, subbook->directory_name,
	    subbook->data_directory_name, subbook->text_file_name,
	    out_path_name);
	eb_fix_path_name_suffix(out_path_name, EBZIP_SUFFIX_EBZ);

	if (in_zio_code != ZIO_INVALID
	    && !string_list_find(&string_list, in_path_name)) {
	    ebzip_initialize_zip_speedup(&speedup);
	    if (ebzip_set_zip_speedup(&speedup, in_path_name, in_zio_code,
		subbook->index_page) < 0)
		goto failed;
	    if (ebzip_zip_file(out_path_name, in_path_name, in_zio_code,
		&speedup) < 0)
		goto failed;
	    ebzip_finalize_zip_speedup(&speedup);
	    string_list_add(&string_list, in_path_name);
	}

	/*
	 * Compress HONMONS file.
	 */
	in_zio_code = zio_mode(&subbook->sound_zio);
	eb_compose_path_name3(book->path, subbook->directory_name,
	    subbook->data_directory_name, subbook->sound_file_name,
	    in_path_name);
	eb_compose_path_name3(out_top_path, subbook->directory_name,
	    subbook->data_directory_name, subbook->sound_file_name,
	    out_path_name);
	eb_fix_path_name_suffix(out_path_name, EBZIP_SUFFIX_EBZ);

	if (!ebzip_skip_flag_sound
	    && in_zio_code != ZIO_INVALID
	    && !string_list_find(&string_list, in_path_name)) {
	    if (ebzip_zip_file(out_path_name, in_path_name, in_zio_code,
		NULL) < 0)
		goto failed;
	    string_list_add(&string_list, in_path_name);
	}

	/*
	 * Copy HONMONG file.
	 */
	in_zio_code = zio_mode(&subbook->graphic_zio);
	eb_compose_path_name3(book->path, subbook->directory_name,
	    subbook->data_directory_name, subbook->graphic_file_name,
	    in_path_name);
	eb_compose_path_name3(out_top_path, subbook->directory_name,
	    subbook->data_directory_name, subbook->graphic_file_name,
	    out_path_name);

	if (!ebzip_skip_flag_graphic
	    && in_zio_code != ZIO_INVALID
	    && !string_list_find(&string_list, in_path_name)) {
	    if (ebzip_copy_file(out_path_name, in_path_name) < 0)
		goto failed;
	    string_list_add(&string_list, in_path_name);
	}

	if (!ebzip_skip_flag_font) {
	    /*
	     * Make `gaiji' sub directory for the current subbook.
	     */
	    eb_compose_path_name2(out_top_path, subbook->directory_name,
		subbook->gaiji_directory_name, out_sub_path);
	    if (!ebzip_test_flag
		&& make_missing_directory(out_sub_path, out_directory_mode)
		< 0) {
		goto failed;
	    }

	    /*
	     * Compress narrow font files.
	     */
	    for (j = 0; j < EB_MAX_FONTS; j++) {
		font = subbook->narrow_fonts + j;
		if (font->font_code == EB_FONT_INVALID)
		    continue;

		in_zio_code = zio_mode(&font->zio);
		eb_compose_path_name3(book->path, subbook->directory_name,
		    subbook->gaiji_directory_name, font->file_name,
		    in_path_name);
		eb_compose_path_name3(out_top_path, subbook->directory_name,
		    subbook->gaiji_directory_name, font->file_name,
		    out_path_name);
		eb_fix_path_name_suffix(out_path_name, EBZIP_SUFFIX_EBZ);

		if (in_zio_code != ZIO_INVALID
		    && !string_list_find(&string_list, in_path_name)) {
		    if (ebzip_zip_file(out_path_name, in_path_name,
			in_zio_code, NULL) < 0)
			goto failed;
		    string_list_add(&string_list, in_path_name);
		}
	    }

	    /*
	     * Compress wide font files.
	     */
	    for (j = 0; j < EB_MAX_FONTS; j++) {
		font = subbook->wide_fonts + j;
		if (font->font_code == EB_FONT_INVALID)
		    continue;

		in_zio_code = zio_mode(&font->zio);
		eb_compose_path_name3(book->path, subbook->directory_name,
		    subbook->gaiji_directory_name, font->file_name,
		    in_path_name);
		eb_compose_path_name3(out_top_path, subbook->directory_name,
		    subbook->gaiji_directory_name, font->file_name,
		    out_path_name);
		eb_fix_path_name_suffix(out_path_name, EBZIP_SUFFIX_EBZ);

		if (in_zio_code != ZIO_INVALID
		    && !string_list_find(&string_list, in_path_name)) {
		    if (ebzip_zip_file(out_path_name, in_path_name,
			in_zio_code, NULL) < 0)
			goto failed;
		    string_list_add(&string_list, in_path_name);
		}
	    }
	}

	/*
	 * Copy movie files.
	 */
	if (!ebzip_skip_flag_movie) {
	    eb_compose_path_name2(book->path, subbook->directory_name,
		subbook->movie_directory_name, in_path_name);
	    eb_compose_path_name2(out_top_path, subbook->directory_name,
		subbook->movie_directory_name, out_path_name);
	    if (ebzip_copy_files_in_directory(out_path_name, in_path_name) < 0)
		goto failed;
	}
    }

    /*
     * Copy CATALOGS file.
     */
    if (eb_find_file_name(book->path, "catalogs", catalogs_file_name)
	== EB_SUCCESS) {
	eb_compose_path_name(book->path, catalogs_file_name, in_path_name);
	eb_compose_path_name(out_top_path, catalogs_file_name, out_path_name);
	if (ebzip_copy_file(out_path_name, in_path_name) < 0)
	    goto failed;
    }

    string_list_finalize(&string_list);
    return 0;

    /*
     * An error occurs...
     */
  failed:
    string_list_finalize(&string_list);
    return -1;
}
