/* Gnome-Streamer
 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */


#include <gst/gst.h>
#include <gnome.h>

struct element_select_classlist {
  gchar *name;
  GSList *subclasses;
  GSList *factories;
};

struct element_select_details {
  GstElementFactory *factory;
  GtkWidget *longname, *description, *version, *author, *copyright;
};

static gint compare_name(gconstpointer a,gconstpointer b) {
  return (strcmp(GST_OBJECT_NAME (a),
                 GST_OBJECT_NAME (b)));
}

gint str_compare(gconstpointer a,gconstpointer b) {
  return (strcmp((gchar *)a,(gchar *)b));
}

/* this function creates a GtkCTreeNode with the contents of the classtree */
static void make_ctree(GtkCTree *tree,GtkCTreeNode *parent,
                       struct element_select_classlist *class) {
  GSList *traverse;
  GtkCTreeNode *classnode, *node = NULL;
  gchar *data[2];

  data[0] = g_strdup(class->name);
  data[1] = NULL;
  classnode = gtk_ctree_insert_node(tree,parent,NULL,data,0,
                                    NULL,NULL,NULL,NULL,FALSE,TRUE);
  gtk_ctree_node_set_selectable(tree,classnode,FALSE);

  traverse = class->subclasses;
  while (traverse) {
    make_ctree(tree,classnode,
               (struct element_select_classlist *)(traverse->data));
    traverse = g_slist_next(traverse);
  }

  traverse = class->factories;
  while (traverse) {
    GstElementFactory *factory = (GstElementFactory *)(traverse->data);
    data[0] = g_strdup(GST_OBJECT_NAME (factory));
    data[1] = g_strdup(factory->details->description);
    node = gtk_ctree_insert_node(tree,classnode,NULL,data,0,
                                 NULL,NULL,NULL,NULL,TRUE,FALSE);
    gtk_ctree_node_set_row_data_full(tree,node,factory,NULL);
    traverse = g_slist_next(traverse);
  }
}

static void ctree_select(GtkWidget *widget,gint row,gint column,
                         GdkEventButton *bevent,gpointer data) {
  GtkCTree *tree = GTK_CTREE(widget);
  GtkCTreeNode *node;
  GstElementFactory *factory;
  struct element_select_details *details;
  node = gtk_ctree_node_nth(tree,row);
  factory = (GstElementFactory *)gtk_ctree_node_get_row_data(tree,node);
  if (!factory)
    return;
  details = (struct element_select_details *)data;
  details->factory = factory;

  gtk_entry_set_text(GTK_ENTRY(details->longname),
                     factory->details->longname);
  gtk_entry_set_text(GTK_ENTRY(details->description),
                     factory->details->description);
  gtk_entry_set_text(GTK_ENTRY(details->version),
                     factory->details->version);
  gtk_entry_set_text(GTK_ENTRY(details->author),
                     factory->details->author);
  gtk_entry_set_text(GTK_ENTRY(details->copyright),
                     factory->details->copyright);

  if (bevent && bevent->type == GDK_2BUTTON_PRESS)
    gtk_main_quit();
}


