/***************************************************************************
                          ADM_coreMuxer.cpp  -  description
                             -------------------
    copyright            : (C) 2008 by mean
    email                : fixounet@free.fr
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include "ADM_coreMuxerFfmpeg.h"
#include "ADM_default.h"
#include "ADM_muxerInternal.h"
#include "ADM_muxerProto.h"
#include "ADM_muxerUtils.h"

#include "BVector.h"
extern "C"
{
#include "libavformat/url.h"
}

void ADM_MuxersCleanup(void);

ADM_muxer *ADM_muxerSpawn(uint32_t magic, const char *name);

BVector<ADM_dynMuxer *> ListOfMuxers;
/**
    \fn ADM_mux_configure
    \brief
*/
bool ADM_mux_configure(int index)
{
    ADM_assert(index < ListOfMuxers.size());
    return ListOfMuxers[index]->configure();
}

/**
        \fn ADM_mx_getNbMuxers
        \brief Returns the number of muxers plugins except one
*/
uint32_t ADM_mx_getNbMuxers(void)
{
    return ListOfMuxers.size();
}
/**
    \fn ADM_mx_getDisplayName
    \brief Returns display name for muxer i
*/
const char *ADM_mx_getDisplayName(uint32_t i)
{
    ADM_assert(i < ListOfMuxers.size());
    return ListOfMuxers[i]->displayName;
}
/**
    \fn ADM_MuxerGetDefaultExtension
    \brief returns the default extension (i.e. mkv, avi) from index
*/
const char *ADM_MuxerGetDefaultExtension(int i)
{
    ADM_assert(i < ListOfMuxers.size());
    return ListOfMuxers[i]->getDefaultExtension();
}
/**
    \fn ADM_mx_getName
    \brief Returns internal name for muxer i
*/
const char *ADM_mx_getName(uint32_t i)
{
    ADM_assert(i < ListOfMuxers.size());
    return ListOfMuxers[i]->name;
}

