require 'fileutils'

class Projects

  class << self
    def load_all
      Projects.new(Configuration.projects_directory).load_all
    end

    def find(project_name)
      # TODO: sanitize project_name to prevent a query injection attack here
      path = File.join(Configuration.projects_directory, project_name)
      return nil unless File.directory?(path)
      load_project(path)
    end

    def load_project(dir)
      project = Project.read(dir, load_config = false)
      project.path = dir
      project
    end

  end
  
  def initialize(dir = Configuration.projects_directory)
    @dir = dir
    @list = []
  end

  def load_all
    @list = Dir["#{@dir}/*"].find_all {|child| File.directory?(child)}.
                             collect  {|child| Projects.load_project(child)}
    self
  end
  
  def <<(project)
    raise "project named #{project.name.inspect} already exists" if @list.include?(project)
    begin
      @list << project
      save_project(project)
      checkout_local_copy(project)
      write_config_example(project)
      self
    rescue
      FileUtils.rm_rf "#{@dir}/#{project.name}"
      raise
    end
  end

  def save_project(project)
    project.path = File.join(@dir, project.name)
    FileUtils.mkdir_p project.path
  end

  def checkout_local_copy(project)
    work_dir = File.join(project.path, 'work')
    FileUtils.mkdir_p work_dir
    project.source_control.checkout work_dir
  end

  def write_config_example(project)
    config_example = File.join(RAILS_ROOT, 'config', 'cruise_config.rb.example')
    config_in_subversion = File.join(project.path, 'work', 'cruise_config.rb')
    cruise_config = File.join(project.path, 'cruise_config.rb')
    if File.exists?(config_example) and not File.exists?(config_in_subversion)
      FileUtils.cp(config_example, cruise_config)
    end
  end

  # delegate everything else to the underlying @list
  def method_missing(method, *args, &block)
    @list.send(method, *args, &block)
  end

end
