
#include <config.h>

#include <glib.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "global.h"
#include "color.h"
#include "util.h"
#include "mountlist.h"
#include "panel.h"
#include "main.h"
#include "dialog.h"

#include "wtools.h"
#include "widget.h"

#include "cmd.h"
#include "tty.h"

#include "selmnt.h"

#ifdef HAVE_SLANG
#include "myslang.h"
#endif

/* uncomment to retrieve FS usage statistics (may be slow) */
/* #define MNT_USE_GET_FS_USAGE */

extern unsigned char get_hotkey(int);

int mc_cd_mountpoint_and_dir = 0;

extern struct mount_entry *mount_list;
extern void listbox_select_by_number (struct WListbox *l, int n);

#ifdef __BEOS__
struct mount_entry *read_filesystem_list (int need_fs_type, int all_fs);

struct mount_entry *
read_filesystem_list (int need_fs_type, int all_fs)
{
    static struct mount_entry *me = NULL;

    if (me)
    {
	g_free (me->me_devname);
	g_free (me->me_mountdir);
	g_free (me->me_type);
	return NULL;
    }

    me = g_new0 (struct mount_entry, 1);
    me->me_devname = g_strdup("//");
    me->me_mountdir = g_strdup("//");
    me->me_type = g_strdup("unknown");

    return me;
}
#endif /*__BEOS__*/

/* create own listbox window */
Listbox *
create_custom_listbox_window (WPanel *panel, int cols, int lines,
				const char *title _ATTRIBUTE_UNUSED_,
                                const char *help)
{
    int x, y, w, h;
    int widget_x, widget_y;
    Listbox *listbox = g_new0 (Listbox, 1);

    if (!listbox)
	return NULL;

    widget_x = panel->widget.x;
    widget_y = panel->widget.y;

    y = widget_y;
    h = lines + 2;

    if (h <= y || y > LINES - 6)
    {
        h = min (h, y - 1);
        y -= h;
    }
    else
    {
        y++;
        h = min (h, LINES - y);
    }

    x = widget_x;

    if ((w = cols + 4) + x > COLS)
    {
        w = min (w, COLS);
    }

    x = widget_x + (panel->widget.cols - w)/2;
    /* additional checking */
    x = x > 0 ? x : widget_x + 3;
    y = widget_y + (panel->widget.lines - h)/2;

    /*  Create components */
    listbox->dlg = create_dlg (y, x, h, w, dialog_colors, NULL,
				help, _("Mount points"), DLG_COMPACT);
    listbox->list = listbox_new (1, 1, w - 2, h - 2, 0);
    add_widget (listbox->dlg, listbox->list);

    return listbox;
}

/* show mounts list */
static
int show_mnt (Mountp *mntpoints, WPanel *panel)
{
    unsigned char hotkey;
    Mountp *mz, *mhi;
    int menu_lines, i, maxlen = 5, count = 0;
    Listbox *listbox;

    if (!mntpoints)
        return 0;

    mz = mntpoints;

    while (mz->prev)           /* goto first */
        mz = mz->prev;

    mhi = mz;

    while (mhi)
    {
	if ((i = strlen (mhi->mpoint)
	    + (mc_cd_mountpoint_and_dir ? 6 : 4)
	    + ((mhi->path && mc_cd_mountpoint_and_dir) ? strlen (mhi->path) : 0)) > maxlen)
	maxlen = i;

	count++;
	mhi = mhi->next;
    }

    /* count = number of elements
     * maxlen = maximum long of mountpoint menu item name */
    menu_lines = count;

    /* Create listbox */
    listbox = create_custom_listbox_window (panel, maxlen, menu_lines,
					    "Mountpoints", "Mountpoints");

    if (!listbox)
	return -1;

    i = 0;

    while (mz)
    {
	static char buffer[4096];
	    /* sprintf( buffer, "%s (%d/%d)", mz->mpoint, mz->total/1024, mz->avail/1024 ); */ /* for example! */
	    /* sprintf( buffer, "%s", mz->mpoint); */

	hotkey = get_hotkey (i);

	if (mc_cd_mountpoint_and_dir && mz->path) 
	    snprintf (buffer, sizeof(buffer), "%c  %s [%s]", hotkey, mz->mpoint, mz->path);
        else
	    snprintf (buffer, sizeof(buffer),"%c  %s", hotkey, mz->mpoint);

	LISTBOX_APPEND_TEXT(listbox, hotkey, buffer, NULL);

	mz = mz->next;
	i++;
    }

    /* Select the default entry */
    listbox_select_by_number (listbox->list, 0);

    return run_listbox(listbox);
}

/* init Mountp
 * First - we need helper, that must identify our last dir in this mountpoint
 * from dir_history */

