// generated by Fast Light User Interface Designer (fluid) version 1.0106

#include "Fl_Simple_File_Chooser.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <libgen.h>
#include <FL/filename.H>

inline void Fl_Simple_File_Chooser::cb_window_i(Fl_Double_Window*, void*) {
  fileName->value("");
fileList->deselect();
window->hide();
}
void Fl_Simple_File_Chooser::cb_window(Fl_Double_Window* o, void* v) {
  ((Fl_Simple_File_Chooser*)(o->user_data()))->cb_window_i(o,v);
}

inline void Fl_Simple_File_Chooser::cb_fileList_i(Fl_File_Browser*, void*) {
  fileListCB();
}
void Fl_Simple_File_Chooser::cb_fileList(Fl_File_Browser* o, void* v) {
  ((Fl_Simple_File_Chooser*)(o->parent()->user_data()))->cb_fileList_i(o,v);
}

inline void Fl_Simple_File_Chooser::cb_okButton_i(Fl_Return_Button*, void*) {
  if (callback_)
  (*callback_)(data_,fileName->value());

window->hide();
}
void Fl_Simple_File_Chooser::cb_okButton(Fl_Return_Button* o, void* v) {
  ((Fl_Simple_File_Chooser*)(o->parent()->user_data()))->cb_okButton_i(o,v);
}

inline void Fl_Simple_File_Chooser::cb_Cancel_i(Fl_Button*, void*) {
  fileName->value("");
fileList->deselect();
window->hide();
}
void Fl_Simple_File_Chooser::cb_Cancel(Fl_Button* o, void* v) {
  ((Fl_Simple_File_Chooser*)(o->parent()->user_data()))->cb_Cancel_i(o,v);
}

inline void Fl_Simple_File_Chooser::cb_fileName_i(Fl_File_Input*, void*) {
  fileNameCB();
}
void Fl_Simple_File_Chooser::cb_fileName(Fl_File_Input* o, void* v) {
  ((Fl_Simple_File_Chooser*)(o->parent()->user_data()))->cb_fileName_i(o,v);
}

inline void Fl_Simple_File_Chooser::cb_newButton_i(Fl_Button*, void*) {
  newdir();
}
void Fl_Simple_File_Chooser::cb_newButton(Fl_Button* o, void* v) {
  ((Fl_Simple_File_Chooser*)(o->parent()->user_data()))->cb_newButton_i(o,v);
}

Fl_Simple_File_Chooser::Fl_Simple_File_Chooser(const char *p, int t, const char *title) {
  Fl_Double_Window* w;
  sort=fl_numericsort;
type_ = t;
  { Fl_Double_Window* o = window = new Fl_Double_Window(330, 375, "Choose File");
    w = o;
    o->callback((Fl_Callback*)cb_window, (void*)(this));
    { Fl_File_Browser* o = fileList = new Fl_File_Browser(14, 11, 300, 275);
      o->type(2);
      o->callback((Fl_Callback*)cb_fileList);
      Fl_Group::current()->resizable(o);
      w->hotspot(o);
      //#include <FL/Fl_File_Browser.H>
    }
    { Fl_Return_Button* o = okButton = new Fl_Return_Button(139, 338, 85, 25, "OK");
      o->callback((Fl_Callback*)cb_okButton);
    }
    { Fl_Button* o = new Fl_Button(231, 338, 85, 25, "Cancel");
      o->callback((Fl_Callback*)cb_Cancel);
    }
    { Fl_File_Input* o = fileName = new Fl_File_Input(14, 293, 301, 35);
      o->callback((Fl_Callback*)cb_fileName);
      o->when(FL_WHEN_ENTER_KEY);
      fileName->when(FL_WHEN_CHANGED | FL_WHEN_ENTER_KEY_ALWAYS);
    }
    { Fl_Button* o = newButton = new Fl_Button(14, 338, 65, 25, "New dir");
      o->callback((Fl_Callback*)cb_newButton);
    }
    if (title) window->label(title);
    o->set_modal();
    o->end();
  }
  fileList->filter(p);
}

