/*
    REFERENCES -- bibliographic software
    Copyright (C) 1995-2007  Volker Kiefel

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU 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
*/


/* for getcwd in Mingw32: */
#ifdef REFS_USES_MINGW
#include <io.h>
#endif
#ifdef REFS_USES_LINUXGCC
#include <unistd.h>
#endif

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include "refs.h"
#include "fl_ut.h"
#include "str_fun.h"
#include "interf.h"
#include "initial.h"

#include <dirent.h>
#include <sys/stat.h>

 FILE * dir_kat;
 extern char dir_kat_name[PFAD_LEN+1];

 extern char wrtxtbu[WRTXTBU_LEN+1];

 extern config_set one_config_set;

 static int dateikatalog_sortieren(void);


/*
 * programmpfad()
 * 
 * extracts path name from the complete path to the executable file as
 * obtained with argv[0] in `main()', for example:
 *
 *   c:\refs\bin\refs.exe -> c:\refs\bin\
 *
 * or
 *
 *   c:/refs/bin/refs.exe -> c:/refs/bin/
 */

int programmpfad(const char * programm, char * pfad)
{
  char * ptr;
  int zeiger;
   
  ptr = strrchr(programm,'\\');
  if (ptr)
  {
     zeiger = (ptr - programm);
     extract_subs(pfad,programm,0,zeiger);
     strcat(pfad,"\\");
     return 1;
  }
  ptr = strrchr(programm,'/');
  if (ptr)
  {
     zeiger = (ptr - programm);
     extract_subs(pfad,programm,0,zeiger);
     strcat(pfad,"/");
     return 1;
  }
  return 0;
}

/*
 * aktuelles_verzeichnis()
 * 
 * determines the path name of the current working directory
 *
 */

int aktuelles_verzeichnis(char * verz)
{
   if (getcwd(verz,PFAD_LEN)==NULL)
   {
      return 0;
   }
#if defined(REFS_USES_MINGW)
   slash_to_backslash(verz); 
   rtrim(verz,'\\');
   strcat(verz,"\\");
#endif
#if defined(REFS_USES_LINUXGCC)
   rtrim(verz,'/');
   strcat(verz,"/");
#endif
   return 1;
}

int slash_to_backslash(char * zle)
{
   int laenge,i;
   laenge = strlen(zle);
   for (i=0;i<laenge;i++)
   {
      if (zle[i]=='/')
      {
          zle[i]='\\';
      }
   }
   return 1;
}

int backslash_to_slash(char * zle)
{
   int laenge,i;
   laenge = strlen(zle);
   for (i=0;i<laenge;i++)
   {
      if (zle[i]=='\\')
      {
          zle[i]='/';
      }
   }
   return 1;
}

int dir_kat_schreiben(void)
{
  if ((dir_kat=fopen(dir_kat_name,"w"))==NULL)
  {
    return 0;
  }
  else return 1;
}


int dir_kat_lesen(void)
{
  if ((dir_kat=fopen(dir_kat_name,"r"))==NULL)
  {
    return 0;
  }
  else return 1;
}

void dir_kat_schliessen(void)
{
  fclose(dir_kat);
}

int dir_kat_loeschen(void)
{
  if (isfile(dir_kat_name))
  {
     remove(dir_kat_name);
  }
  return 1;
}

/* 
   A primitive globbing pattern matcher, understands the following
   search_patterns:
   
   *.*
   *
   *bc.d
   abc.*
   *bc.*
   a*c.d

   not recognized are:

   *a*b.c*
   a*b*.c
   a*b*c.*d

*/

int match_filename_pattern_simple(char * filename, const char * search_pattern)
{
   int rwert;
   int pat_len;
   int dat_len;
   
   char dat[PFAD_LEN+1];
   char pat[PFAD_LEN+1];
   char wort1[PFAD_LEN+1];
   char wort2[PFAD_LEN+1];
   
   rwert = 1;

   strlimcpy(dat,filename,PFAD_LEN);
   strlimcpy(pat,search_pattern,PFAD_LEN);
   upper(dat);
   upper(pat);
   pat_len = strlen(pat);
   dat_len = strlen(dat);

   if (strcmp(pat,"*.*")==0 || strcmp(pat,"*")==0)
   {
      rwert = 1;
      return rwert;
   }
   else if ((pat[pat_len-1]=='*') && (pat[0]=='*'))
   {
      strlimcpy(wort1,pat,PFAD_LEN);
      trim(wort1,'*'); 
      if (locate_substring(wort1,dat) > -1)
      {
          rwert =1;
          return rwert;
      }
      else
      {
          rwert =0;
          return rwert;
      }
   }
   else if (pat[0]=='*')
   {
      strlimcpy(wort1,pat,PFAD_LEN);
      ltrim(wort1,'*'); 
      /* 
         if (locate_substring(wort1,dat)==strlen(dat)-strlen(wort1)) 
         geaendert 3.8.2006 
      */
      if ((strlen(dat) >= strlen(wort1)) &&
          (locate_substring(wort1,dat)==strlen(dat)-strlen(wort1)))
      {
          rwert =1;
          return rwert;
      }
      else
      {
          rwert =0;
          return rwert;
      }
   }
   else if (pat[pat_len-1]=='*')
   {
      strlimcpy(wort2,pat,PFAD_LEN);
      rtrim(wort2,'*'); 

      if (locate_substring(wort2,dat)==0)
      {
          rwert =1;
          return rwert;
      }
      else
      {
          rwert =0;
          return rwert;
      }
   }
   else if (countitem(pat,"*")==2)
   {
      extractitem(1,pat,"*",wort1);
      extractitem(2,pat,"*",wort2);
      if ((locate_substring(wort1,dat)==0) && 
        (locate_substring(wort2,dat)==strlen(dat)-strlen(wort2)))
      {
         rwert = 1;
         return rwert;
      } else
      {
         rwert = 0;
         return rwert;
      }
   }
   else
   {
      rwert = 0;
      return rwert;
   }
}

int verz_auslesen_beg_mit(const char * pfad, const char * maske)
{
   char anfang[INPUT_BU_LEN + 1];
   char muster[PFAD_LEN +1];
   char anzeige[WRTXTBU_LEN+1];

   strlimcpy(anzeige,"File selection (",WRTXTBU_LEN);
   strlimcat(anzeige,maske,WRTXTBU_LEN);
   strlimcat(anzeige,")\n\nInitial character(s) of file name, default all files",
     WRTXTBU_LEN);
   // ein_zeile(anfang,"File selection - initial character(s) of file name, default all files",
   //   INPUT_BU_LEN);
   ein_zeile(anfang,anzeige,
     INPUT_BU_LEN);
   /* Anfang eingefuegt 24.8.2006 */
   if ((locate_substring("*",anfang) > -1) || 
       (locate_substring("?",anfang) > -1))
   {
      wrtxt("\nWarning: characters `*' or `?' not allowed\n");
      return 0;
   }
   /* Ende eingefuegt 24.8.2006 */
   strlimcpy(muster,anfang,PFAD_LEN);
   strlimcat(muster,maske,PFAD_LEN);
   return verzeichnis_auslesen(pfad,muster);
}

/* portable version, requires 
     #include <dirent.h> 
     #include <sys/stat.h>
  (mingw32)
 */
int verzeichnis_auslesen(const char * pfad, const char * maske)
{
  char pfadunddatei[PFAD_LEN + 1];
  DIR *dp;
  struct dirent *ep;
  struct stat attribut;
  int n_dateien;
  
  n_dateien = 0;
  dp = opendir (pfad);
  if (dir_kat_schreiben()==0)
  {
     fprintf(stderr,"\nProblem: %s cannot be created.\n",dir_kat_name);
     return 0;
  }
  if (dp != NULL)
  {
      while ((ep = readdir (dp)))
      {
        strncpy(pfadunddatei,pfad,PFAD_LEN);
        strncat(pfadunddatei,ep->d_name,PFAD_LEN);
        if (stat(pfadunddatei,&attribut)==0)
        {
          
          if (attribut.st_mode & S_IFREG) /* regular file */
          /* if (attribut.st_mode & S_IFDIR) */ /* directory */
          {
            if (match_filename_pattern_simple(ep->d_name,maske)==1)
            {
              fprintf(dir_kat,"%s\n",ep->d_name);
              n_dateien++;
            }
          }
        }
        else 
        {
          fprintf(stderr,"\nStat-ERROR in 'verzeichnis_auslesen()'\n");
          dir_kat_schliessen();
          exit(1);
        }
      }
      closedir (dp);
  }
  else
  {
     return n_dateien; /* returns 0 */
  }
  dir_kat_schliessen();
  return n_dateien;
}


