/* IglooFTP - Graphical and User Friendly FTP Client.
 * Copyright (c) 1998-1999 Jean-Marc Jacquet. 
 * All rights reserved.
 * 
 * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE
 *
 * IglooFTP Original Packages, information and support,  
 * can be obtained at :
 *                              http://www.littleigloo.org
 * 
 *
 */

#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "protos.h"

#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>


static char SHOW_HIDDEN = FALSE;

static char DIR_TREE_browse_directory (GtkCTree * ctree, GtkCTreeNode * parent, char *this_pathname, char LOOK_IN);
static void DIR_TREE_selected_row (GtkCTree * ctree, GtkCTreeNode * node, gint col, /*GdkEventButton *event, */ GtkWidget * label);
static void DIR_TREE_tree_expand (GtkCTree * ctree, GtkCTreeNode * node, /*GdkEventButton *event, */ gpointer data);
static GtkCTreeNode *DIR_TREE_find_parent (GtkCTree * ctree, GtkCTreeNode * node, char *data);


static char
DIR_TREE_browse_directory (GtkCTree * ctree, GtkCTreeNode * parent, char *this_pathname, char LOOK_IN)
{
  DIR *this_dir = NULL;
  struct dirent *dirlist;
  struct stat stat_buf;
  char path_buf[1024];
  char *pathname = strdup (this_pathname);
  char PARENT_BROWSED_FLAG = FALSE;
  char CONTAINS_SUBDIR = FALSE;
  GtkCTreeNode *node = NULL;
  GdkPixmap *dclosepix, *dopenpix, *dlclosepix, *dlopenpix;
  GdkBitmap *dclosemsk, *dopenmsk, *dlclosemsk, *dlopenmsk;
  gchar *col[1];
  static gchar *default_look_in_dir_name[1] =
  {"iglooftp_tmp_node"};
  dclosepix = folder_pixmap (&dclosemsk);
  dopenpix = folder_open_pixmap (&dopenmsk);
  dlclosepix = dlink_pixmap (&dlclosemsk);
  dlopenpix = folder_open_pixmap (&dlopenmsk);


  PROCESS_EVENTS;

  stat (this_pathname, &stat_buf);
  if ((stat_buf.st_mode & S_IFMT) != S_IFDIR)	/* check that this_pathname is a valid dir */
    {
      printf ("not a dir : %s\n", pathname);
      CONTAINS_SUBDIR = 0;
      goto end_of_sub_routine;
    }

  //printf ("dir : %s\n", pathname);


  if (!LOOK_IN)
    {
      GtkCTreeNode *search_node = GTK_CTREE_ROW (parent)->children;
      gchar *nodename;

      gtk_clist_freeze (GTK_CLIST (ctree));

      while (search_node != NULL)	//search for tempory node added and delete it

	{
	  gtk_ctree_node_get_pixtext (ctree, search_node, 0, &nodename, NULL, NULL, NULL);
	  if (!strcmp (nodename, default_look_in_dir_name[0]))
	    {
	      gtk_ctree_remove_node (ctree, search_node);
	      search_node = NULL;
	    }
	  else
	    search_node = GTK_CTREE_NODE_NEXT (search_node);
	}
    }



  if ((this_dir = opendir (pathname)))
    {
      while ((dirlist = readdir (this_dir)))
	{
	  sprintf (path_buf, "%s/%s", pathname, dirlist->d_name);	/* Build absolute filename */
	  stat (path_buf, &stat_buf);

	  if ((stat_buf.st_mode & S_IFMT) == S_IFDIR)	/* Browse only dirs */
	    {
	      char SHOW_IT = TRUE;


	      if (SHOW_HIDDEN)	/* -- If must show hidden files, don't show "." & ".." Else don't show dir begining with a dot -- */
		{
		  if (dirlist->d_name[0] == '.')
		    switch (dirlist->d_name[1])
		      {
		      case 0:
			SHOW_IT = FALSE;
			break;
		      case '.':
			SHOW_IT = (dirlist->d_name[2] != 0);
			break;
		      }
		}
	      else
		SHOW_IT = (dirlist->d_name[0] != '.');


	      if (DIR_TREE_find_parent (ctree, parent, dirlist->d_name) != NULL)	/* don't add path that was already added */
		SHOW_IT = FALSE;	/* (search if it appears in the children nodes of the actual parent node) */


	      if (SHOW_IT)	/*So, we must show this one */
		{
		  CONTAINS_SUBDIR = TRUE;
		  col[0] = dirlist->d_name;
		  if (LOOK_IN)
		    col[0] = default_look_in_dir_name[0];
		  lstat (path_buf, &stat_buf);

		  if ((stat_buf.st_mode & S_IFMT) != S_IFLNK)
		    node = gtk_ctree_insert_node (ctree, parent, node, col, 7, dclosepix, dclosemsk, dopenpix, dopenmsk, FALSE, FALSE);
		  else
		    node = gtk_ctree_insert_node (ctree, parent, node, col, 7, dlclosepix, dlclosemsk, dlopenpix, dlopenmsk, FALSE, FALSE);


		  if (!LOOK_IN)	/* if not checking for the first subdir */
		    {
		      if (!PARENT_BROWSED_FLAG)		/* if parent not yet marked as browsed, mark it (first character != B)  */
			{
			  char *ptr = gtk_ctree_node_get_row_data (ctree, parent);
			  if (ptr != NULL && *ptr != 'B')
			    {
			      char *new_ptr = strdup (ptr);
			      new_ptr[0] = 'B';
			      gtk_ctree_node_set_row_data_full (ctree, parent, strdup (new_ptr), (GtkDestroyNotify) free);
			      free (new_ptr);
			      free (ptr);	// verify that this is a good thing to do       

			      PARENT_BROWSED_FLAG = TRUE;
			    }
			}
		      if (strlen (pathname) > 1)
			sprintf (path_buf, " %s/%s", pathname, col[0]);
		      else
			sprintf (path_buf, " %s%s", pathname, col[0]);

		      if (!DIR_TREE_browse_directory (ctree, node, path_buf + 1, TRUE))		/* look if there is at least one dir in this subdir */
			path_buf[0] = 'B';	/*if not marking it as browsed  */


		      gtk_ctree_node_set_row_data_full (ctree, node, strdup (path_buf), (GtkDestroyNotify) free);	/* add dir to tree */
		    }
		  else
		    goto end_of_sub_routine;	/* we have found one dir in this subdir, return whithout browse it completely  */
		}

	    }
	}

      if (!LOOK_IN)
	{
	  gtk_ctree_sort_node (ctree, parent);	/* alphasort tree node */
	  gtk_clist_thaw (GTK_CLIST (ctree));
	}
    }

end_of_sub_routine:
  if (this_dir)
    closedir (this_dir);
  free (pathname);

  gdk_pixmap_unref (dclosepix);
  gdk_pixmap_unref (dclosemsk);
  gdk_pixmap_unref (dopenpix);
  gdk_pixmap_unref (dopenmsk);
  gdk_pixmap_unref (dlclosepix);
  gdk_pixmap_unref (dlclosemsk);
  gdk_pixmap_unref (dlopenpix);
  gdk_pixmap_unref (dlopenmsk);

  return CONTAINS_SUBDIR;
}