void Fl_Simple_File_Chooser::fileNameCB() {
  char		*filename,	// New filename
		*slash,		// Pointer to trailing slash
		pathname[1024],	// Full pathname to file
		matchname[256];	// Matching filename
int		i,		// Looping var
		min_match,	// Minimum number of matching chars
		max_match,	// Maximum number of matching chars
		num_files,	// Number of files in directory
		first_line;	// First matching line
const char	*file;		// File from directory

// Get the filename from the text field...
filename = (char *)fileName->value();

if (!filename || !filename[0]) {
    okButton->deactivate();
    return;
}

  // Expand ~ and $ variables as needed...
if (strchr(filename, '~') || strchr(filename, '$')) {
    fl_filename_expand(pathname, sizeof(pathname), filename);
    filename = pathname;
    value(pathname);
}

// Make sure we have an absolute path...
if (directory_[0] != '\0' && filename[0] != '/') {
    fl_filename_absolute(pathname, sizeof(pathname), filename);
    value(pathname);
} else if (filename != pathname) {
    // Finally, make sure that we have a writable copy...
    strncpy(pathname, filename, sizeof(pathname));
}

filename = pathname;

// Now process things according to the key pressed...
if (Fl::event_key() == FL_Enter  ||  Fl::event_key() == FL_KP_Enter)
{
    // Enter pressed - select or change directory...
    if (fl_filename_isdir(pathname)) {
      directory(pathname);
    } else if ((type_ & CREATE) || access(pathname, 0) == 0) {
      // New file or file exists...  If we are in multiple selection mode,
      // switch to single selection mode...
      if (type_ & MULTI)
        type(SINGLE);

      // Hide the window to signal things are done...
      window->hide();
    }
}
else if (Fl::event_key() != FL_Delete && Fl::event_key() != FL_BackSpace)
{
    // Check to see if the user has entered a directory...
    if ((slash = strrchr(pathname, '/')) == NULL)
    	slash = strrchr(pathname, '\\');

    if (slash != NULL)
    {
      // Yes, change directories if necessary...
      *slash++ = '\0';
      filename = slash;

      if (strcmp(pathname, directory_) &&
          (pathname[0] || strcasecmp("/", directory_))) {
        int p = fileName->position();
	int m = fileName->mark();

        directory(pathname);

        if (filename[0]) {
	  char tempname[1024];

	  snprintf(tempname, sizeof(tempname), "%s/%s", directory_, filename);
	  fileName->value(tempname);
	}

	fileName->position(p, m);
      }
    }

    // Other key pressed - do filename completion as possible...
    num_files  = fileList->size();
    min_match  = strlen(filename);
    max_match  = 100000;
    first_line = 0;

    for (i = 1; i <= num_files && max_match > min_match; i ++)
    {
      file = fileList->text(i);

      if (strncmp(filename, file, min_match) == 0)

      {
        // OK, this one matches; check against the previous match
	if (max_match == 100000)
	{
	  // First match; copy stuff over...
	  strncpy(matchname, file, sizeof(matchname));
	  max_match = strlen(matchname);

          // Strip trailing /, if any...
	  if (matchname[max_match - 1] == '/')
	  {
	    max_match --;
	    matchname[max_match] = '\0';
	  }

	  // And then make sure that the item is visible
          fileList->topline(i);
	  first_line = i;
	}
	else
	{
	  // Succeeding match; compare to find maximum string match...
	  while (max_match > min_match)

	    if (strncmp(file, matchname, max_match) == 0)
	      break;
	    else
	      max_match --;

          // Truncate the string as needed...
          matchname[max_match] = '\0';
	}
      }
    }

    // If we have any matches, add them to the input field...
    if (first_line > 0 && min_match == max_match &&
        max_match == (int)strlen(fileList->text(first_line))) {
      // This is the only possible match...
      fileList->deselect(0);
      fileList->select(first_line);
      fileList->redraw();
    }
    else if (max_match > min_match && max_match != 100000)
    {
      // Add the matching portion...
      fileName->replace(filename-pathname,filename-pathname+min_match,matchname);

      // Highlight it with the cursor at the end of the selection so
      // s/he can press the right arrow to accept the selection
      // (Tab and End also do this for both cases.)
      fileName->position(filename-pathname+max_match,filename-pathname+min_match);
    }
    else if (max_match == 0) {
      fileList->deselect(0);
      fileList->redraw();
    }

    // See if we need to enable the OK button...
    if ((type_ & CREATE || access(fileName->value(), 0) == 0) &&
        (!fl_filename_isdir(fileName->value()) || type_ & DIRECTORY))
      okButton->activate();
    else
      okButton->deactivate();
  } else {

    // FL_Delete or FL_BackSpace
    fileList->deselect(0);
    fileList->redraw();
    okButton->deactivate();
  }
}

