# Copyright 1999-2020. Plesk International GmbH. All rights reserved.
package ArchiveContent::ArchiveContent;

use strict;
eval{require warnings;1;};

use ArchiveContent::UnixArchiveContent;
use ArchiveContent::WindowsArchiveContent;
use File::Temp qw/tmpnam/;

use vars qw|@ISA|;

sub new {
  
  my ($self, $storage, $packer) = @_;
  
  if ($packer->{content_transport_os} eq 'unix') {
    return ArchiveContent::UnixArchiveContent->new( $storage, $packer );
  } else {
    return ArchiveContent::WindowsArchiveContent->new( $storage, $packer );
  }
  
}

### Public routines ###
# addAdminContent,addResellerContent,addClientContent,addDomainContent,addPhostingContent,\
# addSubDomainContent,addSubDomainPhostingContent,addMailnameContent,addDbContent,addSubdomainDbContent

sub addAdminContent{
  my $self = shift;
  my $cid_type = shift;
  my $id = shift;
  my $file = shift;
  return $self->_addTar( $cid_type, $self->{packer}->getAdminBackupPath( $file ) , @_);
}

sub addResellerContent{
  my $self = shift;
  my $cid_type = shift;
  my $id = shift;
  my $file = shift;
  return $self->_addTar( $cid_type, $self->{packer}->getResellersBackupPath($id, $file ), @_);
}

sub addClientContent{
  my $self = shift;
  my $cid_type = shift;
  my $id = shift;
  my $file = shift;
  return $self->addResellerContent( $cid_type, $id, $file, @_ ) if defined ($self->{packer}->{resellersNodes}) and exists $self->{packer}->{resellersNodes}->{$id};
  return $self->_addTar( $cid_type, $self->{packer}->getClientsBackupPath($id, $file ), @_);
}

sub addDomainContent{
  my $self = shift;
  my $cid_type = shift;
  my $id = shift;
  my $file = shift;
  return $self->_addTar( $cid_type, $self->{packer}->getDomainsBackupPath($id, $file ), @_);
}

sub addPhostingContent{
  my $self = shift;
  my $cid_type = shift;
  my $id = shift;
  my $referralId = shift;
  my $file = shift;
  
  my $domainId = $self->{packer}->getPhostingParentId( $referralId );
  my $referer;
  # do not allow referred cid creation to user-data archive, otherwise user-data archive itself will not be restored
  if (exists $self->{packer}->{domainVhost}->{$domainId} && $self->{packer}->{domainVhost}->{$domainId}->[0] != 'user-data') {
    $referer = $self->_getDomainPhTarReferer($domainId, @_);
    $referer = $self->_getDomainStatTarReferer($domainId, @_) unless defined $referer;
  }
  if( defined $referer ) {
    return $self->_addRefererCid( $referer , $cid_type);
  }
  else{
    return $self->_addTar( $cid_type, $self->{packer}->getPhostingBackupPath($id, $file ), @_);
  }
}

sub addSubDomainContent{
  my $self = shift;
  my $cid_type = shift;
  my $id = shift;
  my $file = shift;
  return $self->_addTar( $cid_type, $self->{packer}->getSubdomainsBackupPath($id, $file ), @_);
}

sub addSubDomainPhostingContent{
  my $self = shift;
  my $cid_type = shift;
  my $id = shift;
  my $referralId = shift;
  my $file = shift;
  my $referer;
  if( $referralId ) {
    $referer = $self->_getDomainPhTarReferer( $referralId, @_ );
    unless( defined $referer) {
      $referer = $self->_getDomainPhTarReferer( $self->{packer}->getSubdomainParentId( $id ), @_ );
    }
  }
  if( defined $referer ) {
    return $self->_addRefererCid( $referer , $cid_type );
  }
  else {
    return $self->_addTar( $cid_type, $self->{packer}->getSubdomainsBackupPath($id, $file ), @_);
  }
}

sub addMailnameContent{
  my $self = shift;
  my $cid_type = shift;
  my $id = shift;
  my $file = shift;
  my $domainId = $self->{packer}->getMailNameParentId( $id );
  my $referrer = $self->_getDomainMailTarReferer( $self->{packer}->getMailNameParentId( $id ), @_ );
  if( defined $referrer ){
    return $self->_addRefererCid( $referrer, $cid_type );
  }
  else {
    return $self->_addTar( $cid_type, $self->{packer}->getMailnamesBackupPath($id, $file ), @_);
  }
}

sub addDbContent {
  my $self = shift;
  my $cid_type = shift;
  my $id = shift;
  return $self->_addDb( $cid_type, $self->{packer}->getDatabasesBackupPath( $id, '' ), @_);
}

sub addSubdomainDbContent {
  my $self = shift;
  my $cid_type = shift;
  my $subdomainId = shift;
  my $id = shift;
  return $self->_addDb( $cid_type, $self->{packer}->getSubdomainsBackupPath( $subdomainId, "db$id" ), @_);
}