/* 
 * datei_suchen() returns 0 if you abort the function by entering an empty
 * string or by entering `q' 
 */


int datei_suchen(const char * pfad, const char * maske, char * dateiname)
{
  long i;
  char zeile[PFAD_LEN+1];
  int n_dateien;
  long dateinummer;
# define E_LEN 20
  char eingabe[E_LEN+1];
  // char suchpfad[PFAD_LEN + 1];

  if (isfile(dir_kat_name))
  {
    remove(dir_kat_name);
  }

  // n_dateien = verzeichnis_auslesen(pfad,maske);
  n_dateien = verz_auslesen_beg_mit(pfad,maske);

  if (n_dateien==0)
  {
     wrtxt("\n(No file(s) found)\n");
     /* BEGIN Inserted March 16, 2005 */
     if (isfile(dir_kat_name))
     {
        remove(dir_kat_name);
     }
     /* BEGIN Inserted March 16, 2005 */
     return 0;
  }
  /* Hier Dateien sortieren */
  if (n_dateien > 1 && n_dateien <= KAT_SORTIER_N)
  {
       dateikatalog_sortieren();
  }

  dir_kat_lesen();
  wrtxt("\n");
  for (i=1;i<=n_dateien;i++)
  {
    int schleife_beenden;

    schleife_beenden = 0;
    if(fgets(zeile,PFAD_LEN-1,dir_kat)==NULL)
    {
      fprintf(stderr,"\nUnexpected error: Reading of directory-catalog\n");
      exit(1);
    }
    rtrim(zeile,'\n');
    sprintf(wrtxtbu,"%4li: %s\n",i,zeile);
    wrtxt(wrtxtbu);
    if ((i % (one_config_set.sl-3))==0 || (i==n_dateien))
    { 
       sprintf(wrtxtbu,"Select file number: 1..%li, [q] to abort",i);
       do
       {
           int ok;
           ein_zeile(eingabe,wrtxtbu,E_LEN);
           string_in_long(eingabe,&dateinummer,&ok);
           if (strcmp(eingabe,"")==0) 
           { 
             // evtl wieder loeschen  
              if (i < n_dateien)
              {
                wrtxt("\n");
              }
              break;
           }
           else if (strcmp(eingabe,"q")==0) 
           { 
              schleife_beenden = 1;
              break;
           }
           else if (ok && dateinummer > 0 && dateinummer <= i)
           {
              schleife_beenden = 1;
              break;
           }
       } while (1);
       if (schleife_beenden == 1)
       {
          break;
       }
    }
  }
  dir_kat_schliessen();
  if (dateinummer < 1)
  {
     strcpy(dateiname,"");
     remove(dir_kat_name);
     return 0;
  }
  dir_kat_lesen(); 

  for (i=1;i<=n_dateien;i++)
  {
     if(fgets(zeile,PFAD_LEN,dir_kat)==NULL)
     {
      fprintf(stderr,"\nUnexpected error: Reading of directory-catalog\n");
      exit(1);
     }
     if (i==dateinummer)
     {
       break;
     }
  }
  dir_kat_schliessen();
  rtrim(zeile,'\n');
  strlimcpy(dateiname,zeile,PFAD_LEN-1);
  remove(dir_kat_name);
      
  return 1;
}

int datei_suchen_mit_pfad(const char * wildcard_spec, /* wildcard specification */
                          const char * pfad,          /* directory to search in */
                          char * dateiname_mit_pfad   /* file found with path */
                          )
{
   char pfad_zum_suchen[PFAD_LEN+1];
   char dateiname[PFAD_LEN+1];
   strlimcpy(pfad_zum_suchen,pfad,PFAD_LEN);
   if (!strlimcat(pfad_zum_suchen,wildcard_spec,PFAD_LEN))
   {
      return 0;
   }
   // if (!datei_suchen(pfad_zum_suchen,dateiname))
   if (!datei_suchen(pfad,wildcard_spec,dateiname))
   {
      return 0;
   }
   strlimcpy(dateiname_mit_pfad,pfad,PFAD_LEN);
   if (!strlimcat(dateiname_mit_pfad,dateiname,PFAD_LEN))
   {
      return 0;
   }
   return 1;
}



long filesize(char * datname)
{
   FILE * fp;
   long curpos, length;

   if ((fp = fopen(datname,"rb"))==NULL)
        return -1;
   curpos = ftell(fp);
   fseek(fp, 0L, SEEK_END);
   length = ftell(fp);
   fseek(fp, curpos, SEEK_SET);
   fclose(fp);
   return length;
}

