#!/usr/bin/perl
# Copyright 1999-2016. Plesk. All Rights Reserved.

use strict;

# Prefer internal modules over external
use lib '.';

use PleskX;
use CompatArgParse;
use Storage::Storage;
use DumpStatus;
use Logging;
use XmlNode;
use HelpFuncs;
use AgentConfig;
use PleskVersion;

use sigtrap qw(die normal-signals);
use POSIX qw(:signal_h);
use Carp qw( confess  );
use IO::Handle;

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)
      --admin-info           dump administrator info (may be used as independent command)
  -nc|--no-content           make a shallow structure dump
  -co|--configuration-only   dump only configuration
      --capability-only      dump only capability info
  -om|--only-mail            dump only mail content
  -oh|--only-hosting         dump only hosting
  -nz|--no-compress          do not compress content files
  -dt|--dump-child           dump child`s objects
      --content-transport    type of transport used for content ("archive"|"rsync"). Default is "archive"
      --existing-remote-db-servers
                             list of database servers on destination to compare with database servers registered on source
                             Format: type1:host1:port1, type2:host2:port2, ..., typeN:hostN:portN

  -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

  -ia|--include-app-distrib  Include server wide application distrib to dump for installed packages
  -nl|--no-license	     Do not dump license

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

HELP
}

sub main {
  my $sigset = POSIX::SigSet->new;
  sigprocmask( SIG_SETMASK, $sigset );

  $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'           => '',
    '--dump-child|-dt'	       => '',
    '--get-content-list|-lc'   => '',
    '--no-content|-nc'         => '',
    '--only-mail|-om'          => '',
    '--only-hosting|-oh'       => '',
    '--no-compress|-nz'        => '',
    '--configuration-only|-co' => '',
    '--capability-only'        => '',
    '--server'                 => '',
    '--admin-info'             => '',
    '--content-transport'      => '',
    '--output|-o'              => 's',
    '--split-size|-ss'         => 's',
    '--description|-d'         => 's',
    '--verbosity|-v'           => 's',
    '--include-app-distrib'    => '',
    '--no-license|-nl'         => '',
    '--migration-mode'         => '',
    '--skip-extra-server-settings' => '',
    '--existing-remote-db-servers' => 's',
  );

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

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

  if ( exists $args->{'verbosity'} ) {
    Logging::setVerbosity( $args->{'verbosity'} );
  }


  if ( exists $args->{'get-status'} ) {
    my $root = XmlNode->new('agent-status');

    my @problems = PleskX::checkHost();

    if (@problems) {
      $root->addChild(
        XmlNode->new( 'wrong-platform', 'content' => ( join "\n", @problems ) )
      );
    }

    $root->serialize( \*STDOUT );

    return 0;
  }

  my $do_gzip = exists $args->{'no-compress'} ? undef : 1;

  my $storage;
  my $status;

  # Migration
  my $workDir = AgentConfig::cwd();

  open(my $agentPid, "> $workDir/agent.pid");
  print $agentPid $$;
  $agentPid->flush();

  if (defined $args->{'split-size'}) {
    my $minSplitSize = 1024*1024; # Minimum split size is 1M
    $args->{'split-size'} = HelpFuncs::Max($args->{'split-size'}, $minSplitSize);
  }
  my $rlimit = AgentConfig::getRLimitFsize();
  if($rlimit) {
    $args->{'split-size'} = HelpFuncs::Min($args->{'split-size'}, 512*$rlimit);
  }

  if ( exists $args->{'get-content-list'} ) {
    $storage = Storage::Storage::createFileStorage( $do_gzip, $workDir, $args->{'split-size'});
    print $storage->getContentList();
    return 0;
  }

  my $res;
  Logging::setXmlLogging();
  eval {
    my $space_reserved = 10*1024*1024;
    $storage = Storage::Storage::createFileStorage( $do_gzip, $workDir, $args->{'split-size'} , undef, $space_reserved);
    $status = DumpStatus::createMigration( $workDir . "/dumping-status.xml" );

    # in PleskX.pl shared agents code is always in the current directory
    my $agent = PleskX->new( $storage, $status, AgentConfig::cwd());

	$agent->turnOnMigrationMode() if (exists $args->{'migration-mode'});
    $agent->turnOnListingOnlyMode() if ( exists $args->{'dump-all'} && exists $args->{'no-content'});

    if ( PleskVersion::atLeast( 11, 0, 0 ) ) {
      $agent->setDecryptFullDump();
    }

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

    if ( exists $args->{'content-transport'} and $args->{'content-transport'} eq 'rsync' ) {
      my $transport_host = <STDIN>;
      chomp $transport_host;
      my $transport_login = <STDIN>;
      chomp $transport_login;
      my $transport_passwd = <STDIN>;
      chomp $transport_passwd;
      my $transport_port = <STDIN>;
      chomp $transport_port;
      my %transportOpt;
      $transportOpt{'host'} = $transport_host;
      $transportOpt{'login'} = $transport_login;
      $transportOpt{'passwd'} = $transport_passwd;
      $transportOpt{'port'} = $transport_port if $transport_port;
      $agent->setContentTransport( 'rsync', %transportOpt, 'unix' );
    }
    else {
      $agent->setDumpWholeVHost();
      $agent->setDumpWholeMail();
    }

    if ( exists $args->{'no-content'} ) {
      $agent->setDumpType($PleskX::SHALLOW);
    }
    if ( exists $args->{'configuration-only'} ) {
      $agent->setDumpType($PleskX::CONFIGURATION);
    }
    if ( exists $args->{'capability-only'} ) {
      $agent->turnOnMigrationMode();
      $agent->turnOnListingOnlyMode();
      $agent->turnOnCapabilityOnlyMode();
      $agent->setDumpType($PleskX::SHALLOW);
      $agent->setDumpType($PleskX::CONFIGURATION);
      $agent->setDumpType($PleskX::CAPABILITY);
    }
    if ( exists $args->{'skip-extra-server-settings'} ) {
      $agent->skipExtraServerSettings();
    }
    if ( exists $args->{'only-mail'} ) {
      $agent->setDumpType($PleskX::ONLY_MAIL);
    }
    if ( exists $args->{'only-hosting'} ) {
      $agent->setDumpType($PleskX::ONLY_HOSTING);
    }
    if ( exists $args->{'description'} ) {
      $agent->setDescription( $args->{'description'} );
    }
    if ( exists $args->{'no-license'} ) {
      $agent->setDumpType($PleskX::NO_LICENSE);
    }

    if ( exists $args->{'dump-all'} ) {
      Logging::debug("Selected all objects");
      $agent->selectAll();
    }
    else {
      my $dumpchild = 0;
      $dumpchild = 1 if exists $args->{'dump-child'};
      if ( exists $args->{'dump-domains'} ) {
        my $value = $args->{'dump-domains'};
        if ( $value eq "-" ) {
          $value = <STDIN>;
          chomp $value;
        }
        my @domains = split( /\s*,\s*/, $value );
        my %d = map { $_, 1 } @domains;
        @domains = keys %d;
        Logging::debug( "Selected domains: " . join( ", ", @domains ) );
        $agent->selectDomains(@domains);
      }
      elsif( not $dumpchild ){
        my @empty;
        $agent->excludeDomains(@empty);
      }
      if ( exists $args->{'dump-clients'} ) {
        my $value = $args->{'dump-clients'};
        if ( $value eq "-" ) {
          $value = <STDIN>;
          chomp $value;
        }
        my @clients = split( /\s*,\s*/, $value );
        my %c = map { $_, 1 } @clients;
        @clients = keys %c;
        Logging::debug( "Selected clients: " . join( ", ", @clients ) );
        $agent->selectClients(@clients);
      }
      elsif( not $dumpchild ){
        my @empty;
        $agent->excludeClients(@empty);
      }
      if ( exists $args->{'dump-resellers'} ) {
        my $value = $args->{'dump-resellers'};
        if ( $value eq "-" ) {
          $value = <STDIN>;
          chomp $value;
        }
        my @resellers = split( /\s*,\s*/, $value );
        my %r = map { $_, 1 } @resellers;
        @resellers = keys %r;
        Logging::debug( "Selected resellers: " . join( ", ", @resellers ) );
        $agent->selectResellers(@resellers);
      }
      elsif( not $dumpchild ){
        my @empty;
        $agent->excludeResellers(@empty);
      }
    }
    if ( exists $args->{'server'} ) {
      $agent->selectServerSettings();
    }
    if ( exists $args->{'admin-info'} ) {
      $agent->selectAdminInfo();
    }
    if ( exists $args->{'include-app-distrib'} && !exists $args->{'server'}) {
      $agent->setDumpType($PleskX::INCLUDE_APP_DISTRIB);
    }

    if ( exists $args->{'existing-remote-db-servers'} ) {
      my $value = $args->{'existing-remote-db-servers'};
      my @dbServers = split( /\s*,\s*/, $value );
      $agent->setExistingRemoteDbServers(\@dbServers);
    }

    $res = $agent->dump();
  };
  if ($@) {
    my $error = $@;
    my $errmsg = "Unable to create dump";
    Logging::debug("$errmsg: $error");
    Logging::error($errmsg,'fatal');
  }
  $storage->createContentList() if $storage;
  $status->finish() if $status;

  return $res;
}

sub writeMigrationResult{
  my $sessionPath = AgentConfig::cwd();
  Logging::serializeXmlLog("$sessionPath/migration.result");
  return;
}

my $exitcode = main();
writeMigrationResult();
unlink(AgentConfig::cwd() . '/agent.pid');
exit( $exitcode );

# Local Variables:
# mode: cperl
# cperl-indent-level: 2
# indent-tabs-mode: nil
# tab-width: 4
# End:
