#include <string.h>

#include "support.h"

#include "perspic.h"

typedef struct {
  GtkWidget *tree;
  char *n;
} NTree;

static void **st1,**st,**ste;
static void **et1,**et,**ete;
static GtkStyle *style;
static GdkFont *font;

static void
tree_pointer_add(void ***p1,void ***p,void ***pe,void *pp) {

  void **tp;

  for (tp=*p1;tp<*p && *tp!=pp;tp++);
  if (tp<*p)
    return;

  if (*pe==*p) 
    r_mem(*p,(*pe-*p1)+20);

  **p=pp;
  (*p)++;

}

static GtkWidget *
tree_get_subtree(const char *t,GtkWidget *tree1,
		 unsigned *l1,unsigned *l3) {

  GtkWidget *subtree,*label;
  const char *t1;
  char *tt;
  GList *list,*list1;

  subtree=tree1;

  for (*l1=0;((t1=strchr(t,'/')) || (t1=t+strlen(t))>t);t=*t1 ? t1+1 : t1) {

    for (list=GTK_TREE(subtree)->children;
	 list;
	 list=g_list_next(list),(*l1)++) {

      label=GTK_WIDGET(GTK_BIN(list->data)->child);
      gtk_label_get(GTK_LABEL(label),&tt);

      if (!strncmp(t,tt,t1-t)) {

	if (!GTK_TREE_ITEM(list->data)->expanded) {

	  (*l1)++;
	  gtk_tree_item_expand(GTK_TREE_ITEM(list->data));
	  tree_pointer_add(&et1,&et,&ete,list->data);
	  list1=GTK_TREE(GTK_TREE_ITEM(list->data)->subtree)->children;
	  for (;list1;list1=g_list_next(list1),(*l3)++);


	}

	subtree=GTK_TREE_ITEM(list->data)->subtree;
	break;

      }

    }
    
    if (!list)
      err("list error\n");

  }

  return subtree;

}


static void
tree_erase_lines(GtkWidget *tree1) {

  GtkWidget *owner,*text1;

  for (;st && --st>=st1;) {

    gtk_widget_ref(*st);
    owner=GTK_TREE(*st)->tree_owner;
    gtk_tree_remove_items(GTK_TREE(*st),GTK_TREE(*st)->children);

    if (!GTK_WIDGET(*st)->parent) {

      gtk_tree_item_expand(GTK_TREE_ITEM(owner));
      gtk_tree_item_set_subtree(GTK_TREE_ITEM(owner),*st);

    } else
      gtk_widget_unref(*st);

  }
  st=st1;

  for (;et && --et>=et1;) 
    gtk_tree_item_collapse(GTK_TREE_ITEM(*et));

  et=et1;

  text1=lookup_widget(GTK_WIDGET(tree1),"text1");
  text_write_text(text1,NULL);


}

void
tree_set_font(GtkWidget *tree1,GdkFont *f) {

  font=f;
  tree_load_lines(tree1);

}

static void
tree_style_push(void) {

  static GdkFont *lfont;
  GdkFont *ifont;
    
  if (!style) {
    style=gtk_style_copy(gtk_widget_get_default_style());
    ifont=gdk_font_load("-adobe-courier-medium-r-normal-*-*-120-*-*-m-*-iso8859-1");
    style->font=ifont ? ifont : style->font;
  }

  if (font && !gdk_font_equal(style->font,font)) {
    
    if (lfont)
      gdk_font_unref(lfont);
    
    lfont=style->font=font;
    gdk_font_ref(lfont);
  }
  
  if (style)
    gtk_widget_push_style(style);
  
}


static void
tree_style_pop(void) {

  gtk_widget_pop_style();

}


static void
tree_new_line(GtkWidget *subtree,const Hit *h) {

  GtkWidget *item1,*label;

  item1=gtk_tree_item_new_with_label("");
  label=GTK_WIDGET(GTK_BIN(item1)->child);
  
  gtk_label_set_text(GTK_LABEL(label),*query_format_line(h,80));
  gtk_widget_show(label);
  
  gtk_tree_append(GTK_TREE(subtree),item1);
  tree_pointer_add(&st1,&st,&ste,subtree);
  
  gtk_widget_show(item1);
  gtk_signal_connect (GTK_OBJECT(item1), "select",text_write_text,(gpointer) h);

  gtk_tree_item_expand(GTK_TREE_ITEM(item1));
  
}

