/*-
 * Copyright (c) 2003-2004 Seth Kingsley.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgment:
 *    This product includes software developed by Seth Kingsley and
 *    contributors.
 * 4. Neither the author's name, nor any of the contributors names may be
 *    used to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include    <sys/cdefs.h>

#include    <gtk/gtkwidget.h>
#include    <gtk/gtkclist.h>
#include    <gtk/gtkstatusbar.h>

#include    <string.h>
#include    <assert.h>
#ifdef DEBUG
#include    <err.h>
#endif /* DEBUG */

#include    <xmk-gtk.h>

#include    "support.h"
#include    "portlist.h"
#include    "portsman.h"
#include    "refresh.h"
#include    "catlist.h"

__RCSID("$Id: catlist.c,v 1.20 2004/06/07 23:14:26 sethk Exp $");

struct catlist_data
{
    struct refresh_data	    *cd_rdatap;
    struct portlist_data    *cd_pldatap;
    struct cat_desc	    *cd_curcat;
    GtkCList		    *cd_catview;
    GtkVBox		    *cd_search_vbox;
    GtkStatusbar	    *cd_status_bar;
};

enum catlist_cols
{
    CLCOL_NAME,
    CLCOL_NCOL
};

struct catlist_data *cdatap;

struct catlist_data *
catlist_init(GtkWindow *app, struct refresh_data *rdp)
{
    static struct catlist_data	cdata;

    cdata.cd_rdatap = rdp;
    cdata.cd_pldatap = portlist_init(app, rdp, &cdata);

    cdata.cd_catview = GTK_CLIST(lookup_widget(GTK_WIDGET(app), "catlist"));
    gtk_clist_column_title_passive(cdata.cd_catview, CLCOL_NAME);

    cdata.cd_search_vbox =
	GTK_VBOX(lookup_widget(GTK_WIDGET(app), "search_vbox"));
    cdata.cd_status_bar =
	GTK_STATUSBAR(lookup_widget(GTK_WIDGET(app), "status_bar"));

    return (cdatap = &cdata);
}

void
catlist_fini(struct catlist_data *cdp)
{
    portlist_fini(cdp->cd_pldatap);
}

void
catlist_clear(struct catlist_data *cdp)
{
#ifdef DEBUG_VIEWS
    warnx("%s", __func__);
#endif /* DEBUG_VIEWS */

    if (cdp->cd_curcat)
	portlist_clear(cdp->cd_pldatap);

    gtk_widget_set_sensitive(GTK_WIDGET(cdp->cd_search_vbox), FALSE);

    gtk_clist_clear(cdp->cd_catview);
    gtk_widget_set_sensitive(gtk_widget_get_parent(
		GTK_WIDGET(cdp->cd_catview)), FALSE);

    gtk_statusbar_pop(cdp->cd_status_bar, 0);

    cdp->cd_curcat = NULL;
}

void
catlist_populate(struct catlist_data *cdp, GSList *cdlist)
{
    gchar   *status;

#ifdef DEBUG_VIEWS
    warnx("%s(%p)", __func__, cdlist);
#endif /* DEBUG_VIEWS */

    assert(!cdp->cd_curcat);

    gtk_clist_freeze(cdp->cd_catview);
    while (cdlist)
    {
	struct cat_desc	*cdescp = cdlist->data;

	catlist_add(cdp, cdescp, FALSE);
	cdlist = g_slist_next(cdlist);
    }
    gtk_clist_thaw(cdp->cd_catview);

    gtk_widget_set_sensitive(
	    gtk_widget_get_parent(GTK_WIDGET(cdp->cd_catview)), TRUE);
    gtk_widget_set_sensitive(GTK_WIDGET(cdp->cd_search_vbox), TRUE);

    status = g_strdup_printf(_("   %u ports, %u categories"),
	    refresh_numport(cdp->cd_rdatap),
	    refresh_numcat(cdp->cd_rdatap));
    gtk_statusbar_push(cdp->cd_status_bar,
	    0,
	    status);
    g_free(status);
}

void
catlist_refresh(struct catlist_data *cdp)
{
    if (cdp->cd_curcat)
    {
	if (cdp->cd_curcat->cd_dynamic)
	{
	    portlist_clear(cdp->cd_pldatap);
	    portlist_populate(cdp->cd_pldatap, cdp->cd_curcat);
	}
	else
	    portlist_refresh(cdp->cd_pldatap);
    }
}

void
catlist_add(struct catlist_data *cdp,
	struct cat_desc *cdescp,
	gboolean dynamic)
{
    gint    row;
    gchar   *text[] = {cdescp->cd_name, NULL};

    if (dynamic)
    {
	gtk_clist_freeze(cdp->cd_catview);
	row = gtk_clist_prepend(cdp->cd_catview, text);
    }
    else
	row = gtk_clist_append(cdp->cd_catview, text);
    gtk_clist_set_row_data(cdp->cd_catview, row, cdescp);

    if (dynamic)
    {
	gtk_clist_select_row(cdp->cd_catview, row, CLCOL_NAME);
	gtk_clist_moveto(cdp->cd_catview, row, CLCOL_NAME, 0, 0);
	gtk_clist_thaw(cdp->cd_catview);
    }
}

void
catlist_select(struct catlist_data *cdp, struct cat_desc *cdescp)
{
    xmk_clist_scroll_select_bydata(cdp->cd_catview, CLCOL_NAME, cdescp);
}

void
catlist_select_row(struct catlist_data *cdp, gint row)
{
    struct cat_desc *cdescp;
    guint	    nall, nport;
    gchar	    *status;

    if (!(cdescp = gtk_clist_get_row_data(cdp->cd_catview, row)))
	return;	/* populating, no row data. */

    nall = refresh_numport(cdp->cd_rdatap);

    xmk_busy_push(gtk_widget_get_parent_window(GTK_WIDGET(cdp->cd_catview)));

    nport = g_tree_nnodes(cdescp->cd_pdtree);

    if (cdp->cd_curcat)
    {
	portlist_clear(cdp->cd_pldatap);
	gtk_statusbar_pop(cdp->cd_status_bar, 0);
    }
    portlist_populate(cdp->cd_pldatap, cdescp);
    cdp->cd_curcat = cdescp;

    if (nport == nall)
	status = g_strdup_printf(_("   All %u ports"), nall);
    else
	status = g_strdup_printf(_("   %u of %u ports"), nport, nall);
    gtk_statusbar_push(cdp->cd_status_bar, 0, status);
    g_free(status);

    xmk_busy_pop(gtk_widget_get_parent_window(GTK_WIDGET(cdp->cd_catview)));
}

void
catlist_remove(struct catlist_data *cdp, struct cat_desc *cdescp)
{
    if (cdp->cd_curcat == cdescp)
	portlist_clear(cdp->cd_pldatap);

    gtk_clist_remove(cdp->cd_catview,
	    gtk_clist_find_row_from_data(cdp->cd_catview, cdescp));
}

const gchar *
catlist_getpath(struct catlist_data *cdp)
{
    const gchar	*wd;

    if ((wd = portlist_getpath(cdp->cd_pldatap)))
	return wd;
    else if (cdp->cd_curcat && cdp->cd_curcat->cd_real == TRUE)
	return cdp->cd_curcat->cd_name;
    else
	return NULL;
}