static void
DIR_TREE_selected_row (GtkCTree * ctree, GtkCTreeNode * node, gint col, /*GdkEventButton *event, */ GtkWidget * label)
{
  char *ptr = gtk_ctree_node_get_row_data (ctree, node);

  if (ptr != NULL)
    gtk_label_set (GTK_LABEL (label), ++ptr);
}



static void
DIR_TREE_tree_expand (GtkCTree * ctree, GtkCTreeNode * node, /*GdkEventButton *event, */ gpointer data)
{
  char *ptr = gtk_ctree_node_get_row_data (ctree, node);

  if (ptr != NULL)
    if (*ptr != 'B')
      DIR_TREE_browse_directory (ctree, node, ptr + 1, FALSE);

  gtk_ctree_select (ctree, node);
}



static GtkCTreeNode *
DIR_TREE_find_parent (GtkCTree * ctree, GtkCTreeNode * node, char *data)
{
  char *ptr = NULL;

  if (node != NULL)
    {
      node = GTK_CTREE_ROW (node)->children;
      while (node != NULL)
	{
	  ptr = gtk_ctree_node_get_row_data (ctree, node);
	  if (ptr != NULL)
	    if (strstr (ptr, data) != NULL)
	      break;
	  node = GTK_CTREE_NODE_NEXT (node);
	}
    }

  return node;
}