void Fl_Simple_File_Chooser::fileListCB() {
  char *filename, pathname[1024];

filename = (char *)fileList->text(fileList->value());
if (!filename) return;

if (!directory_[0]) {
    strncpy(pathname, filename, sizeof(pathname));
} else if (strcmp(directory_, "/") == 0) {
    snprintf(pathname, sizeof(pathname), "/%s", filename);
} else {
    snprintf(pathname, sizeof(pathname), "%s/%s", directory_, filename);
}

if (Fl::event_clicks()) {
    if (fl_filename_isdir(pathname))
    {
      // Change directories...
      directory(pathname);

      // Reset the click count so that a click in the same spot won't
      // be treated as a triple-click.  We use a value of -1 because
      // the next click will increment click count to 0, which is what
      // we really want...
      Fl::event_clicks(-1);
    }
    else
    {
	if (callback_)
  	  (*callback_)(data_,fileName->value());


      // Hide the window - picked the file...
      window->hide();
    }
}
else
{
    // Strip any trailing slash from the directory name...
    filename = pathname + strlen(pathname) - 1;
    if (*filename == '/') *filename = '\0';

    // puts("Setting fileName from fileListCB...");
    fileName->value(pathname);

    // Activate the OK button as needed...
    if (!fl_filename_isdir(pathname) || (type_ & DIRECTORY))
      okButton->activate();
}
}

void Fl_Simple_File_Chooser::type(int t) {
  type_ = t;
if (t & MULTI)
  fileList->type(FL_MULTI_BROWSER);
else
  fileList->type(FL_HOLD_BROWSER);
if (t & CREATE)
  newButton->activate();
else
  newButton->deactivate();
if (t & DIRECTORY)
  fileList->filetype(Fl_File_Browser::DIRECTORIES);
else
  fileList->filetype(Fl_File_Browser::FILES);
}

void Fl_Simple_File_Chooser::newdir() {
  const char	*dir;		// New directory name
  char		pathname[1024];	// Full path of directory


  // Get a directory name from the user
  if ((dir = fl_input("New directory name:", NULL)) == NULL)
    return;

  // Make it relative to the current directory as needed...
  if (dir[0] != '/' && dir[0] != '\\')
    snprintf(pathname, sizeof(pathname), "%s/%s", directory_, dir);
  else
    strncpy(pathname, dir, sizeof(pathname));

  // Create the directory; ignore EEXIST errors...

  if (mkdir(pathname, 0777))
    if (errno != EEXIST)
    {
      fl_alert("%s", strerror(errno));
      return;
    }

  // Show the new directory...
  directory(pathname);
}

const char* Fl_Simple_File_Chooser::value(int f) {
  int		i;		// Looping var
  int		fcount;		// Number of selected files
  const char	*name;		// Current filename
  char		*slash;		// Trailing slash, if any
  static char	pathname[1024];	// Filename + directory


  if (!(type_ & MULTI)) {
    name = fileName->value();
    if (!name || !name[0]) return NULL;
    else if (fl_filename_isdir(name)) {
      if (type_ & DIRECTORY) {
        // Strip trailing slash, if any...
        strncpy(pathname, name, sizeof(pathname));
	slash = pathname + strlen(pathname) - 1;
	if (*slash == '/') *slash = '\0';
        return pathname;
      } else return NULL;
    } else return name;
  }

  for (i = 1, fcount = 0; i <= fileList->size(); i ++)
    if (fileList->selected(i)) {
      // See if this file is a directory...
      name = fileList->text(i);

      if (name[strlen(name) - 1] != '/') {
        // Not a directory, see if this this is "the one"...
	fcount ++;

	if (fcount == f) {
	  if (directory_[0]) {
	    snprintf(pathname, sizeof(pathname), "%s/%s", directory_, name);
	  } else {
	    strncpy(pathname, name, sizeof(pathname));
	  }

	  return (pathname);
	}
      }
    }

  return (NULL);
}

