// ----------------------------------------------------------------------------
//
// Copyright (C) Columbia University, 1994. All Rights Reserved.
// Sameer A. Nene, Shree K. Nayar, Hiroshi Murase
//
// See file LICENSE for details of software license agreement.
//
// ----------------------------------------------------------------------------
//
// fileiter.C
//
// Author:               Sameer Nene
// Date:                 07/01/94
// Version:              1.1
// Modification History:
//   07/01/94: Fixed bug in FileListIter::operator const void* which caused
//             core dump when FileListIter attempted to access an empty
//             FileList
//
// Bugs:
//   It is possible to iterate over the last element in a list using
//   FileListIter. When then is done, the program coredumps.
//
//   There are no out of memory checks.
//
// Classes:
//   FileList
//   FileListAry
//   FileListIter
//
// Notes:
//   This module contains implementation of classes declared in fileiter.h
//   
// ----------------------------------------------------------------------------

#include <dirent.h>
#include <string.h>
#include "errorscope.h"
#include "stringary.h"
#include "naming.h"
#include "fileiter.h"

FileList::FileList(const char *dirName, const char *s, const char *ending) :
d_nparam(0), d_error(OK), d_fnames_p(0), d_psizes_p(0)
{
  int i, j, k, l, m, n;
  struct dirent *p;
  DIR *dir;

  if(dirName[(d_catpos = strlen(dirName)) - 1] == '/')
    strcpy(d_dir_p = new char[d_catpos + 1 + 255], dirName);
  else {
    ++d_catpos;
    strcpy(d_dir_p = new char[d_catpos + 1 + 255], dirName);
    d_dir_p[d_catpos - 1] = '/';
    d_dir_p[d_catpos] = '\0';
  }

  if((dir = opendir(dirName)) == 0) {
    d_error = DIRECTORY_OPEN_ERROR;
    return;
  }

  for(i = 0, p = readdir(dir); p != 0; p = readdir(dir))
    if(n = NamingScope::isValid(s, p -> d_name, ending))
      if(!i++)
	d_nparam = n;

  if(i == 0) {
    d_error = FILE_OPEN_ERROR;
    return;
  }
  
  rewinddir(dir);
  d_fnames_p = new StringAry(i);
  d_psizes_p = new int[d_nparam];
  for(i = 0, p = readdir(dir); p != 0; p = readdir(dir))
    if(NamingScope::isValid(s, p -> d_name, ending))
      d_fnames_p -> set(i++, p -> d_name);
  NamingScope::sort(d_fnames_p);

  for(n = d_nparam - 1, l = 1; n >= 0; --n) {
    for(m = 1, k = l, j = NamingScope::getParam((*d_fnames_p)[0], n); l < i;
	++m, l += k)
      if(NamingScope::getParam((*d_fnames_p)[l], n) == j)
	break;
    d_psizes_p[n] = m;
  }

  closedir(dir);
}

FileList::~FileList()
{
  delete[] d_dir_p;
  delete d_fnames_p;
  delete[] d_psizes_p;
}

ErrorScope::Error FileList::error() const
{
  return d_error;
}

int FileList::getSize() const
{
  return d_fnames_p -> getSize();
}

int FileList::getSize(int i) const
{
  return d_psizes_p[i];
}

int FileList::getNumParam() const
{
  return d_nparam;
}

FileListAry::FileListAry(const char *dirName, const StringAry &s,
			 const char *ending) : d_error(OK)
{
  Error error;

  d_data_p = new FileList*[d_size = s.getSize()];
  for(int i = 0; i < d_size; ++i)
    if((error = (*(d_data_p[i] = new FileList(dirName, s[i], ending))).error())
       != OK)
      d_error = error;
}

FileListAry::~FileListAry()
{
  for(int i = 0; i < d_size; delete d_data_p[i++]);
  delete[] d_data_p;
}

const FileList& FileListAry::operator[](int i) const
{
  return *(d_data_p[i]);
}

int FileListAry::getSize() const
{
  return d_size;
}

ErrorScope::Error FileListAry::error() const
{
  return d_error;
}

FileListIter::FileListIter(const FileList &fl) : d_fl(fl), d_element(0)
{
}

FileListIter::~FileListIter()
{
}

void FileListIter::operator++()
{
  ++d_element;
}

void FileListIter::operator--()
{
  --d_element;
}

void FileListIter::reset()
{
  d_element = 0;
}

FileListIter::operator const void*() const
{
  return d_fl.d_fnames_p ? (d_element < d_fl.d_fnames_p -> getSize() && d_element >= 0 ? this : 0) : 0;
}

const char* FileListIter::operator()() const
{
  strcpy(&(d_fl.d_dir_p[d_fl.d_catpos]), (*(d_fl.d_fnames_p))[d_element]);
  return d_fl.d_dir_p;
}
