/* Copyright (C) 1996,1997 Robert H”hne, see COPYING.RH for details */
/* This file is part of RHIDE. */
#define Uses_TNSSortedCollection

#define Uses_TDirList
#define Uses_tvutilFunctions
#include <libtvuti.h>

#define Uses_TProject
#define Uses_TOptions
#define Uses_ideFunctions
#include <libide.h>
#include <rhide.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>

int debug_dependencies = 0;
int debug_commands = 0;
int debug_tempfiles = 0;
int debug_files = 0;
int c_words_changed = 1;
int gpc_words_changed = 1;
int user_words_changed = 1;

char *RHIDE_DIR;
char *RHIDE_NAME;
char *RHIDE_EXT;

int FindFile(char *name,char *&full_name)
{
  return (Boolean)FindFile((const char *)name,full_name) == True ? 1 : 0;
}

Boolean FindFile(const char * name,char * & full_name)
{
  FILE_TYPE t;
  Boolean retval = False;
  if (!name)
  {
    string_dup(full_name,"");
    return False;
  }
  if (debug_files)
  {
    fprintf(stderr,_("Search for file '%s'\n"),name);
  }
  if (strchr(name,'/') != NULL && __file_exists(name))
  {
    string_dup(full_name,name);
    FExpand(full_name);
    retval = True;
  }
  else
  {
    t = get_file_type(name);
    switch (t)
    {
      case FILE_C_SOURCE:
      case FILE_C_SOURCE_I:
      case FILE_CC_SOURCE:
      case FILE_CC_SOURCE_II:
      case FILE_ASM_SOURCE:
      case FILE_FLEX_SOURCE:
      case FILE_BISON_SOURCE:
      case FILE_OBJC_SOURCE:
      case FILE_PASCAL_SOURCE:
      case FILE_FORTRAN_SOURCE:
      case FILE_FORTRAN_SOURCE_PRE:
        retval = FindFile(name,Options.SrcDirs,full_name,False);
        break;
      case FILE_LIBRARY:
        retval = FindFile(name,Options.library_path,full_name,False);
        break;
      case FILE_OBJECT:
        retval = FindFile(name,Options.ObjDirs,full_name);
        break;
      case FILE_HEADER:
        retval = FindFile(name,Options.include_path,full_name,False);
        break;
      default:
#if 0
        string_dup(full_name,name);
        if (__file_exists(full_name))
        {
          retval = True;
          FExpand(full_name);
        }
        else retval = False;
        break;
#else
/* What is with files, which have no known source suffixes?
   I think this is the better way to find it. As an example
   I have in the doc directory a project doc.gpr where I have
   inserted the file rhide.tx which should be searched also
   in the source directories. May be I will add sometimes a
   path for so called 'other files'.
*/
        retval = FindFile(name,Options.SrcDirs,full_name,False);
        break;
#endif
    }
  }
  if (debug_files)
  {
    if (retval == True)
      fprintf(stderr,_("found '%s'\n"),full_name);
    else
      fprintf(stderr,_("not found: take '%s'\n"),full_name);
  } 
  return retval;
}

class FindCacheCollection : public TNSSortedCollection
{
public:
  FindCacheCollection(ccIndex alimit,ccIndex adelta) :
    TNSSortedCollection(alimit,adelta) {}
private:
  virtual int compare(void *,void *);
  virtual void freeItem(void *);
};

struct FileFind {
  char *name;
  char *full_name;
  FileFind(const char *_name,const char *_full_name)
  {
    string_dup(name,_name);
    if (_full_name) string_dup(full_name,_full_name);
    else full_name = NULL;
  }
  ~FileFind()
  {
    string_free(name);
    string_free(full_name);
  }
};

int Fcompcount;

int FindCacheCollection::compare(void *key1,void *key2)
{
  return strcmp(((FileFind *)key1)->name,((FileFind *)key2)->name);
}

void FindCacheCollection::freeItem(void *item)
{
  delete((FileFind *)item);
}

static FindCacheCollection *FindCache = NULL;

void ClearFindCache()
{
  if (debug_files)
  {
    fprintf(stderr,_("clearing the FindCache\n"));
  }
  destroy(FindCache);
  FindCache = NULL;
}

Boolean FindFile(const char * name,TDirList * list,
                            char * & full_name,Boolean uselist)
{
  int i;
  FileFind *ff = NULL;
  ccIndex findIndex;
  char bname[PATH_MAX];
  if (!name)
  {
    string_dup(full_name,"");
    return False;
  }
  strcpy(bname,name);
  // That's now a try for allowing directories in 'name'
#if 0
  BaseName(bname);
#endif
  if (!NoFileCache)
  {
    ff = new FileFind(bname,NULL);
    if (!FindCache) FindCache = new FindCacheCollection(100,100);
    if (FindCache->search(ff,findIndex) == True)
    {
      string_dup(full_name,((FileFind *)FindCache->at(findIndex))->full_name);
      delete(ff);
      if (debug_files)
      {
        fprintf(stderr,_("found '%s' in FindCache\n"),name);
      }
      return True;
    }
  }
  if (__file_exists(bname))
  {
    string_dup(full_name,bname);
    FExpand(full_name);
    if (debug_files)
    {
      fprintf(stderr,_("found '%s' in current directory\n"),name);
    }
    if (!NoFileCache)
    {
      string_dup(ff->full_name,full_name);
      FindCache->atInsert(findIndex,ff);
    }
    return True;
  }
  for (i=0;i<list->getCount();i++)
  {
    string_dup(full_name,(char *)list->at(i));
    expand_variables(&full_name);
    string_cat(full_name,"/");
    string_cat(full_name,bname);
    if (__file_exists(full_name))
    {
      if (debug_files)
      {
        fprintf(stderr,_("found '%s' using the search directory '%s'\n"),
                       name,(char *)list->at(i));
      }
      FExpand(full_name);
      if (!NoFileCache)
      {
        string_dup(ff->full_name,full_name);
        FindCache->atInsert(findIndex,ff);
      }
      return True;
    }
    string_free(full_name);
  }
  if (uselist == True && list && list->getCount() > 0)
  {
    string_dup(full_name,(char *)list->at(0));
    expand_variables(&full_name);
    string_cat(full_name,"/");
    string_cat(full_name,bname);
  }
  else
  {
    string_dup(full_name,name);
  }
  FExpand(full_name);
  if (!NoFileCache) delete(ff);
  return False;
}

#ifdef FILEFINDDEBUG
static __attribute__ (( __destructor__ ))
void print_findfiles()
{
  if (!FindCache)
    return;
  int i,count = FindCache->getCount();
  fprintf(stderr,"FindFiles(%d)\n",count);
  for (i=0;i<count;i++)
  {
    FileFind *ff = (FileFind *)FindCache->at(i);
    fprintf(stderr,"%s[%s]\n",ff->full_name,ff->name);
  }
}
#endif