void Fl_Simple_File_Chooser::value(const char *filename) {
  int	i,					// Looping var
  	fcount;					// Number of items in list
  char	*slash;					// Directory separator
  char	pathname[1024];				// Local copy of filename


  // See if the filename is the "My System" directory...
  if (filename == NULL || !filename[0]) {
    // Yes, just change the current directory...
    directory(filename);
    fileName->value("");
    okButton->deactivate();
    return;
  }

  // Switch to single-selection mode as needed
  if (type_ & MULTI)
    type(SINGLE);

  // See if there is a directory in there...
  fl_filename_absolute(pathname, sizeof(pathname), filename);

  if ((slash = strrchr(pathname, '/')) == NULL)
    slash = strrchr(pathname, '\\');

  if (slash != NULL) {
    // Yes, change the display to the directory... 
    if (!fl_filename_isdir(pathname)) *slash++ = '\0';

    directory(pathname);
    if (*slash == '/') slash = pathname;
  } else {
    directory(".");
    slash = pathname;
  }

  // Set the input field to the absolute path...
  if (slash > pathname) slash[-1] = '/';

  fileName->value(pathname);
  fileName->position(0, strlen(pathname));
  okButton->activate();

  // Then find the file in the file list and select it...
  fcount = fileList->size();

  fileList->deselect(0);
  fileList->redraw();

  for (i = 1; i <= fcount; i ++)
    if (strcmp(fileList->text(i), slash) == 0) {
      fileList->topline(i);
      fileList->select(i);
      break;
    }
}

void Fl_Simple_File_Chooser::directory(const char *d) {
  char	*dirptr;			// Pointer into directory

  // NULL == current directory
  if (d == NULL) d = ".";

  if (d[0] != '\0')
  {
    // Make the directory absolute...
    if (d[0] != '/' && d[0] != '\\')
      fl_filename_absolute(directory_, d);
    else
      strncpy(directory_, d, sizeof(directory_));

    // Strip any trailing slash...
    dirptr = directory_ + strlen(directory_) - 1;
    if ((*dirptr == '/' || *dirptr == '\\') && dirptr > directory_)
      *dirptr = '\0';

    // See if we have a trailing .. or . in the filename...
    dirptr = directory_ + strlen(directory_) - 3;
    if (dirptr >= directory_ && strcmp(dirptr, "/..") == 0) {
      // Yes, we have "..", so strip the trailing path...
      *dirptr = '\0';
      while (dirptr > directory_) {
        if (*dirptr == '/') break;
	dirptr --;
      }

      if (dirptr >= directory_ && *dirptr == '/')
        *dirptr = '\0';
    } else if ((dirptr + 1) >= directory_ && strcmp(dirptr + 1, "/.") == 0) {
      // Strip trailing "."...
      dirptr[1] = '\0';
    }
  }
  else
    directory_[0] = '\0';

  // Rescan the directory...
  rescan();
}

void Fl_Simple_File_Chooser::rescan() {
  char pathname[1024]; // New pathname for filename field

  // Clear the current filename
  strncpy(pathname, directory_, sizeof(pathname));

  if (pathname[0] && pathname[strlen(pathname) - 1] != '/') {
    strncat(pathname, "/", sizeof(pathname));
  }

  //  puts("Setting fileName in rescan()");
  fileName->value(pathname);

  if (type_ & DIRECTORY) okButton->activate();
  else okButton->deactivate();

  // Build the file list...
  fileList->load(directory_, sort);
}

void Fl_Simple_File_Chooser::show() {
  rescan();
window->hotspot(fileList);
window->show();
fileName->take_focus();
}

void Fl_Simple_File_Chooser::callback(void (*cb)(void *,const char*),void *p) {
  callback_ = cb;
data_ = p;
}

void Fl_Simple_File_Chooser::setdir(const char* d) {
  strncpy(directory_,d,1024);
dirname(directory_);
}