static char *
path_from_history (WPanel *panel, char *mountpoint)
{
    GList *hd, *d;

    hd = panel->dir_history;

    if (!hd)
	return NULL;

    if (!strcmp (mountpoint, PATH_SEP_STR))
	return NULL;

    d = hd = g_list_first (hd);

    while ((d = g_list_next (d)))
	hd = d;

    do
    {
	if (strcmp (mountpoint, (char *)(hd->data)))
	    if (!strncmp (mountpoint, (char *)(hd->data), strlen(mountpoint)))
		return (char *)(hd->data);

	hd = g_list_previous(hd);
    }
    while (hd);

    return NULL;
}

Mountp *
init_mountp (WPanel *panel)
{
    gboolean lockm = FALSE;
    Mountp *mounts = NULL;
    struct mount_entry *temp = NULL;
    struct mount_entry *it = NULL;

#ifdef MNT_USE_GET_FS_USAGE
    struct fs_usage fs_use;
#endif

    it = temp = read_filesystem_list(0, 0);

    if (!temp)
	return NULL;

    while (temp)
    {
	if (!strncmp(temp->me_mountdir, "/dev/", 5)
	    || !strncmp(temp->me_mountdir, "/sys/", 5)
	    || !strncmp(temp->me_mountdir, "/lib/", 5)
	    || !strncmp(temp->me_mountdir, "/proc/", 6))
	{
	    temp = temp->me_next;
	    continue;
	}

	if (!mounts)
	{
#ifdef MNT_USE_GET_FS_USAGE
	    get_fs_usage (temp->me_mountdir, &fs_use);
#endif
	    mounts = g_new0 (Mountp, 1);
	    mounts->mpoint = g_strdup (temp->me_mountdir);
	    mounts->path = mc_cd_mountpoint_and_dir ? g_strdup (path_from_history (panel, temp->me_mountdir)) : NULL;
	    mounts->name = g_strdup (temp->me_devname);

#ifdef MNT_USE_GET_FS_USAGE
	    mounts->avail = getuid () ? fs_use.fsu_bavail/2 : fs_use.fsu_bfree/2;
	    mounts->total = fs_use.fsu_blocks/2;
#endif
            lockm = TRUE;
	}

	if (mounts->next)
	{
	    g_free (mounts->next->mpoint);
	    g_free (mounts->next->name);
	}
	else
	{
	    mounts->next = g_new0 (Mountp, 1);
	    mounts->next->prev = mounts;
	}

	if (!lockm)
	{
#ifdef MNT_USE_GET_FS_USAGE
	    get_fs_usage (temp->me_mountdir, &fs_use);
#endif
	    mounts = mounts->next;
	    mounts->mpoint = g_strdup (temp->me_mountdir);
	    mounts->name = g_strdup (temp->me_devname);
	    mounts->path = mc_cd_mountpoint_and_dir ? g_strdup (path_from_history (panel, temp->me_mountdir)) : NULL;
#ifdef MNT_USE_GET_FS_USAGE
	    mounts->avail = getuid () ? fs_use.fsu_bavail/2 : fs_use.fsu_bfree/2;
	    mounts->total = fs_use.fsu_blocks/2;
#endif
	}

	lockm = FALSE;
	temp = temp->me_next;
    }

    /* free memory */
    if (it)
    {
	temp = it;

	while (temp)
	{
	    g_free (temp->me_type);
	    g_free (temp->me_mountdir);
	    g_free (temp->me_devname);

	    it = temp;
	    temp = temp->me_next;
	    g_free (it);
	}
    }

    return mounts; /* must be freed! */
}

static int
select_mountpoint (WPanel *panel)
{
    int i, inta;
    char *s = NULL;
    Mountp *mount_ls = init_mountp (panel);
    Mountp *tmp = mount_ls;

    if(mount_ls && (mount_ls->prev || mount_ls->next))
    {
	inta = show_mnt (mount_ls, panel);

        if (inta != -1)
	{
	    while (mount_ls->prev)           /* goto first */
		mount_ls = mount_ls->prev;

	    for ( i = 0; i < inta; i++)
		if (mount_ls->next)
		    mount_ls = mount_ls->next;

	    /* resulting dirname */
	    if (mc_cd_mountpoint_and_dir && mount_ls->path)
		s = mount_ls->path;
	    else if (mount_ls->mpoint)
		s = mount_ls->mpoint;
	}

	if (s) /* execute CD */
	    do_panel_cd (panel, s, cd_exact);
	else /* execute command */
	{ }

	/* free mem */
	while (tmp->prev)
	    tmp = tmp->prev;

	mount_ls = tmp;

	while (mount_ls)
	{
	    g_free (mount_ls->path);
	    g_free (mount_ls->name);
	    g_free (mount_ls->mpoint);

	    tmp = mount_ls;
	    mount_ls = mount_ls->next;
	    g_free (tmp);
	}
    }

    return 1;
}

//------------------ programming interfaces
void select_mnt_left (void)
{
    switch_to_listing (0);
    select_mountpoint (left_panel);
}


void select_mnt_right (void)
{
    switch_to_listing (1);
    select_mountpoint (right_panel);
}