/**
    \fn     ADM_dm_getDemuxerInfo
    \brief  Get Infos about the demuxer #th plugin
*/
bool ADM_mx_getMuxerInfo(int filter, const char **name, uint32_t *major, uint32_t *minor, uint32_t *patch)
{
    ADM_assert(filter < ListOfMuxers.size());
    ListOfMuxers[filter]->getVersion(major, minor, patch);
    *name = ListOfMuxers[filter]->descriptor;
    return true;
}
/**
    \fn tryLoadingMuxerPlugin
    \brief Try loading the file given as argument as a muxer

*/
#define Fail(x)                                                                                                        \
    {                                                                                                                  \
        printf("%s:" #x "\n", file);                                                                                   \
        goto er;                                                                                                       \
    }
static bool tryLoadingMuxerPlugin(const char *file)
{
    ADM_dynMuxer *dll = new ADM_dynMuxer(file);
    if (!dll->initialised)
        Fail(CannotLoad);
    if (dll->apiVersion != ADM_MUXER_API_VERSION)
        Fail(WrongApiVersion);

    ListOfMuxers.append(dll); // Needed for cleanup. FIXME TODO Delete it.
    ADM_info("[Muxers] Registered filter %s as  %s\n", file, dll->descriptor);
    return true;
    // Fail!
er:
    delete dll;
    return false;
}
/**
 * 	\fn ADM_mx_loadPlugins
 *  \brief load all audio device plugins
 */
uint8_t ADM_mx_loadPlugins(const char *path)
{
    // FIXME Factorize
    std::vector<std::string> filelist;
    ADM_info("Scanning directory %s\n", path);

    if (!buildDirectoryContent(path, &filelist, SHARED_LIB_EXT))
    {
        ADM_warning("Cannot open plugin directory\n");
        return 0;
    }

    for (int i = 0; i < filelist.size(); i++)
        tryLoadingMuxerPlugin(filelist.at(i).c_str());

    printf("[ADM_mx_plugin] Scanning done\n");
    // Sort muxers by displayName, bubble sort
    int nb = ListOfMuxers.size();
    for (int i = 0; i < nb; i++)
    {
        for (int j = i + 1; j < nb; j++)
        {
            ADM_dynMuxer *a, *b;
            a = ListOfMuxers[i];
            b = ListOfMuxers[j];
            if (strcmp(a->displayName, b->displayName) > 0)
            {
                ListOfMuxers[j] = a;
                ListOfMuxers[i] = b;
            }
        }
    }
    ADM_info("Scanning done, %d muxers found\n", nb);
    return 1;
}
/**
    \fn ADM_mx_cleanup
*/
bool ADM_mx_cleanup(void)
{
    ADM_MuxersCleanup();
    return true;
}
/**
    \fn ADM_mx_getExtraConf
    \brief Retrieve extra configuration from current muxer
*/
bool ADM_mx_getExtraConf(int index, CONFcouple **c)
{
    *c = NULL;
    if (index >= ListOfMuxers.size())
    {
        ADM_error("Given index exceeds muxer list\n", index);
        return false;
    }
    ADM_dynMuxer *mux = ListOfMuxers[index];
    return mux->getConfiguration(c);
}
/**
    \fn ADM_mx_setExtraConf
    \brief Set extra configuration from current muxer
*/
bool ADM_mx_setExtraConf(int index, CONFcouple *c)
{
    if (!c)
        return true;
    if (index >= ListOfMuxers.size())
    {
        ADM_error("Given index exceeds muxer list\n", index);
        return false;
    }
    ADM_dynMuxer *mux = ListOfMuxers[index];
    return mux->setConfiguration(c);
}
/**
        \fn ADM_MuxersCleanup
        \brief Current device is no longer used, delete
*/
void ADM_MuxersCleanup(void)
{
    int nb = ListOfMuxers.size();
    for (int i = 0; i < nb; i++)
    {
        ADM_dynMuxer *mx = ListOfMuxers[i];
        if (!mx)
            continue;
        delete mx;
        ListOfMuxers[i] = NULL;
    }
}

/**
    \fn ADM_muxerIndexFromName
    \brief return muxer index from name, -1 if error
*/
int ADM_MuxerIndexFromName(const char *name)
{
    int n = ListOfMuxers.size();
    for (int i = 0; i < n; i++)
    {
        ADM_dynMuxer *mux = ListOfMuxers[i];
        if (!strcasecmp(mux->name, name))
            return i;
    }
    return -1;
}
/**
    \fn ADM_MuxerSpawn
    \brief Locate the correct demuxer and instantiate it

*/
ADM_muxer *ADM_MuxerSpawn(const char *name)
{
    int found = -1;
    uint32_t score = 0;
    uint32_t mark;
    found = ADM_MuxerIndexFromName(name);
    if (score && found != -1)
    {
        return ListOfMuxers[found]->createmuxer();
    }
    return NULL;
}

/**
    \fn ADM_MuxerSpawnFromIndex
    \brief Locate the correct demuxer and instantiate it

*/
ADM_muxer *ADM_MuxerSpawnFromIndex(int index)
{
    ADM_assert(index < ListOfMuxers.size());
    return ListOfMuxers[index]->createmuxer();
}

//___________________________________________
extern "C"
{
#include "libavformat/avformat.h"
#include "libavutil/mem.h"
};

void ADM_lavFormatInit(void)
{
    // Make sure avformat is correctly configured
    const char *formats[] = {"mpegts", "dvd", "vcd", "svcd", "mp4", "psp", "flv", "matroska"};
    const AVOutputFormat *avfmt;

    for (int i = 0; i < 8; i++)
    {
        avfmt = av_guess_format(formats[i], NULL, NULL);

        if (avfmt == NULL)
        {
            printf("Error: %s muxer isn't registered\n", formats[i]);
            ADM_assert(0);
        }
    }

    const URLProtocol **prot = ffurl_get_protocols("file", NULL);
    bool found = false;
    if (prot)
    {
        if (!strcmp(prot[0]->name, "file"))
        {
            found = true;
        }
        av_freep(&prot);
    }
    if (!found)
    {
        printf("Error: file protocol isn't registered\n");
        ADM_assert(0);
    }
}
// EOF
