//  This may look like C code, but it is really -*- C++ -*-

//  ------------------------------------------------------------------
//  The Goldware Library
//  Copyright (C) 1990-1999 Odinn Sorensen
//  Copyright (C) 1999-2000 Alexander S. Aganichev
//  ------------------------------------------------------------------
//  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 program; if not, write to the Free
//  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
//  MA 02111-1307, USA
//  ------------------------------------------------------------------
//  $Id$
//  ------------------------------------------------------------------
//  Allows user to select a file name.
//  ------------------------------------------------------------------

#include <gctype.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <gmemdbg.h>
#include <gfilutil.h>
#include <gwildmat.h>
#include <gwinall.h>
#include <gfilutil.h>
#include <gdirposx.h>
#include <gstrall.h>


//  ------------------------------------------------------------------

static bool path_in_title, case_sensitive;
static VfvCP open_function = NULL;
static char* cwdp;
static char* tcwdp;
static char* namextp;


//  ------------------------------------------------------------------
//  this function is the compare function for qsort()

static int compare(const char** str1, const char** str2) {

  // Sort with directories first
  bool dir1 = !!strchr(*str1, GOLD_SLASH_CHR);
  bool dir2 = !!strchr(*str2, GOLD_SLASH_CHR);
  int cmp = compare_two(dir2, dir1);
  if(cmp != 0)
    return cmp;

  Path p1, p2;
  strcpy(p1, *str1); if(dir1) { p1[strlen(p1)-1] = NUL; }
  strcpy(p2, *str2); if(dir2) { p2[strlen(p2)-1] = NUL; }

  if(case_sensitive)
    return strcmp(p1, p2);
  else {
    cmp = stricmp(p1, p2);
    if(cmp == 0)
      cmp = strcmp(p1, p2);
  }

  return cmp;
}


//  ------------------------------------------------------------------
//  this function displays the title on the pick window border

static void disp_title() {

  if(path_in_title) {
    char buf[sizeof(Path)+2];
    strcpy(buf, " ");
    PathCopy(buf+1, cwdp);
    strcat(buf, namextp);
    strcat(buf, " ");

    wtitle(buf, TCENTER, gwin.active->battr);
  }

  if(open_function)
    (*open_function)();
}


//  ------------------------------------------------------------------
//  this function frees all allocated strings in the array of pointers

static void free_strings(char** p, int numelems) {

  for(int i=0;i<numelems;i++)
    throw_xfree(p[i]);
}


//  ------------------------------------------------------------------

static void pre_exit(char** p, int numelems) {

  free_strings(p,numelems);
  throw_xfree(p);
  gchdir(tcwdp);
}


//  ------------------------------------------------------------------

bool wpickfile(int srow, int scol, int erow, int ecol, int btype, int bordattr, int winattr, int barattr, bool title, std::string &filespec, VfvCP open, bool casesens) {

  Path cwd, dir, namext, tcwd, path, spec;

  cwdp = cwd;
  tcwdp = tcwd;
  namextp = namext;

  // allocate space to hold array of char pointers
  int allocated = 100;
  char** p = (char**)throw_xmalloc(allocated*sizeof(char*));

  // set static variables
  open_function = open;
  path_in_title = title;
  case_sensitive = casesens;

  // save current working directory
  getcwd(tcwd, GMAXPATH);

  // if drive was specified, change to it
  char* q = strxcpy(spec, filespec.c_str(), sizeof(Path));

  // split up input filespec into its current
  // working directory and filename/extension
  char* r = strrchr(q, GOLD_SLASH_CHR);
  #if defined(__HAVE_DRIVES__)
  if(r == NULL)
    if(q[1] == ':')
      r = q + 1;
  #endif
  if(r == NULL) {
    *dir = NUL;
    strcpy(namext, q);
  }
  else {
    strins(" ", ++r, 0);
    *r++ = NUL;
    strcpy(dir, q);
    strcpy(namext, r);
  }

  bool finished;
  int picked, files;

  do {

    // if directory was specified, change to it
    if(*dir) {
      if(gchdir(dir)) {
        pre_exit(p, 0);
        return false;
      }
    }

    // get current working directory
    getcwd(cwd, GMAXPATH);
    strcpy(dir, cwd);

    // find all directories plus all files matching input filespec in
    // current directory, allocating an array element for each
    files = 0;
    picked = -1;
    gposixdir d(dir);
    const gdirentry *de;
    if(d.ok) {
      while((de = d.nextentry()) != NULL) {
        const char* name = NULL;
        if(de->is_directory()) {
          if(de->name != ".") {
            strxmerge(path, sizeof(Path), de->name.c_str(), GOLD_SLASH_STR, NULL);
            name = path;
          }
        }
        else if(de->is_file()) {
          if(case_sensitive ? gwildmat(de->name.c_str(), namext) : gwildmati(de->name.c_str(), namext))
            name = de->name.c_str();
        }
        if(name) {
          p[files] = throw_xstrdup(name);
          files++;
          if(files == allocated-1) {
            allocated *= 2;
            p = (char**)throw_xrealloc(p, allocated*sizeof(char*));
          }
        }
      }
    }
    p[files] = NULL;

    // sort files in array by swapping their pointers
    qsort(p, files, sizeof(char*), (StdCmpCP)compare);

    // let user pick file
    if(files)
      picked = wpickstr(srow, scol, erow, ecol, btype, bordattr, winattr, barattr, p, 0, disp_title);
    if(picked == -1 or files == 0) {
      pre_exit(p, files);
      return false;
    }

    // see if a directory was selected. if so save
    // directory name, otherwise build whole path name
    q = strchr(p[picked], GOLD_SLASH_CHR);
    if(q) {
      finished = false;
      strcpy(dir, p[picked]);
      r = strrchr(dir, GOLD_SLASH_CHR);
      if(r)
        *r = NUL;
      *q = NUL;
    }
    else {
      finished = true;
      PathCopy(filespec, cwd);
      filespec += p[picked];
    }

    // free allocated strings
    free_strings(p, files);

  // if a directory was selected, go back and do again
  } while(not finished);

  // change back to current drive and directory
  gchdir(tcwd);

  // free allocated char pointers
  throw_xfree(p);

  // return normally
  return true;
}


//  ------------------------------------------------------------------