sub getContentTransportDescription {
  return undef;
}

sub _callRemoteCommand {
    my ($self, $command, $fileName, $options) = @_;
        
    my $remoteExecutorCommand = AgentConfig::getRemoteAgentExecutorCommand();
 
    $remoteExecutorCommand .= " --exec-backup-util ";
    $remoteExecutorCommand .= $command;
    $remoteExecutorCommand .= " -service-node-ip " . $options->{'remoteCommunicationIp'};
    $remoteExecutorCommand .= " -args-file " . $fileName;
    
    Logging::debug("Execute backup content on remote host " . $remoteExecutorCommand);
    my $exec = `$remoteExecutorCommand`;
    chomp($exec);
    
    my $retCode = $? >> 8;
    if( $retCode!=0 ){
      Logging::error( "Cannot create content backup on Service Node $options->{'remoteCommunicationIp'} (ErrorCode: $retCode, STDOUT:$exec) [Error:$!]", 'UtilityError' );
      unlink $fileName;
      return undef;
    }
 
    return $exec;
}


sub _getTarReferer{
  my( $self, $referrer, %options ) = @_;
  if( $referrer && exists $options{'directory'} ) {
    my $directory = HelpFuncs::convertPathToUnixFormat($options{'directory'});
    return undef unless -d $directory;
    my $referrerDir = HelpFuncs::convertPathToUnixFormat($referrer->[2]);
    
    if( index( $directory, $referrerDir ) == 0 ){
      my @res;
      my $ref = substr( $directory, length($referrerDir) );
      while( index( $ref, '/' )==0 ) {
        $ref = substr( $ref, 1 );
      }
      push @res, $referrer->[1];
      push @res, $ref;
      push @res, $directory;
      return \@res;
    }
  }
  return;
}

sub _getDomainMlTarReferer{
  my $self = shift;
  my $domainId = shift;
  if (exists $self->{packer}->{domainMailListContent}->{$domainId} ) {
    return $self->_getTarReferer( \@{$self->{packer}->{domainMailListContent}->{$domainId}}, @_ );
  }
  return;
}

sub _getDomainPhTarReferer{
  my $self = shift;
  my $domainId = shift;
  if (exists $self->{packer}->{domainVhost}->{$domainId} ) {
    return $self->_getTarReferer( \@{$self->{packer}->{domainVhost}->{$domainId}}, @_ );
  }
  return;
}

sub _getDomainStatTarReferer{
  my $self = shift;
  my $domainId = shift;
  if (exists $self->{packer}->{domainStatistics}->{$domainId} ) {
    return $self->_getTarReferer( \@{$self->{packer}->{domainStatistics}->{$domainId}}, @_ );
  }
  return;
}

sub _getDomainMailTarReferer{
  my $self = shift;
  my $domainId = shift;
  if (exists $self->{packer}->{domainMailContent}->{$domainId} ) {
    return $self->_getTarReferer( \@{$self->{packer}->{domainMailContent}->{$domainId}}, @_ );
  }
  return;
}

sub _addRefererCid{
  my ($self, $referer, $cid_type ) = @_;
  return unless defined $referer;
  Logging::debug( "Add referrer cid for type '$cid_type', referer '$referer->[1]', from path '$referer->[2]'" );

  my $cid = XmlNode->new( 'cid' );
  $cid->setAttribute( 'type', $cid_type );
  $cid->setAttribute( 'unpacksize', $referer->[0]->getAttribute( 'unpacksize' ) );
  $cid->setAttribute( 'path', $referer->[0]->getAttribute( 'path' ) );
  $cid->setAttribute( 'referrer', 'true' );
  $cid->setAttribute( 'offset', $referer->[1] );
  my @files = $referer->[0]->getChildren( 'content-file' );
  foreach my $file(@files) {
    if ($file) {
      $cid->addChild( XmlNode->new( 'content-file', 'content' => $file->getText(), 'attributes' => {'size' => $file->getAttribute('size')}));
    }
  }
  return $cid;
}

sub _writeContentToTempFile()
{
  my ($self, $content) = @_;
  
    my $fileName = tmpnam();
    open OPTSFILE, ">$fileName";
    close OPTSFILE;
    
    chown 0 + getpwnam("root"), 0 + getgrnam("psaadm"), $fileName;
    chmod 0640, $fileName;
    
    open OPTSFILE, ">$fileName";
    print OPTSFILE $content;
    close OPTSFILE; 
    
    return $fileName;
}

sub _skipContent {
  my ($self, %options) = @_;

  if (exists($options{'skip_content'})) {
    return $options{'skip_content'} ? 1 : 0;
  } else {
    return exists($self->{packer}->{skip_content}) ? 1 : 0;
  }
}

1;