#!/usr/bin/ruby -w
# -*- ruby -*-

require './filetest'
require './log'

# Additions to the File built-in class.

class File
  include Log

  # Returns a File::Stat object, or null if there were errors (such as the file
  # not existing, access denied, etc.).
  def File.status(fd)
    begin 
      return File.stat(fd)
    rescue
      # ignore files that could not be read, etc.
      return nil
    end
  end

  # Returns whether the given object is a file. Ignores errors.
  def File.is_file?(fd)
    fs = File.status(fd)
    return fs && fs.file?
  end
  
  # Returns whether the given object is a directory. Ignores errors.
  def File.is_directory?(fd)
    fs = File.status(fd)
    return fs && fs.directory?
  end

  # Returns an array containing each of the names for which the associated block
  # returned true.
  def File.find_where(dir)
    names = Array.new
    Find.find(dir) do |f|
      names.push(f) if yield(f)
    end
    names
  end

  # Returns an array of all files under the given directory.
  def File.find_files(dir)
    File.find_where(dir) { |f| is_file?(f) }
  end

  # Returns an array of all directory under the given directory.
  def File.find_directories(dir)
    File.find_where(dir) { |f| is_directory?(f) }
  end
  
  # Returns an array of all files within the given directory.
  def File.local_files(dir)
    Dir.new(dir).find_all { |f| is_file?(f) }
  end

  # Strips the PWD and the leading ./
  def File.clean_name(fname)
    Log.log "fname: #{fname}"
    file = fname.dup
    file.gsub!(Dir.pwd, "")
    file.gsub!(/^\//, "")
    file.sub!(/^\.\//, "")
    file
  end

  def File.is_text?(fname)
    FileTester.text?(fname)
  end

end


# A hash that ensures that we use file name of the form: "foo/Bar", not
# "./foo/Bar".

class FileHash < Hash

  def []=(f, value)
    fname = File.clean_name(f)
    super(fname, value)
  end

  def [](f)
    fname = File.clean_name(f)
    super(fname)
  end

end


# An array that ensures that we use file name of the form: "foo/Bar", not
# "./foo/Bar".

class FileArray < Array

  def []=(index, name)
    file = File.clean_name(f)
    super(index, name)
  end

  def push(name)
    fname = File.clean_name(name)
    super(fname)
  end

end



# Directories listed so that the parents are first in the list.

class OrderedDirectoryList < Array

  def initialize(files)
    files.each { |f| add(File.dirname(f)) }
  end

  # add a directory
  def add(dir)
    if dir && !File.exists?(dir + "/CVS/Entries")
      
      # TODO: remove the CVS-icity of this:

      # attempt to add the parent, unless this is "."
      # note: this won't work if dir == "."
      if dir == "."
        puts "ERROR: Cannot process files from within a directory"
        puts "not in CVS. Please move up to the parent directory"
        puts "and retry."
        exit
      end
      
      add(File.dirname(dir))
      pos = index(dir)
      if pos
        # nothing to do; dir is already in the list
      else
        pdpos = index(File.dirname(dir))
        if pdpos
          # parent already in the list, so insert this dir immediately afterward
          self[pdpos + 1, 0] = dir
        else
          # prepending
          unshift(dir)
        end
      end
    end
  end

end


if __FILE__ == $0
  fa = FileArray.new
  fa.push("/this/is/a/test")
  puts fa

  fa.push("./another/test")
  puts fa
end


syntax highlighted by Code2HTML, v. 0.9.1