static void
tree_set_adjustment(GtkWidget *tree1,unsigned l2,unsigned l3) {

  GtkWidget *sw;
  GtkObject *adj=NULL;

  if ((sw=lookup_widget(GTK_WIDGET(tree1),"scrolledwindow1")))
    adj=GTK_OBJECT(GTK_RANGE(GTK_SCROLLED_WINDOW(sw)->vscrollbar)->adjustment);
  
  if (adj) {
    while (gtk_events_pending())
      gtk_main_iteration();
    gtk_adjustment_set_value(GTK_ADJUSTMENT(adj),
			     (GTK_ADJUSTMENT(adj)->upper -
			      GTK_ADJUSTMENT(adj)->lower) *
			     ((float)l2/l3) -
			     0.5*GTK_ADJUSTMENT(adj)->page_size);
  }

}


void
tree_load_lines(GtkWidget *tree1) {
  
  Hit *h;
  GtkWidget *subtree=NULL;
  const char *f;
  unsigned l1,l2,l3;
  GList *list;
  const Query *q=query_current();

  tree_erase_lines(tree1);
  tree_style_push();

  l1=l2=l3=0;
 
  if (q) {
    
    for (list=GTK_TREE(tree1)->children;list;list=g_list_next(list),l3++);
    
    for (h=q->h,f=NULL;h<q->he;h++) {
      
      if (h->f!=f) {
	
	subtree=tree_get_subtree(h->f,tree1,&l1,&l3);
	f=h->f;
	
      }
      
      if (!l2)
	l2=l1;
      
      tree_new_line(subtree,h);
      l3++;
      
    }
    
  }
  
  tree_set_adjustment(tree1,l2,l3);
  
  tree_style_pop();
  
}


static void
select_file(GtkWidget *item,const char *s) {

  GtkWidget *tree1;
  Query *q;
  
  q=(Query *)query_word_lines(20,s);
  if ((tree1=lookup_widget(GTK_WIDGET(item),"tree1")))
    tree_load_lines(tree1);

}

int
tree_make_dict_tree(GtkWidget *tree1,const char *f1,const char *fe) {

  static NTree *n1,*n,*ne,*nn;
  const char *f,*t,*t1;
  GtkWidget *item1,*subtree,*owner;

  tree_erase_lines(tree1);
  gtk_widget_ref(tree1);
  owner=GTK_TREE(tree1)->tree_owner;
  gtk_tree_remove_items(GTK_TREE(tree1),GTK_TREE(tree1)->children);
  
  if (!GTK_WIDGET(tree1)->parent) {
    
    gtk_tree_item_expand(GTK_TREE_ITEM(owner));
    gtk_tree_item_set_subtree(GTK_TREE_ITEM(owner),tree1);
    
  } else
    gtk_widget_unref(tree1);

  subtree=tree1;
  for (n=n1,f=f1;f<fe;f+=strlen(f)+1) {

    for (t=f,nn=n1;nn<n && ((t1=strchr(t,'/')) || (t1=t+strlen(t))>t) && 
	   !memcmp(nn->n,t,t1-t);nn++,t=*t1 ? t1+1 : t1);
    
    if (nn<n)
      subtree=nn->tree;
    
    for (n=nn;((t1=strchr(t,'/')) || (t1=t+strlen(t))>t);n++,t=*t1 ? t1+1 : t1) {
      
      if (n==ne) 
	r_mem(n,(ne-n1)+20);
      
      n->tree=subtree;

      emem(n->n,t1-t+1);
      memcpy(n->n,t,t1-t);
      
      item1=gtk_tree_item_new_with_label(n->n);
      gtk_signal_connect (GTK_OBJECT(item1), "select",
			  GTK_SIGNAL_FUNC(select_file), (gpointer)f);
      gtk_tree_append(GTK_TREE(subtree),item1);
      gtk_widget_show(item1);
      subtree=gtk_tree_new();
      gtk_tree_item_set_subtree(GTK_TREE_ITEM(item1), subtree);
      
    }
    
  }

  return 0;

}

