# Copyright 1999-2016. Parallels IP Holdings GmbH. All Rights Reserved.
package ArchiveContent::UnixArchiveContent;

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

use Logging;
use AgentConfig;
use ArchiveContent::ArchiveContent;
use Cwd;

use vars qw|@ISA|;

@ISA = qw|ArchiveContent::ArchiveContent|;

sub new {
  my $self = {};
  bless( $self, shift );
  $self->_init(@_);
  return $self;
}

sub _init {
  my ( $self, $storage, $packer ) = @_;
  $self->{storage} = $storage;
  $self->{packer} = $packer;
  Logging::debug("Unix Archive content transport has been initialized");
}


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

    my $fileName = $self->_prepareDataForRemoteBackupAgent ($proposedId, \%options);

    my $response = undef;

    $response = $self->_callRemoteCommand('backup-content', $fileName, \%options);
    Logging::debug("RESPONSE: $response");

    $response = $self->_callRemoteCommand('get-logs', $fileName, \%options);
    Logging::debug("Logs from remote node:" . $response);

    # In this variable information from remote host about created archives are stored
    my $storage1 = undef;
    $response = $self->_callRemoteCommand('get-created-content-info', $fileName, \%options);
    Logging::debug("RESPONSE: $response");
    eval($response);
    if ($@) {
        Logging::debug(Data::Dumper::Dumper $@);
    }

    $response = $self->_callRemoteCommand('destroy-session', $fileName, \%options);

    unlink $fileName;

    return $storage1;
}

sub hasLink {
  my ($self, $linkpath, $targetpath, %options) = @_;

  Logging::debug("Check link '$linkpath' to '$targetpath'.");
  my $result = defined($options{'remoteCommunicationIp'}) ? $self->_hasRemoteLink($linkpath, $targetpath, %options) : $self->_hasLocalLink($linkpath, $targetpath);
  Logging::debug("Check link result: $result");
  return $result;
}

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

  Logging::debug("Check directory existence '$directory'.");
  my $result = defined($options{'remoteCommunicationIp'}) ? $self->_remoteDirectoryExists($directory, %options) : -d $directory;
  Logging::debug("Result: $result");
  return $result;
}

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

  my $tmpFileContent = '';
  $tmpFileContent .= "\$directory = '" . $directory . "';";
  $tmpFileContent .= "\$sessionId = '" . HelpFuncs::mktemp("XXXXXXXX") . "';";

  my $fileName = $self->_writeContentToTempFile($tmpFileContent);

  my $directoryExists = $self->_callRemoteCommand('directory-exists', $fileName, \%options);
  Logging::debug("DirectoryExists: " . $directoryExists);
  my $logs = $self->_callRemoteCommand('get-logs', $fileName, \%options);
  Logging::debug("Logs from remote node: " . $logs);
  $self->_callRemoteCommand('destroy-session', $fileName, \%options);
  unlink $fileName;

  return $directoryExists eq 'true';
}

sub _prepareDataForRemoteBackupAgent {
    my ($self, $proposedId, $options) = @_;

    my $tmpFileContent = '';
    # create file with input parameters for $storage->addTar method on remote host
    $tmpFileContent = "%options = (";
    foreach my $key (keys %$options) {
      if (ref($options->{$key}) eq 'ARRAY') {
        $tmpFileContent .= "'$key'" . "=>" . "['" . join("','", @{$options->{$key}}). "'] , ";
      } else {
        $tmpFileContent .= "'$key'" . "=>" . "'$options->{$key}'" . ',';
      }
    }
    $tmpFileContent .= ");";

    $tmpFileContent .= "\$proposedId = '". $proposedId ."';";

    # save also information for storage initialization
    $tmpFileContent .= "\$passwd = '". $self->{storage}->{ftpsettings}->{password}."';";
    $tmpFileContent .= "\$do_gzip = '". $self->{storage}->{gzip_bundle}."';";
    $tmpFileContent .= "\$workDir = '". $self->{storage}->{output_dir}."';";
    $tmpFileContent .= "\$splitSize = '". $self->{storage}->{split_size}."';";
    $tmpFileContent .= "\$space_reserved = '". $self->{storage}->{space_reserved}."';";
    $tmpFileContent .= "\$passiveMode = '". $self->{storage}->{passive_mode}."';";

    # session identificator on remote node
    $tmpFileContent .= "\$sessionId = '".HelpFuncs::mktemp("XXXXXXXX")."';";

    my $fileName = $self->_writeContentToTempFile($tmpFileContent);

    return $fileName;
}


### Private routines ###