GtkCTreeNode *
DIR_TREE_show_path (GtkCTree * ctree, char *pathname)
{
  GtkCTreeNode *node = NULL;

  const char slash = '/';
  char *dir_ptr = strdup (pathname);
  char *this_pathname = strdup (pathname);
  char *ptr_deb = this_pathname;
  char *ptr_end;

  //printf("\n---\n");

  node = gtk_ctree_node_nth (GTK_CTREE (ctree), 0);

  if (node != NULL)
    {
      if (strlen (pathname))
	{

	  if (!strcmp (ptr_deb, "/"))
	    {
	      DIR_TREE_browse_directory (ctree, node, "/", FALSE);
	      gtk_ctree_select (ctree, node);
	      gtk_ctree_node_moveto (ctree, node, -1, 0.5, 0);
	      goto end_of_sub_routine;
	    }


	  strcpy (dir_ptr, "");
	  while (ptr_deb != NULL)
	    {
	      ptr_deb = strchr (ptr_deb, slash);
	      ptr_end = strchr (++ptr_deb, slash);
	      strcat (dir_ptr, "/");
	      if (ptr_end != NULL)
		strncat (dir_ptr, ptr_deb, (char *) ptr_end - (char *) ptr_deb);
	      else
		strcat (dir_ptr, ptr_deb);
	      ptr_deb = ptr_end;

	      if ((node = DIR_TREE_find_parent (ctree, node, dir_ptr)) != NULL)
		{
		  //printf ("> %s\n", dir_ptr);
		  DIR_TREE_browse_directory (ctree, node, dir_ptr, FALSE);
		  gtk_ctree_expand (ctree, node);
		  gtk_ctree_node_moveto (ctree, node, -1, 0.5, 0);
		  PROCESS_EVENTS;
		}
	    }
	}
    }

end_of_sub_routine:
  free (dir_ptr);
  free (this_pathname);
  return node;
}



void
DIR_TREE_init (GtkCTree * ctree, char *pathname, char *rootname)
{
  GtkCTreeNode *node = NULL;
  GdkPixmap *rootpix;
  GdkBitmap *rootmsk;
  gchar *col[1];
  char this_path[1024];

  col[0] = rootname;
  rootpix = computer_pixmap (&rootmsk);
  strncpy (this_path, pathname, sizeof (this_path) - 1);

  if (access (this_path, F_OK))
    getcwd (this_path, sizeof (this_path) - 1);


  gtk_widget_set_sensitive (GTK_WIDGET (ctree), FALSE);

  node = gtk_ctree_insert_node (ctree, NULL, node, col, 7, rootpix, rootmsk, rootpix, rootmsk, FALSE, TRUE);
  gtk_ctree_node_set_row_data (ctree, node, "B/");
  DIR_TREE_browse_directory (ctree, node, "/", FALSE);

  node = DIR_TREE_show_path (ctree, this_path);

  gtk_widget_set_sensitive (GTK_WIDGET (ctree), TRUE);
  gtk_ctree_node_moveto (ctree, node, 1, 0.5, 0);

  gdk_pixmap_unref (rootpix);
  gdk_pixmap_unref (rootmsk);
}



GtkWidget *
DIR_TREE_create (GtkCTree ** Ctree, GtkWidget ** Label, char show_hidden)
{
  GtkWidget *scrolled_win;
  GtkCTree *ctree = NULL;
  GtkWidget *title_label = NULL;
  gchar *titles[1] =
  {""};

  *Ctree = ctree = GTK_CTREE (gtk_ctree_new_with_titles (1, 0, titles));
  gtk_widget_show (GTK_WIDGET (ctree));
  gtk_clist_set_column_auto_resize (GTK_CLIST (ctree), 0, TRUE);
  gtk_ctree_set_line_style (ctree, GTK_CTREE_LINES_DOTTED);
  gtk_ctree_show_stub (ctree, FALSE);

  gtk_clist_set_hadjustment (GTK_CLIST (ctree), NULL);
  gtk_clist_set_vadjustment (GTK_CLIST (ctree), NULL);
  scrolled_win = gtk_scrolled_window_new (NULL, NULL);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  gtk_widget_show (scrolled_win);
  gtk_container_add (GTK_CONTAINER (scrolled_win), GTK_WIDGET (ctree));


  *Label = title_label = gtk_label_new ("Working ...");
  gtk_widget_show (title_label);
  gtk_clist_set_column_widget (GTK_CLIST (ctree), 0, title_label);
  gtk_misc_set_alignment (GTK_MISC (title_label), 0, -1);
  gtk_label_set_justify (GTK_LABEL (title_label), GTK_JUSTIFY_RIGHT);


  gtk_signal_connect (GTK_OBJECT (ctree), "tree_select_row",
		      GTK_SIGNAL_FUNC (DIR_TREE_selected_row), title_label);
  gtk_signal_connect (GTK_OBJECT (ctree), "tree_expand",
		      GTK_SIGNAL_FUNC (DIR_TREE_tree_expand), NULL);
  gtk_signal_connect_object (GTK_OBJECT (ctree), "tree_collapse",
		    GTK_SIGNAL_FUNC (gtk_ctree_select), GTK_OBJECT (ctree));

  return scrolled_win;
}



/* EOF */