GstElementFactory *element_select_dialog() {
  GtkWidget *dialog;
  gchar *titles[2];
  GtkWidget *ctree;
  GtkWidget *scroller;
  GtkTable *table;
  GtkWidget *detailslabel;
  GtkWidget *detailshsep;
  GtkWidget *longname, *description, *version, *author, *copyright;

  GList *elements;
  GstElementFactory *element;
  gchar **classes, **class;
  GSList *classtree, *treewalk;
  GSList **curlist;
  struct element_select_classlist *branch = NULL;
  struct element_select_details details;

  /* first create the dialog and associated stuff */
  dialog = gnome_dialog_new("Select Element",
                            GNOME_STOCK_BUTTON_OK,
                            GNOME_STOCK_BUTTON_CANCEL,
                            NULL);
  gnome_dialog_set_close(GNOME_DIALOG(dialog),TRUE);
  gnome_dialog_close_hides(GNOME_DIALOG(dialog),TRUE);
  gnome_dialog_set_default(GNOME_DIALOG(dialog),GNOME_OK);

  titles[0] = "Element                               ";
  titles[1] = "Description";
  ctree = gtk_ctree_new_with_titles(2,0,titles);
  gtk_widget_set_usize(ctree,400,350);

  scroller = gtk_scrolled_window_new(NULL,NULL);
  gtk_container_add(GTK_CONTAINER(scroller),ctree);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroller),
                                 GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);
  gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox),scroller,
                             TRUE,TRUE,0);

  /* create the details table and put a title on it */
  table = GTK_TABLE(gtk_table_new(2,7,FALSE));
  detailslabel = gtk_label_new("Element Details:");
  gtk_misc_set_alignment(GTK_MISC(detailslabel),0.0,0.5);
  gtk_table_attach(table,detailslabel,0,2,0,1,GTK_FILL|GTK_EXPAND,0,0,0);

  /* then a separator to keep the title separate */
  detailshsep = gtk_hseparator_new();
  gtk_table_attach(table,detailshsep,0,2,1,2,GTK_FILL|GTK_EXPAND,0,0,0);

  /* the long name of the element */
  longname = gtk_label_new("Name:");
  gtk_misc_set_alignment(GTK_MISC(longname),1.0,0.5);
  gtk_table_attach(table,longname,0,1,2,3,GTK_FILL,0,5,0);
  details.longname = gtk_entry_new();
  gtk_entry_set_editable(GTK_ENTRY(details.longname),FALSE);
  gtk_table_attach(table,details.longname,1,2,2,3,GTK_FILL|GTK_EXPAND,0,0,0);

  /* the description */
  description = gtk_label_new("Description:");
  gtk_misc_set_alignment(GTK_MISC(description),1.0,0.5);
  gtk_table_attach(table,description,0,1,3,4,GTK_FILL,0,5,0);
  details.description = gtk_entry_new();
  gtk_entry_set_editable(GTK_ENTRY(details.description),FALSE);
  gtk_table_attach(table,details.description,1,2,3,4,GTK_FILL|GTK_EXPAND,0,0,0);

  /* the version */
  version = gtk_label_new("Version:");
  gtk_misc_set_alignment(GTK_MISC(version),1.0,0.5);
  gtk_table_attach(table,version,0,1,4,5,GTK_FILL,0,5,0);
  details.version = gtk_entry_new();
  gtk_entry_set_editable(GTK_ENTRY(details.version),FALSE);
  gtk_table_attach(table,details.version,1,2,4,5,GTK_FILL|GTK_EXPAND,0,0,0);

  /* the author */
  author = gtk_label_new("Author:");
  gtk_misc_set_alignment(GTK_MISC(author),1.0,0.5);
  gtk_table_attach(table,author,0,1,6,7,GTK_FILL,0,5,0);
  details.author = gtk_entry_new();
  gtk_entry_set_editable(GTK_ENTRY(details.author),FALSE);
  gtk_table_attach(table,details.author,1,2,6,7,GTK_FILL|GTK_EXPAND,0,0,0);

  /* the copyright */
  copyright = gtk_label_new("Copyright:");
  gtk_misc_set_alignment(GTK_MISC(copyright),1.0,0.5);
  gtk_table_attach(table,copyright,0,1,7,8,GTK_FILL,0,5,0);
  details.copyright = gtk_entry_new();
  gtk_entry_set_editable(GTK_ENTRY(details.copyright),FALSE);
  gtk_table_attach(table,details.copyright,1,2,7,8,GTK_FILL|GTK_EXPAND,0,0,0);

  gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox),GTK_WIDGET(table),
                             TRUE,TRUE,0);


  /* first create a sorted (by class) tree of all the factories */
  classtree = NULL;
  elements = gst_elementfactory_get_list();
  while (elements) {
    element = (GstElementFactory *)(elements->data);
    printf("%s %s\n", GST_OBJECT_NAME (element), element->details->klass);
    /* split up the factory's class */
    classes = g_strsplit(element->details->klass,"/",0);
    class = classes;
    curlist = &classtree;
    /* walk down the class tree to find where to place this element */
    /* the goal is for treewalk to point to the right class branch */
    /* when we exit this thing, branch is pointing where we want */
    while (*class) {
      treewalk = *curlist;
      /* walk the current level of class to see if we have the class */
      while (treewalk) {
        branch = (struct element_select_classlist *)(treewalk->data);
        /* see if this class matches what we're looking for */
        if (!strcmp(branch->name,*class)) {
          /* if so, we progress down the list into this one's list */
          curlist = &branch->subclasses;
          break;
        }
        treewalk = g_slist_next(treewalk);
      }
      /* if treewalk == NULL, it wasn't in the list. add one */
      if (treewalk == NULL) {
        /* curlist is pointer to list */
        branch = g_new0(struct element_select_classlist,1);
        branch->name = g_strdup(*class);
        *curlist = g_slist_insert_sorted(*curlist,branch,str_compare);
        curlist = &branch->subclasses;
      }
      class++;
    }
    /* theoretically branch points where we want now */
    branch->factories = g_slist_insert_sorted(branch->factories,element,
                                              compare_name);
    elements = g_list_next(elements);
  }

  /* now fill in the ... */
  gtk_clist_freeze(GTK_CLIST(ctree));
  treewalk = classtree;
  while (treewalk) {
    make_ctree(GTK_CTREE(ctree),NULL,
               (struct element_select_classlist *)(treewalk->data));
    treewalk = g_slist_next(treewalk);
  }
  gtk_clist_thaw(GTK_CLIST(ctree));

  gtk_signal_connect(GTK_OBJECT(ctree),"select_row",
                     GTK_SIGNAL_FUNC(ctree_select),&details);

  gtk_widget_show_all(GTK_WIDGET(dialog));

  details.factory = NULL;
  if (gnome_dialog_run_and_close(GNOME_DIALOG(dialog)) == GNOME_CANCEL)
    return NULL;
  else
    return details.factory;
};


/* this is available so we can do a quick test of this thing */
#ifdef ELEMENTSELECT_MAIN
int main(int argc,char *argv[]) {
  GstElementFactory *chosen;

  gst_init(&argc,&argv);
  gst_plugin_load_all();
  gnome_init("elementselect_test","0.0.0",argc,argv);
  chosen = element_select_dialog();
  if (chosen)
    g_print("selected '%s'\n",chosen->name);
  else
    g_print("didn't choose any\n");
  exit(0);
}
#endif /* ELEMENTSELECT_MAIN */