int iseof(FILE * datei)
{
   long curpos, endpos;
   curpos = ftell(datei);
   fseek(datei,0L,SEEK_END);
   endpos=ftell(datei);
   fseek(datei,curpos,SEEK_SET);
   if ((curpos-endpos)==0L)
      return 1;
   else return 0;
}

int isfile(const char * test_datei_name)
{
  FILE * test_datei;
  if ((test_datei=fopen(test_datei_name,"rb"))==0)
  {
    return 0;
  }
  else fclose(test_datei);
  return 1;
}

static int dateikatalog_sortieren(void)
{
  char * zeile;
  int lauf;
  int anzahl_dateien;


  d_katalogstapel_rec * sortierstapel;

  anzahl_dateien = 0;
  lauf = 0;

  if ((zeile = (char *) malloc((KATDATEINAME_LEN+4) * sizeof(char)))==NULL)
  {
     return 0;
  }
  if ((sortierstapel = (d_katalogstapel_rec *)
      malloc ((KAT_SORTIER_N + 2) * sizeof(d_katalogstapel_rec))) == NULL)
  {
      free(zeile);
      return 0;
  }



  dir_kat_lesen();

  while (fgets(zeile,KATDATEINAME_LEN + 3,dir_kat)!=NULL)
  {
     lauf++;
     rtrim(zeile,'\n');
     if (strlen(zeile) > KATDATEINAME_LEN)
     {
        dir_kat_schliessen();
        free(zeile);
        free(sortierstapel);
        return 0;
     }
     strcpy(sortierstapel[lauf].dname,zeile);
     if (lauf > KAT_SORTIER_N)
     {
        break;
     }
  }
  dir_kat_schliessen();
  anzahl_dateien = lauf;


  {
      int i, j, h;
      d_katalogstapel_rec v;

      for (h=1;h<=anzahl_dateien/9;h=3*h+1);
      for(; h>0; h/=3)
        for (i=h+1;i <= anzahl_dateien ; i+=1)
        {
           v = sortierstapel[i]; j = i;
           while(j>h && strcmp(sortierstapel[j-h].dname,v.dname) > 0)
           {  sortierstapel[j] = sortierstapel[j-h], j -= h; }
           sortierstapel[j] = v;
        }
  }

  if ((dir_kat=fopen(dir_kat_name,"w"))==NULL)
  {
    fprintf(stderr,"\nERROR: cannot write %s\n", dir_kat_name);
    exit(1);
  }
  
  for (lauf=1;lauf <= anzahl_dateien;lauf++)
  {
     fprintf(dir_kat,"%s\n",sortierstapel[lauf].dname);
  }
  dir_kat_schliessen();

  free(zeile);
  free(sortierstapel);
  return 1;
}

int kopieren(char * quelle, char * ziel)
{
   FILE * eins; /* quelle */
   FILE * zwei; /* ziel */
   unsigned char c1;
   long max_eins, i; /* size of quelle, counter */

   if ((eins=fopen(quelle,"rb"))==NULL)
   {
      fprintf(stderr,"\nUnable to open %s\n",quelle);
      exit (1);
   }
   if (setvbuf(eins,NULL,_IOFBF,25000)!=0)
   {
      wrtxt("\nError: failed to set up buffer for input of first file\n");
      exit(1);
   }
   if ((zwei=fopen(ziel,"wb"))==NULL)
   {
      fprintf(stderr,"\nUnable to open %s\n",ziel);
      exit (1);
   }
   if (setvbuf(zwei,NULL,_IOFBF,25000)!=0)
   {
      wrtxt("\nError: failed to set up buffer for input of second file\n");
      exit(1);
   }
   
   fseek(eins,0L,SEEK_END); 
   max_eins = ftell(eins)-1;
   rewind(eins);
   for (i=0;i<=max_eins;i++)
   {
      fread(&c1,sizeof(c1),1,eins);
      if (fwrite(&c1,sizeof(c1),1,zwei) < 1) schreibfehler();
   }

   fclose(eins);
   fclose(zwei);
   sprintf(wrtxtbu,"\n(File `%s' copied to `%s')\n",quelle,ziel);
   wrtxt(wrtxtbu);
   sprintf(wrtxtbu,"\nFile `%s' \n  copied to `%s'",quelle,ziel);
   protokollieren(wrtxtbu);

   return 1;
}