sub _addTar {
  my $self = shift;
  my $cid_type = shift;
  my $dstFile = shift;
  my %options = @_;
  return undef if $self->_skipContent(%options);

  if (defined $options{'remoteCommunicationIp'}) {
    my $remoteStorage = $self->addRemoteTar( $dstFile, %options);
    return undef unless defined $remoteStorage;
    return $self->_makeCidNodeFromRemote($dstFile, $cid_type, $remoteStorage, @_);
  } else {
    my $id = $self->{storage}->addTar( $dstFile, @_);
    return undef unless defined $id;
    return $self->_makeCidNode($id, $cid_type, @_);
  }
}


sub _makeCidNode{
  my ($self, $id, $cid_type, %options) = @_;
  my $cid = XmlNode->new( 'cid' );
  $cid->setAttribute( 'type', $cid_type );
  $cid->setAttribute( 'unpacksize', $self->{storage}->getFilesUnpackSizeFromId($id) );
  $cid->setAttribute( 'path', $self->{storage}->getFilePathFromId( $id ) );
  my $files = $self->{storage}->getFilesFromId( $id );
  foreach my $filedata( @{$files} ){
    $cid->addChild( XmlNode->new( 'content-file', 'content' => $filedata->[0], 'attributes' => {'size' => $filedata->[1] } ) );
  }

  if (defined($options{'include'})) {
    my @includes = @{$options{'include'}};
    foreach my $inc (@includes) {
      $cid->addChild(XmlNode->new('include-item', 'content' => $inc));
    }
  }

  if (defined($options{'exclude'})) {
    my @excludes = @{$options{'exclude'}};
    foreach my $exc (@excludes) {
      $cid->addChild(XmlNode->new('exclude-item', 'content' => $exc));
    }
  }
  
  if (defined($options{'indexed'})) {
    $cid->setAttribute( 'indexed', 'true' );
  }

  return $cid;
}

sub _makeCidNodeFromRemote{
  my ($self, $proposedId, $cid_type, $storage, %options) = @_;
  my ($destDir, $destFile, $id) = $storage->getFileNameIdFromId( $proposedId, $storage->getDefExtension(), 1 );
  my $cid = XmlNode->new( 'cid' );
  $cid->setAttribute( 'type', $cid_type );
  $cid->setAttribute( 'unpacksize', $storage->getFilesUnpackSizeFromId($id) );
  $cid->setAttribute( 'path', $storage->getFilePathFromId( $id ) );
  my $files = $storage->getFilesFromId( $id );
  foreach my $filedata( @{$files} ){
    $cid->addChild( XmlNode->new( 'content-file', 'content' => $filedata->[0], 'attributes' => {'size' => $filedata->[1] } ) );
  }

  if (defined($options{'include'})) {
    my @includes = @{$options{'include'}};
    foreach my $inc (@includes) {
      $cid->addChild(XmlNode->new('include-item', 'content' => $inc));
    }
  }

  if (defined($options{'exclude'})) {
    my @excludes = @{$options{'exclude'}};
    foreach my $exc (@excludes) {
      $cid->addChild(XmlNode->new('exclude-item', 'content' => $exc));
    }
  }

  return $cid;
}

sub _addDb {
  my $self = shift;
  my $cid_type = shift;
  my $dstFile = shift;
  my %options = @_;
  return if $self->_skipContent(%options);
  my $id = $self->{storage}->addDb( $dstFile, @_);
  if ( defined $id ) {
    return $self->_makeCidNode($id, $cid_type, @_);
  }
  return;
}

sub _hasLocalLink {
  my ($self, $linkpath, $targetpath) = @_;

  if (! -l $linkpath) {
    return 'false';
  }
  return (Cwd::realpath($linkpath) eq $targetpath) ? 'true' : 'false';
}

sub _hasRemoteLink {
  my ($self, $linkpath, $targetpath, %options) = @_;

  my $tmpFileContent = '';
  $tmpFileContent .= "\$linkpath = '" . $linkpath . "';";
  $tmpFileContent .= "\$targetpath = '" . $targetpath . "';";
  $tmpFileContent .= "\$sessionId = '" . HelpFuncs::mktemp("XXXXXXXX") . "';";

  my $fileName = $self->_writeContentToTempFile($tmpFileContent);

  my $hasLink = $self->_callRemoteCommand('has-link', $fileName, \%options);
  my $logs = $self->_callRemoteCommand('get-logs', $fileName, \%options);
  Logging::debug("Logs from remote node: " . $logs);
  $self->_callRemoteCommand('destroy-session', $fileName, \%options);

  unlink $fileName;

  return $hasLink;
}

1;