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

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

#include "edvmimetypes.h"
#include "edvmimetypesfio.h"
#include "config.h"


edv_mimetype_struct **EDVMimeTypeListLoadFromFile(
	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_mimetype_struct **EDVMimeTypeListLoadFromFile(
	const gchar *filename, gint *total
)
{
	gchar *parm_str;
	FILE *fp;
	gulong file_size;
	gint mt_num = -1, ltotal = 0;
	edv_mimetype_struct *mt_ptr = NULL, **list = NULL;

	struct stat stat_buf;


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

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

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

	/* Get 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_mimetype_class mt_class;

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

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

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

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

	    /* IconSmallStandard */
	    else if(!g_strcasecmp(parm_str, "IconSmallStandard"))
	    {
		gchar *path = FGetString(fp);
		gchar **storage = &mt_ptr->small_icon_file[
		    EDV_MIMETYPE_ICON_STATE_STANDARD
		];
		if(mt_ptr != 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_ptr->small_icon_file[
		    EDV_MIMETYPE_ICON_STATE_SELECTED
		];
		if(mt_ptr != 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_ptr->small_icon_file[
		    EDV_MIMETYPE_ICON_STATE_EXTENDED
		];
		if(mt_ptr != 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_ptr->small_icon_file[
                    EDV_MIMETYPE_ICON_STATE_HIDDEN
                ];
                if(mt_ptr != 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_ptr->medium_icon_file[
		    EDV_MIMETYPE_ICON_STATE_STANDARD
		];
		if(mt_ptr != 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_ptr->medium_icon_file[
		    EDV_MIMETYPE_ICON_STATE_SELECTED
		];
		if(mt_ptr != 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_ptr->medium_icon_file[
		    EDV_MIMETYPE_ICON_STATE_EXTENDED
		];
		if(mt_ptr != 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_ptr->medium_icon_file[
                    EDV_MIMETYPE_ICON_STATE_HIDDEN
                ];
                if(mt_ptr != 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_ptr->large_icon_file[
		    EDV_MIMETYPE_ICON_STATE_STANDARD
		];
		if(mt_ptr != 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_ptr->large_icon_file[
		    EDV_MIMETYPE_ICON_STATE_SELECTED
		];
		if(mt_ptr != 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_ptr->large_icon_file[
		    EDV_MIMETYPE_ICON_STATE_EXTENDED
		];
		if(mt_ptr != 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_ptr->large_icon_file[
                    EDV_MIMETYPE_ICON_STATE_HIDDEN
                ];
                if(mt_ptr != NULL)
                {
                    g_free(*storage);
                    *storage = STRDUP(path);
                }
                g_free(path);
            }

	    /* Handler */
	    else if(!g_strcasecmp(parm_str, "Handler"))
	    {
		gchar *s = FGetString(fp);
		if(mt_ptr != NULL)
		{
		    if(!g_strcasecmp(s, "Archiver"))
			mt_ptr->handler = EDV_MIMETYPE_HANDLER_EDV_ARCHIVER;
		    else if(!g_strcasecmp(s, "ImageBrowser"))
			mt_ptr->handler = EDV_MIMETYPE_HANDLER_EDV_IMAGE_BROWSER;
		    else if(!g_strcasecmp(s, "RecycleBin"))
			mt_ptr->handler = EDV_MIMETYPE_HANDLER_EDV_RECYCLE_BIN;
		    else
			mt_ptr->handler = EDV_MIMETYPE_HANDLER_COMMAND;
		}
		g_free(s);
	    }

	    /* Command */
	    else if(!g_strcasecmp(parm_str, "Command"))
	    {
		gint n;
		gchar *command = FGetString(fp);

		if(mt_ptr != NULL)
		{
		    /* Allocate more pointers for this new command */
		    n = MAX(mt_ptr->total_commands, 0);
		    mt_ptr->total_commands = n + 1;

		    mt_ptr->command = (gchar **)g_realloc(
		        mt_ptr->command,
		        mt_ptr->total_commands * sizeof(gchar *)
		    );
		    mt_ptr->command_name = (gchar **)g_realloc(
		        mt_ptr->command_name,
			mt_ptr->total_commands * sizeof(gchar *)
		    );
		    if((mt_ptr->command == NULL) ||
		       (mt_ptr->command_name == NULL)
		    )
		    {
		        g_free(mt_ptr->command);
		        mt_ptr->command = NULL;
		        g_free(mt_ptr->command_name);
		        mt_ptr->command_name = NULL;
		        mt_ptr->total_commands = 0;
		    }
		    else
		    {
		        gchar *s2;

		        mt_ptr->command[n] = NULL;
		        mt_ptr->command_name[n] = NULL;

		        if(command != NULL)
		        {
			    mt_ptr->command_name[n] = STRDUP(command);
			    s2 = strchr(
			        mt_ptr->command_name[n],
			        EDV_CFG_DELIMINATOR_CHAR
			    );
			    if(s2 != NULL)
			        *s2 = '\0';

			    s2 = strchr(command, EDV_CFG_DELIMINATOR_CHAR);
			    if(s2 == NULL)
			        s2 = command;
			    else
			        s2++;
			    mt_ptr->command[n] = STRDUP(s2);
		        }
		    }
		}
		g_free(command);
	    }

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

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

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

	/* Delete parameter */
	g_free(parm_str);

	/* Close MIME Types file */
	FClose(fp);

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

	return(list);
}
