#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <glib.h>

#include "../../include/string.h"
#include "../../include/fio.h"

#include "edv_mime_type.h"
#include "edv_mime_types_list.h"
#include "config.h"


edv_mime_type_struct **EDVMimeTypesListFileOpen(
	const gchar *filename, gint *total
);


#define ATOI(s)         (((s) != NULL) ? atoi(s) : 0)
#define ATOL(s)         (((s) != NULL) ? atol(s) : 0)
#define ATOF(s)         (((s) != NULL) ? atof(s) : 0.0f)
#define STRDUP(s)       (((s) != NULL) ? g_strdup(s) : NULL)

#define MAX(a,b)        (((a) > (b)) ? (a) : (b))
#define MIN(a,b)        (((a) < (b)) ? (a) : (b))
#define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
#define STRLEN(s)       (((s) != NULL) ? strlen(s) : 0)
#define STRISEMPTY(s)   (((s) != NULL) ? (*(s) == '\0') : TRUE)


/*
 *	Loads the MIME Types from the given MIME Types file.
 *
 *	The format of the file must be an Endeavour 2 MIME Types file.
 *
 *	Returns a list of loaded MIME Types.
 */
edv_mime_type_struct **EDVMimeTypesListFileOpen(
	const gchar *filename, gint *total
)
{
	gchar *parm_str;
	FILE *fp;
	gulong file_size;
	gint mt_num = -1, ltotal = 0;
	edv_mime_type_struct *mt = NULL, **list = NULL;

	struct stat stat_buf;


	if(total != NULL)
	    *total = ltotal;

	if(STRISEMPTY(filename))
	    return(list);

	/* Open the MIME Types file for reading */
	fp = fopen(filename, "rb");
	if(fp == NULL)
	    return(list);

	/* Get the file statistics */
	if(fstat(fileno(fp), &stat_buf))
	    file_size = 0l;
	else
	    file_size = (gulong)stat_buf.st_size;

	/* Begin reading MIME Types file */
	parm_str = NULL;
	while(TRUE)
	{
	    /* Read next parameter */
	    parm_str = FSeekNextParm(
		fp, parm_str,
		EDV_CFG_COMMENT_CHAR,
		EDV_CFG_DELIMINATOR_CHAR
	    );
	    if(parm_str == NULL)
		break;

	    /* Begin handling by parameter */

	    /* BeginMIMEType */
	    if(!g_strcasecmp(parm_str, "BeginMIMEType"))
	    {
		gint value[1];
		edv_mime_type_class mt_class;

		/* Get class code */
		FGetValuesI(fp, value, 1);
		mt_class = (edv_mime_type_class)value[0];

		/* Append MIME Type */
		mt_num = MAX(ltotal, 0);
		ltotal = mt_num + 1;
		list = (edv_mime_type_struct **)g_realloc(
		    list, ltotal * sizeof(edv_mime_type_struct *)
		);
		if(list == NULL)
		{
		    ltotal = 0;
		    mt_num = -1;
		    mt = NULL;
		    break;
		}

		list[mt_num] = mt = EDVMimeTypeNew(
		    mt_class, NULL, NULL, NULL
		);
	    }

	    /* Type */
	    else if(!g_strcasecmp(parm_str, "Type"))
	    {
		gchar *type = FGetString(fp);
		if(mt != NULL)
		{
		    g_free(mt->type);
		    mt->type = STRDUP(type);
		}
		g_free(type);
	    }
	    /* Value */
	    else if(!g_strcasecmp(parm_str, "Value"))
	    {
		gchar *value = FGetString(fp);
		if(mt != NULL)
		{
		    g_free(mt->value);
		    mt->value = STRDUP(value);
		}
		g_free(value);
	    }
	    /* Description */
	    else if(!g_strcasecmp(parm_str, "Description"))
	    {
		gchar *description = FGetString(fp);
		if(mt != NULL)
		{
		    g_free(mt->description);
		    mt->description = STRDUP(description);
		}
		g_free(description);
	    }

	    /* IconSmallStandard */
	    else if(!g_strcasecmp(parm_str, "IconSmallStandard"))
	    {
		gchar *path = FGetString(fp);
		gchar **storage = &mt->small_icon_file[
		    EDV_MIME_TYPE_ICON_STATE_STANDARD
		];
		if(mt != NULL)
		{
		    g_free(*storage);
		    *storage = STRDUP(path);
		}
		g_free(path);
	    }
	    /* IconSmallSelected */
	    else if(!g_strcasecmp(parm_str, "IconSmallSelected"))
	    {
		gchar *path = FGetString(fp);
		gchar **storage = &mt->small_icon_file[
		    EDV_MIME_TYPE_ICON_STATE_SELECTED
		];
		if(mt != NULL)
		{
		    g_free(*storage);
		    *storage = STRDUP(path);
		}
		g_free(path);
	    }
	    /* IconSmallExtended */
	    else if(!g_strcasecmp(parm_str, "IconSmallExtended"))
	    {
		gchar *path = FGetString(fp);
		gchar **storage = &mt->small_icon_file[
		    EDV_MIME_TYPE_ICON_STATE_EXTENDED
		];
		if(mt != NULL)
		{
		    g_free(*storage);
		    *storage = STRDUP(path);
		}
		g_free(path);
	    }
            /* IconSmallHidden */
            else if(!g_strcasecmp(parm_str, "IconSmallHidden"))
            {
                gchar *path = FGetString(fp);
                gchar **storage = &mt->small_icon_file[
                    EDV_MIME_TYPE_ICON_STATE_HIDDEN
                ];
                if(mt != NULL)
                {
                    g_free(*storage);
                    *storage = STRDUP(path);
                }
                g_free(path);
            }

	    /* IconMediumStandard */
	    else if(!g_strcasecmp(parm_str, "IconMediumStandard"))
	    {
		gchar *path = FGetString(fp);
		gchar **storage = &mt->medium_icon_file[
		    EDV_MIME_TYPE_ICON_STATE_STANDARD
		];
		if(mt != NULL)
		{
		    g_free(*storage);
		    *storage = STRDUP(path);
		}
		g_free(path);
	    }
	    /* IconMediumSelected */
	    else if(!g_strcasecmp(parm_str, "IconMediumSelected"))
	    {
		gchar *path = FGetString(fp);
		gchar **storage = &mt->medium_icon_file[
		    EDV_MIME_TYPE_ICON_STATE_SELECTED
		];
		if(mt != NULL)
		{
		    g_free(*storage);
		    *storage = STRDUP(path);
		}
		g_free(path);
	    }
	    /* IconMediumExtended */
	    else if(!g_strcasecmp(parm_str, "IconMediumExtended"))
	    {
		gchar *path = FGetString(fp);
		gchar **storage = &mt->medium_icon_file[
		    EDV_MIME_TYPE_ICON_STATE_EXTENDED
		];
		if(mt != NULL)
		{
		    g_free(*storage);
		    *storage = STRDUP(path);
		}
		g_free(path);
	    }
            /* IconMediumHidden */
            else if(!g_strcasecmp(parm_str, "IconMediumHidden"))
            {
                gchar *path = FGetString(fp);
                gchar **storage = &mt->medium_icon_file[
                    EDV_MIME_TYPE_ICON_STATE_HIDDEN
                ];
                if(mt != NULL)
                {
                    g_free(*storage);
                    *storage = STRDUP(path);
                }
                g_free(path);
            }

	    /* IconLargeStandard */
	    else if(!g_strcasecmp(parm_str, "IconLargeStandard"))
	    {
		gchar *path = FGetString(fp);
		gchar **storage = &mt->large_icon_file[
		    EDV_MIME_TYPE_ICON_STATE_STANDARD
		];
		if(mt != NULL)
		{
		    g_free(*storage);
		    *storage = STRDUP(path);
		}
		g_free(path);
	    }
	    /* IconLargeSelected */
	    else if(!g_strcasecmp(parm_str, "IconLargeSelected"))
	    {
		gchar *path = FGetString(fp);
		gchar **storage = &mt->large_icon_file[
		    EDV_MIME_TYPE_ICON_STATE_SELECTED
		];
		if(mt != NULL)
		{
		    g_free(*storage);
		    *storage = STRDUP(path);
		}
		g_free(path);
	    }
	    /* IconLargeExtended */
	    else if(!g_strcasecmp(parm_str, "IconLargeExtended"))
	    {
		gchar *path = FGetString(fp);
		gchar **storage = &mt->large_icon_file[
		    EDV_MIME_TYPE_ICON_STATE_EXTENDED
		];
		if(mt != NULL)
		{
		    g_free(*storage);
		    *storage = STRDUP(path);
		}
		g_free(path);
	    }
            /* IconLargeHidden */
            else if(!g_strcasecmp(parm_str, "IconLargeHidden"))
            {
                gchar *path = FGetString(fp);
                gchar **storage = &mt->large_icon_file[
                    EDV_MIME_TYPE_ICON_STATE_HIDDEN
                ];
                if(mt != NULL)
                {
                    g_free(*storage);
                    *storage = STRDUP(path);
                }
                g_free(path);
            }

	    /* Handler */
	    else if(!g_strcasecmp(parm_str, "Handler"))
	    {
		gchar *s = FGetString(fp);
		if(mt != NULL)
		{
		    if(!g_strcasecmp(s, "Archiver"))
			mt->handler = EDV_MIME_TYPE_HANDLER_EDV_ARCHIVER;
		    else if(!g_strcasecmp(s, "ImageBrowser"))
			mt->handler = EDV_MIME_TYPE_HANDLER_EDV_IMAGE_BROWSER;
		    else if(!g_strcasecmp(s, "RecycleBin"))
			mt->handler = EDV_MIME_TYPE_HANDLER_EDV_RECYCLE_BIN;
		    else
			mt->handler = EDV_MIME_TYPE_HANDLER_COMMAND;
		}
		g_free(s);
	    }

	    /* Command */
	    else if(!g_strcasecmp(parm_str, "Command"))
	    {
                gchar *command = (gchar *)FGetString(fp);
                if((mt != NULL) && !STRISEMPTY(command))
                {
                    edv_mime_type_command_struct *cmd = EDVMimeTypeCommandNew();
                    if(cmd != NULL)
                    {
                        /* Seek s to the name and command deliminator */
                        gchar *s_cmd = (gchar *)strchr(
                            (char *)command,
                            EDV_CFG_DELIMINATOR_CHAR
                        );
                        if(s_cmd != NULL)
                        {
                            gchar *s_end = s_cmd;
                            gint len = (gint)(s_end - command);

                            s_cmd++;

                            cmd->name = (gchar *)g_malloc((len + 1) * sizeof(gchar));
                            if(len > 0)
                                memcpy(cmd->name, command, len * sizeof(gchar));
                            cmd->name[len] = '\0';
                            strstrip((char *)cmd->name);

                            cmd->command = STRDUP(s_cmd);
                            strstrip((char *)cmd->command);
                        }
                        else
                        {
                            /* No command deliminator, implying there is
                             * only a command
                             *
                             * Create an arbitrary name for this command
                             */
                            cmd->name = g_strdup_printf(
                                "Command #%i",
                                g_list_length(mt->commands_list) + 1
                            );

                            cmd->command = STRDUP(command);
                            strstrip((char *)cmd->command);
                        }

                        mt->commands_list = g_list_append(
                            mt->commands_list, cmd  
                        );
                    }
                }
                g_free(command);
	    }

	    /* AccessTime */
	    else if(!g_strcasecmp(parm_str, "AccessTime"))
	    {
		glong value[1];
		FGetValuesL(fp, value, 1);
		if(mt != NULL)
		    mt->access_time = (gulong)value[0];
	    }
	    /* ModifyTime */
	    else if(!g_strcasecmp(parm_str, "ModifyTime"))
	    {
		glong value[1];
		FGetValuesL(fp, value, 1);
		if(mt != NULL)
		    mt->modify_time = (gulong)value[0];
	    }
	    /* ChangeTime */
	    else if(!g_strcasecmp(parm_str, "ChangeTime"))
	    {
		glong value[1];
		FGetValuesL(fp, value, 1);
		if(mt != NULL)
		    mt->change_time = (gulong)value[0];
	    }

	    /* EndMIMEType */
	    else if(!g_strcasecmp(parm_str, "EndMIMEType"))
	    {
		FSeekNextLine(fp);

		/* Reset contexts */
		mt_num = -1;
		mt = NULL;
	    }
	    /* Unsupported parameter */
	    else
	    {
		/* Ignore unsupported parameter */
		FSeekNextLine(fp);
	    }
	}

	/* Delete the parameter */
	g_free(parm_str);

	/* Close the MIME Types file */
	fclose(fp);

	if(total != NULL)
	    *total = ltotal;

	return(list);
}
