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

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

use Logging;
use Storage::FileStorage;

use vars qw|@ISA|;

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

sub _init {
  my $self = shift;
  my $storage = shift;
  my $packer = shift;
  my %options = @_;
  $self->{storage} = $storage;
  $self->{packer} = $packer;
  $self->{options} = {%options};
  my %notSupportedRsyncContent;
  $notSupportedRsyncContent{'sb5-server'} = 1;
  $notSupportedRsyncContent{'sapp-distrib'} = 1;
  $notSupportedRsyncContent{'drilldowns-config'} = 1;
  $notSupportedRsyncContent{'key'} = 1;
  $notSupportedRsyncContent{'sb5-site'} = 1;
  $notSupportedRsyncContent{'sb-dump'} = 1;
  $notSupportedRsyncContent{'sapp-apsc'} = 1;
  $notSupportedRsyncContent{'web-app'} = 1;
  $notSupportedRsyncContent{'branding-theme'} = 1;
  $notSupportedRsyncContent{'theme-skin'} = 1;

  $self->{notSupportedContent} = \%notSupportedRsyncContent;

  Logging::debug("Rsync content transport has been initialized");
}

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

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

  $self->_addContent($cid_type, $id, $file, @_);
}

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

sub addClientContent{
  _addContent(@_);
}

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

sub addDomainMailListContent{
  my $self = shift;
  my $cid_type = shift;
  my $id = shift;
  return if $self->_isDomainMlParentContent($id);
  _addContent($self, $cid_type, $id, @_);
}

sub addPhostingContent{
  my $self = shift;
  my $cid_type = shift;
  my $id = shift;
  my $referralId = shift;
  my $file = shift;
  
  if (exists $self->{notSupportedContent}->{$cid_type}) {
    return $self->_addTar( $cid_type, $self->{packer}->getPhostingBackupPath($id, $file ), @_);
  }
  
  return if $self->_isDomainPhParentContent( $self->{packer}->getPhostingParentId( $referralId ) );
  _addContent($self, $cid_type, $id, $file, @_);
}

sub addSubDomainContent{
  _addContent(@_);
}

sub addSubDomainPhostingContent{
  my $self = shift;
  my $cid_type = shift;
  my $id = shift;
  my $webspaceId = shift;
  my $file = shift;
  
  if (exists $self->{notSupportedContent}->{$cid_type}) {
    return $self->_addTar( $cid_type, $self->{packer}->getSubdomainsBackupPath($id, $file ), @_);
  }
  
  _addContent($self, $cid_type, $id, $file, @_);
}

sub addMailnameContent{
  my $self = shift;
  my $cid_type = shift;
  my $id = shift;
  return if $self->_isDomainMailParentContent( $self->{packer}->getMailNameParentId( $id ) );
  _addContent($self, $cid_type, $id, @_);
}

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 {
  my $self = shift;
  my $descriptionNode = XmlNode->new( 'rsync' );
  $descriptionNode->setAttribute( 'host', $self->{options}->{'host'} );
  $descriptionNode->setAttribute( 'port', $self->{options}->{'port'} ) if exists ( $self->{options}->{'port'} );
  $descriptionNode->setAttribute( 'login', $self->{options}->{'login'} );
  $descriptionNode->setAttribute( 'password', $self->{options}->{'passwd'} );
  return $descriptionNode;
}

### Private routines ###

# check full vhost content is dumped for domainId
sub _isDomainPhParentContent{
  my $self = shift;
  my $domainId = shift;
  return 1 if exists $self->{packer}->{domainVhost}->{$domainId};
}

sub _isDomainMlParentContent{
  my $self = shift;
  my $domainId = shift;
  return 1 if exists $self->{packer}->{domainMailListContent}->{$domainId};
}

sub _isDomainMailParentContent{
  my $self = shift;
  my $domainId = shift;
  return 1 if exists $self->{packer}->{domainMailContent}->{$domainId};
}

sub _addContent{
  my $self = shift;
  my $cid_type = shift;
  my $id = shift;
  my $file = shift;
  return $self->_addRsyncContent( $cid_type, @_);
}

sub _addRsyncContent {
  my $self = shift;
  my $cid_type = shift;
  my %options = @_;  
  return if exists $self->{packer}->{skip_content};
  
  if ( $options{'checkEmptyDir'} ) {
    return unless $self->{storage}->checkDirForArchive($options{'directory'}, $options{'exclude'}, $options{'include_hidden_files'});
  }
  
  return $self->_makeCidRsyncNode( $cid_type, $options{'directory'}, 
                                              $options{'include'},
                                              $options{'exclude'},
                                              $options{'no_recursion'} );
}

sub _addDb {
  my $self = shift;
  my $cid_type = shift;
  my $dstFile = shift;
  return if exists $self->{packer}->{skip_content};

  my $id = $self->{storage}->addDb( $dstFile, @_);

  return unless defined $id;

  return $self->_makeCidNode( $id, $cid_type);
}

sub _addTar {
  my $self = shift;
  my $cid_type = shift;
  my $dstFile = shift;
  return if exists $self->{packer}->{skip_content};

  my $id = $self->{storage}->addTar( $dstFile, @_);

  return unless defined $id;

  return $self->_makeCidNode( $id, $cid_type );
}


sub _makeCidNode{
  my ($self, $id, $cid_type ) = @_;
  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] } ) );
  }
  return $cid;
}

sub _makeCidRsyncNode{
  my ($self, $cid_type, $directory, $include, $exclude, $no_recursion) = @_;
  # '$include' could contain filename inside '$directory'.
    
  return unless(-d $directory);
  
  my $cid = XmlNode->new( 'cid-rsync' );
  $cid->setAttribute( 'type', $cid_type );
  
  my $path = $directory;
  if ( defined $include ) {
    my @includes = @{$include};
    foreach my $inc (@includes) {
      $cid->addChild(XmlNode->new('include-item', 'content' => $inc));
    }
  }
  
  if ( defined $exclude ) {
    my @excludes = @{$exclude};
    foreach my $inc (@excludes) {
      $cid->addChild(XmlNode->new('exclude-item', 'content' => $inc));
    }
  }  
  my $cmd = "du -sb";
  if ( defined $no_recursion ) {
    $cmd .= " -S";
  }
  $cmd .= " $path";
  my $sizes = `$cmd`;
  
  my $unpacksize = 0;
  for(split /[\r\n]+/,$sizes) {
    my ($number, $file) = split /\t/;
    $unpacksize += $number; 
  }
  
  if ( -d $path and substr( $path, -1, 1 ) ne '/') {
    $path .= '/';
  }
  
  $cid->setAttribute( 'unpacksize', $unpacksize );
  $cid->setAttribute( 'path', $path );
  return $cid;
}


1;
