/** @file
 * @brief Extract metadata using libextractor.
 */
/* Copyright (C) 2020 Parth Kapadia
 * Copyright (C) 2022,2023 Olly Betts
 *
 * 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, see
 * <https://www.gnu.org/licenses/>.
 */
#include <config.h>
#include "handler.h"
#include "parseint.h"

#include <extractor.h>

using namespace std;

/** Store metadata in its corresponding variable.
 *
 *  @param cls  		last parameter from EXTRACTOR_extract (unused)
 *  @param plugin_name  	name of the plugin (unused)
 *  @param type  		mime-type of file according to libextractor
 *  @param format		format information about data
 *  @param data_mime_type	mimetype according to libextractor (unused)
 *  @param data 		actual meta-data found
 *  @param data_len		number of bytes in data
 */
static int
process_metadata(void*,
		 const char*,
		 enum EXTRACTOR_MetaType type,
		 enum EXTRACTOR_MetaFormat format,
		 const char*,
		 const char* data,
		 size_t data_len)
{
    switch (format) {
	case EXTRACTOR_METAFORMAT_UTF8:
	    break;

	default:
	    // specific encoding unknown
	    // EXTRACTOR_METAFORMAT_UNKNOWN
	    // EXTRACTOR_METAFORMAT_BINARY
	    // EXTRACTOR_METAFORMAT_C_STRING
	    return 0;
    }

    // "data_len is strlen (data)+1"!
    --data_len;

    switch (type) {
	case EXTRACTOR_METATYPE_BOOK_TITLE:
	case EXTRACTOR_METATYPE_JOURNAL_NAME:
	case EXTRACTOR_METATYPE_ORIGINAL_TITLE:
	case EXTRACTOR_METATYPE_SUBJECT:
	case EXTRACTOR_METATYPE_SUBTITLE:
	case EXTRACTOR_METATYPE_TITLE:
	    send_field(FIELD_TITLE, data, data_len);
	    break;

	case EXTRACTOR_METATYPE_PAGE_COUNT: {
	    unsigned p;
	    if (parse_unsigned(data, p)) {
		send_field_page_count(int(p));
	    }
	    break;
	}

	case EXTRACTOR_METATYPE_ARTIST:
	case EXTRACTOR_METATYPE_AUTHOR_NAME:
	case EXTRACTOR_METATYPE_COMPOSER:
	case EXTRACTOR_METATYPE_CONDUCTOR:
	case EXTRACTOR_METATYPE_CREATOR:
	case EXTRACTOR_METATYPE_MOVIE_DIRECTOR:
	case EXTRACTOR_METATYPE_ORIGINAL_ARTIST:
	case EXTRACTOR_METATYPE_ORIGINAL_PERFORMER:
	case EXTRACTOR_METATYPE_ORIGINAL_WRITER:
	case EXTRACTOR_METATYPE_PERFORMER:
	case EXTRACTOR_METATYPE_WRITER:
	    send_field(FIELD_AUTHOR, data, data_len);
	    break;

	case EXTRACTOR_METATYPE_KEYWORDS:
	    send_field(FIELD_KEYWORDS, data, data_len);
	    break;

	case EXTRACTOR_METATYPE_ABSTRACT:
	case EXTRACTOR_METATYPE_COMMENT:
	case EXTRACTOR_METATYPE_DESCRIPTION:
	case EXTRACTOR_METATYPE_LYRICS:
	case EXTRACTOR_METATYPE_SUMMARY:
	    send_field(FIELD_BODY, data, data_len);
	    break;

	default:
	    // Ignore other metadata.
	    break;
    }
    return 0;
}

static struct EXTRACTOR_PluginList* plugins;

bool
initialise(string& error)
{
    // Add all default plugins.
    plugins = EXTRACTOR_plugin_add_defaults(EXTRACTOR_OPTION_DEFAULT_POLICY);
    if (plugins == nullptr) {
	error = "Failed to find any libextractor plugins";
	return false;
    }
    return true;
}

void
extract(const string& filename, const string&)
{
    // If plugin not found/ File format not recognised/ corrupt file
    // no data is extracted, rather than reporting an error.
    EXTRACTOR_extract(plugins, filename.c_str(),
		      nullptr, 0,
		      &process_metadata, nullptr);
}
