# Copyright 1999-2012. Parallels IP Holdings GmbH. All Rights Reserved.
package Storage::FileStorage;

use strict;
use bigint;

use Storage::Storage;
use Logging;
use AgentConfig;
use HelpFuncs;

use POSIX;
use IPC::Run;
use Symbol;

use Storage::Splitter;
use Storage::Counter;

use vars qw|@ISA|;

@ISA = qw|Storage::Storage|;

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

  $self->SUPER::_init(%options);
  $self->{split_size} = $options{split_size};
  $self->{gzip_bundle} = $options{gzip_bundle};
  $self->{output_dir} = $options{output_dir};
  $self->{space_reserved} = $options{space_reserved} if $options{space_reserved};
  $self->{sign} = 1 if $options{sign};

  $self->{last_used_id} = 0;

  $self->{unpacked_size} = 0;
  $self->{packed_size} = 0;

  Logging::debug("-" x 60);
  Logging::debug("FILE storage initialized.");
  Logging::debug("Base directory: $self->{output_dir}");
  Logging::debug("Space reserved: $self->{space_reserved}");
  Logging::debug("Gzip bundles: " . ($self->{gzip_bundle} ? "yes" : "no"));
  Logging::debug("Bundle split size: " . ($self->{split_size} || "do not split"));
  Logging::debug("-" x 60);
  $self->reserveSpace();
}

sub getFullOutputPath{
 my $self = shift;
 return "$self->{output_dir}";
}

sub createRepositoryIndex{
  my ( $self, $index ) = @_;
  if( $index ){
    Logging::debug("Create repository index: $index");
    my $destDir = "$self->{output_dir}/.discovered";
    system("mkdir", "-p", "$destDir") if not -e $destDir;
    open INDEXFILE, "> $destDir/$index";
    close INDEXFILE;
  }
}

sub writeDiscovered{
  my ( $self, $dumpPath, $dumpXmlName, $dumpSize, $ownerGuid, $ownerType, $objectGuid, $objectId ) = @_;

  my $idx = rindex( $dumpXmlName, '.xml' );
  $dumpXmlName = substr( $dumpXmlName, 0, $idx ) if $idx>0;
  my $destDir = $self->getFullOutputPath();
  $destDir .= "/$dumpPath" if $dumpPath;
  $destDir .= "/.discovered/$dumpXmlName";
  push @{$self->{discovered}}, $destDir;

  Logging::debug("Create discovered: $destDir");
  system("mkdir", "-p", "$destDir") if not -e $destDir;
  open SIZEFILE, "> $destDir/size_$dumpSize";
  close SIZEFILE;
  open OWNERFILE, "> $destDir/owner_$ownerGuid";
  close OWNERFILE;
  open OWNERTYPEFILE, "> $destDir/ownertype_$ownerType";
  close OWNERTYPEFILE;
  open GUIDFILE, "> $destDir/GUID_$objectGuid";
  close GUIDFILE;
  open OBJIDFILE, "> $destDir/objectid_$objectId";
  close OBJIDFILE;

  if ($dumpXmlName . ".xml" eq $self->getMainDumpXmlFile()) {
    open INDEPENDFILE, "> $destDir/dump_full";
    close INDEPENDFILE;
  } else {
    open PARTFILE, "> $destDir/dump_part";
    close PARTFILE;
  }

  my @files;
  my $file = ["size_$dumpSize", 0]; push @files, $file;
  $file = ["owner_$ownerGuid", 0]; push @files, $file;
  $file = ["ownertype_$ownerType", 0]; push @files, $file;
  $file = ["GUID_$objectGuid", 0]; push @files, $file;
  $file = ["objectid_$objectId", 0]; push @files, $file;

  if ($dumpXmlName . ".xml" eq $self->getMainDumpXmlFile()) {
    $file = ["dump_full", 0]; push @files, $file;
  } else {
    $file = ["dump_part", 0]; push @files, $file;
  }

  $self->regIdFiles( $destDir, $destDir, 0, \@files );
}

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

  return unless -d $options{'directory'};

  if (defined $options{'checkEmptyDir'} ||
     !exists $options{'include'} && !exists $options{'add_file'} && !exists $options{'include_hidden_files'} # don`t run tar ... * in empty dir
  ) {
    return unless $self->checkDirForArchive($options{'directory'}, $options{'exclude'}, $options{'include_hidden_files'});
  }

  if ($self->{collectStatistics})
  {
    $self->{stopWatch}->createMarker("pack");
  }

  my ($destDir, $destFile, $id) = $self->getFileNameIdFromId( $proposedId, $self->getDefExtension(), 1 );
  Logging::debug("Tar bundle. id=$id, destFile=$destDir/$destFile");

  my $bundle = Storage::Bundle::createTarBundle(%options, 'gzip' => $self->{gzip_bundle});

  unless ($bundle)
  {
    if ($self->{collectStatistics})
    {
      $self->{statistics}->{packTime} += $self->{stopWatch}->getDiff("pack");
      $self->{stopWatch}->releaseMarker("pack");
    }
    return;
  }
  my $size = 0;
  my $files = $self->executeAndSave($destDir, $destFile, $self->getDefExtension(), $bundle, \$size);
  my $ret =  $self->regIdFiles( $id, $destDir, $size, $files );
  if ($self->{collectStatistics})
  {
    $self->{statistics}->{packTime} += $self->{stopWatch}->getDiff("pack");
    $self->{stopWatch}->releaseMarker("pack");
  }

  return $ret;
}

sub CleanupFiles()
{
  my $self = shift;
  my $pid;
  while( ( $pid = wait() ) !=-1 ){
    Logging::debug("The child process '$pid' has been terminated" );
  }
  my $path = $self->getFullOutputPath();
  my @files = $self->getDumpFiles();
  foreach my $file(@files ){
     Logging::debug("Remove file '$file' from repository '$path' ");
     unlink "$path/$file" or Logging::debug("Cannot remove file '$path/$file'");
  }
  if( exists $self->{discovered} ){
    foreach my $discovered(@{$self->{discovered}} ){
       Logging::debug("Remove discovered '$discovered'");
       opendir DIR, $discovered;
       my @dirfiles = readdir( DIR );
       closedir DIR;
       foreach my $file(@dirfiles){
         if( $file ne '.' and $file ne '..' ){
           unlink "$discovered/$file" or Logging::debug("Cannot remove file '$discovered/$file'");
         }
       }
       rmdir( $discovered ) or Logging::debug("Cannot remove discovered '$discovered'");
    }
  }
}

1;

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