# Copyright 1999-2012. Parallels IP Holdings GmbH. All Rights Reserved.
package AgentCLI;

use strict;

use Agent;

use AgentConfig;
use CompatArgParse;

use Logging;
use DumpComposer;

use POSIX qw(:signal_h);
use Carp qw(confess);

sub printHelp {
  print <<HELP;

Usage:
  $0 <command> [<options>]

Commands:
  -s |--get-status           get status of the host: is this agent applicable
  -dr|--dump-resellers=<list> comma-separated list of clients to dump
  -dc|--dump-clients=<list>  comma-separated list of clients to dump
  -dd|--dump-domains=<list>  comma-separated list of domains to dump
  -da|--dump-all             dump all objects on hosts
  -lc|--get-content-list     get list of content files
  -h |--help                 this help

Options:
      --server               dump server settings (may be used as independent command)
  -nc|--no-content           make a shallow structure dump
  -du|--dummy-content        do not dump diskspace-consuming parts of content. When this option is set, MySQL databases are dumped without content.
  -co|--configuration-only   dump only configuration
  -om|--only-mail            dump only mail content
  -oh|--only-hosting         dump only hosting
  -nz|--no-compress          do not compress content files

  -ss|--split-size=<size>    Split the dump to the parts of <size>.
                             Additional parts have .001, .002... suffixes.
                             Dump is not split if such option is not given.

  -d |--description=<text>   Add description to the dump

  -v |--verbosity=<1-5>      Verbosity level. Default 5

HELP
}

sub main {
  my $sigset = POSIX::SigSet->new;
  sigprocmask( SIG_SETMASK, $sigset );
  # To simplify debugging (this makes perl to print stack trace on die)
  $SIG{__DIE__} =  \&confess;

  my %arg_opts = (
    '--help|-h'                => '',
    '--get-status|-s'          => '',
    '--dump-resellers|-dr'     => 's',
    '--dump-clients|-dc'       => 's',
    '--dump-domains|-dd'       => 's',
    '--dump-all|-da'           => '',
    '--get-content-list|-lc'   => '',
    '--no-content|-nc'         => '',
    '--dummy-content|-du'      => '',
    '--only-mail|-om'          => '',
    '--only-hosting|-oh'       => '',
    '--no-compress|-nz'        => '',
    '--configuration-only|-co' => '',
    '--server'                 => '',
    '--output|-o'              => 's',
    '--split-size|-ss'         => 's',
    '--description|-d'         => 's',
    '--verbosity|-v'           => 's',
    '--content-transport'      => 's'
  );

  my $args = CompatArgParse::parse( \@ARGV, \%arg_opts );

  # reduce verbosity level for get-content-list output
  Logging::setVerbosity(2);

  if ( exists $args->{'get-content-list'} ) {
    open( my $CONTENT_FILE, "<", AgentConfig::cwd() . "/content-list.xml" )
      || die "Couldn't get content list: $!\n";
    undef $/;
    my $content = <$CONTENT_FILE>;
    print $content;
    return 0;
  }

  if ( exists $args->{'help'} ) {
    printHelp();
    return 0;
  }

  # set up default verbosity
  Logging::setVerbosity(3);
  if ( exists $args->{'verbosity'} ) {
    Logging::setVerbosity( $args->{'verbosity'} );
  }

  if ( exists $args->{'get-status'} ) {
    my $statusNode = Agent::getAgentStatus();
    $statusNode->serialize( \*STDOUT );
    return 0;
  }

  Agent::enableCompression() unless exists $args->{'no-compress'};

  if ((exists $args->{'content-transport'}) && ($args->{'content-transport'} eq 'rsync')) {
    # seek to data this agent can handle
    my $transport_host = <STDIN>;
    my $transport_login = <STDIN>;
    my $transport_passwd = <STDIN>;
    my $transport_port = <STDIN>;
  }

  die "Cannot use 'only-mail' and 'only-hosting' at one time. Use only one of them."
    if exists $args->{'only-mail'}
    and exists $args->{'only-hosting'};

  # Mapping from command-line option names to agent internal option names
  my %optionsMap = qw/no-content         configOnly
                      configuration-only configOnly
                      only-mail          onlyMail
                      only-hosting       onlyHosting
                      dummy-content      dummyContent
					  server             dumpServerSettings/;
  my $dumpOptions;
  for my $cliOption (keys %optionsMap) {
    if (exists $args->{$cliOption}) {
      $dumpOptions->{$optionsMap{$cliOption}} = 1;
    }
  }
  $dumpOptions->{'gzip'} = Agent::getCompressionStatus();

  my ($domains, $clients, $resellers) = (undef, undef, undef);

  sub parseSelectedObjectsArg {
    my ($args, $argumentName, $objectsDescription) = @_;
    
    my @objects;

    if (exists $args->{$argumentName}) {
      my $value = $args->{$argumentName};
      if ($value eq "-") {
        $value = <STDIN>;
        chomp $value;
      }
      @objects = split( /\s*,\s*/, $value);
    } else {
      # argument was not passed, so no objects are selected
    }
      
    Logging::debug("Selected $objectsDescription: " . join(", ", @objects));
    return @objects;
  }

  unless (exists $args->{'dump-all'}
    || exists $args->{'dump-resellers'}
    || exists $args->{'dump-clients'}
    || exists $args->{'dump-domains'})
  {
    printHelp();
    return 0;
  } elsif (exists $args->{'dump-all'}) {
    Logging::debug("Selected all objects");
  } else { # at least one of object selection argument was passed
    $domains = [ parseSelectedObjectsArg($args, 'dump-domains', 'domains') ];
    $clients = [ parseSelectedObjectsArg($args, 'dump-clients', 'clients') ];
    $resellers = [ parseSelectedObjectsArg($args, 'dump-resellers', 'resellers') ];
  }

  my $isDumpSuccess;
  if (exists $args->{'dump-all'} && exists $args->{'no-content'}) {
    $isDumpSuccess = DumpComposer::makeShallowDump( AgentConfig::cwd(), $args->{'dump_server_settings'} );
  } else {
    $isDumpSuccess = DumpComposer::makeDump(
      AgentConfig::cwd(), 
      $resellers, $clients, $domains, $dumpOptions, 0
    );
  }

  if ($isDumpSuccess) {
    Logging::info("Migration dump is successfully saved.");
  } else {
    Logging::error("Migration dump is not saved.");
  }

  return 0;
}

1;
