##################################################################
#                  Licensing Information                         #
#                                                                #
#  The following code is licensed, as standalone code, under     #
#  the Ruby License, unless otherwise directed within the code.  #
#                                                                #
#  For information on the license of this code when distributed  #
#  with and used in conjunction with the other modules in the    #
#  Amp project, please see the root-level LICENSE file.          #
#                                                                #
#  © Michael J. Edgar and Ari Brown, 2009-2010                   #
#                                                                #
##################################################################

##
# This command will go through your repository's working directory, and if it
# discovers any files that it was tracking, but have mysteriously disappeared,
# the command will assume you meant to remove it (stop tracking it), and remove it
# for you. Similarly, if you have any files that are untracked and have appeared
# in your repository, and they aren't ignored by your .hgignore file, then we
# assume you wanted to add them, and add them for you.
#
# The only significant difference between this command and Mercurial's implementation
# is the addition of the interactive mode. This mode asks the user before each removal
# and addition. Personally, I added it because I don't like blanket actions taken across
# my entire repository. It's off by default.
command :addremove do |c|
  c.workflow :hg
  
  c.desc "Add all new files, delete all missing files"
  c.opt :interactive, "Asks about each file before adding/removing", :default => false, :short => "-a"
  c.opt :include, "include names matching the given patterns", :type => :string, :short => "-I"
  c.opt :exclude, "exclude names matching the given patterns", :type => :string, :short => "-E"
  c.opt :"dry-run", "Don't perform actions, just print output", :short => "-n"
  c.help <<-EOS
amp addremove [options]+

  New files are ignored if they match any of the patterns in .hgignore. As
  with add, these changes take effect at the next commit.

  Use the -s option to detect renamed files. With a parameter > 0,
  this compares every removed file with every added file and records
  those similar enough as renames. This option takes a percentage
  between 0 (disabled) and 100 (files must be identical) as its
  parameter. Detecting renamed files this way can be expensive.
  
  Where options are:
EOS

  c.on_run do |opts, args|
    repo = opts[:repository]
    
    # Standard preparation for mercurial-style matching. We need a match object.
    # If a file is missed by our matcher, assume we want it included (unknown files match
    # this situation)
    matcher = Amp::Match.create(:includer => opts[:include], :excluder => opts[:exclude]) { true }
    # Get only the deleted and unknown files. We'll remove the former and add the latter.
    results = repo.status(:match => matcher, :deleted => true, :added => false, :unknown => true,
                          :ignored => false, :modified => false, :clean => false)
    
    Amp::UI.say
    # Prettified, add check later if user disables colors
    Amp::UI.say "ADDING FILES".blue if results[:unknown].any?
    # Handle adding the files now
    if opts[:interactive]
      # Interactive means we ask the user if they want to add the file or not.
      # Build a list based on what they agree upon, then add that list
      to_add = []
      results[:unknown].each do |file|
        add = Amp::UI.yes_or_no("Add #{file.relative_path(repo.root).blue}? [y/n] ")
        to_add << file if add
      end
    else
      # Otherwise, just let the user know what we're about to add
      results[:unknown].each {|file| Amp::UI.say "Adding #{file.relative_path repo.root}" }
      to_add = results[:unknown]
    end
    repo.staging_area.add(to_add) unless opts[:"dry-run"]
    
    Amp::UI.say
    # Prettified, add check later if user disables colors
    Amp::UI.say "REMOVING FILES".red if results[:deleted].any?
    # Now we remove any files that mysteriously disappeared on us
    if opts[:interactive]
      # Interactive means ask the user if they want to remove a file from the repo or not.
      # Build a list.
      to_del = []
      results[:deleted].each do |file|
        del = Amp::UI.yes_or_no("Remove #{file.relative_path(repo.root).red}?")
        to_del << file if del
      end
    else
      # Otherwise, just inform the user of the damage (yes I'm biased against this command)
      results[:deleted].each {|file| Amp::UI.say "Removing #{file.relative_path repo.root}" }
      to_del = results[:deleted]
    end
    repo.staging_area.remove to_del unless opts[:"dry-run"]
    
    repo.staging_area.save
  end
end