# Copyright (c) 2007-2012 Zmanda, Inc.  All Rights Reserved.
# Copyright (c) 2013-2016 Carbonite, Inc.  All Rights Reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
#
# Contact information: Carbonite Inc., 756 N Pastoria Ave
# Sunnyvale, CA 94085, or: http://www.zmanda.com

package Amanda::Index::Message;
use strict;
use warnings;

use Amanda::Message;
use vars qw( @ISA );
@ISA = qw( Amanda::Message );

sub local_message {
    my $self = shift;

    if ($self->{'code'} == 2400000) {
        return "Can't find header filename for the dump";
    } elsif ($self->{'code'} == 2400001) {
        return "header file '$self->{'filename'} does not exist";
    } elsif ($self->{'code'} == 2400002) {
        return "header file '$self->{'filename'} is not a regular file";
    } elsif ($self->{'code'} == 2400003) {
        return "Can'open header file '$self->{'filename'}: $self->{'error'}";
    } elsif ($self->{'code'} == 2400004) {
        return "The header buffer";
    } elsif ($self->{'code'} == 2400005) {
        return "The header";
    } elsif ($self->{'code'} == 2400006) {
        return "The index";
    }
}

package Amanda::Index;

use strict;
use warnings;
use POSIX ();
use Fcntl qw( O_RDWR O_CREAT LOCK_EX LOCK_NB );
use Data::Dumper;
use vars qw( @ISA );
use Time::Local;
use Text::ParseWords;
use IPC::Open2;

use Amanda::Paths;
use Amanda::Util qw( match_labelstr );
use Amanda::Config qw( :getconf );
use Amanda::Device qw( :constants );
use Amanda::Debug qw( debug );
use Amanda::MainLoop;
use Amanda::Process;

=head1 NAME

Amanda::Index -- Get index or header from index directory

=head1 SYNOPSIS

    use Amanda::Index;

    my $index = Amanda::Index->new();
    my $index = Amanda::Index->new(indexdir => $indexdir);

    my $h_name = $index->get_header_filename(host      => $host,
					     disk      => $disk,
					     datestamp => $datestamp,
					     level     => $level);
    my $buffer = $index->get_header_buffer(host      => $host,
					   disk      => $disk,
					   datestamp => $datestamp,
					   level     => $level);
    my $header = $index->get_header(host      => $host,
				    disk      => $disk,
				    datestamp => $datestamp,
				    level     => $level);
    my $index_handle = $index->get_index_handle(host      => $host,
					        disk      => $disk,
					        datestamp => $datestamp,
					        level     => $level);
    my $index_data = $index->get_index(host      => $host,
				       disk      => $disk,
				       datestamp => $datestamp,
				       level     => $level);
=cut

sub new {
    my $class = shift;
    my %params = @_;

    my $indexdir = $params{'indexdir'};
    $indexdir = getconf($CNF_INDEXDIR) if !$indexdir;

    my $self = {
	indexdir => $indexdir,
    };

    bless $self, $class;
    return $self;
}

sub get_header_filename() {
    my $self = shift;
    my %params = @_;

    return Amanda::Logfile::getheaderfname($params{'host'},
					   $params{'disk'},
					   $params{'datestamp'},
					   0+$params{'level'});
}

sub get_header_buffer() {
    my $self = shift;

    my $filename = $self->get_header_filename(@_);
    if (!$filename) {
	return Amanda::Index::Message->new(
			source_filename => __FILE__,
                        source_line => __LINE__,
                        code        => 2400000,
			severity => $Amanda::Message::ERROR,
                        filename    => $filename);
    }
    if (!-e $filename) {
	return Amanda::Index::Message->new(
			source_filename => __FILE__,
                        source_line => __LINE__,
                        code        => 2400001,
			severity => $Amanda::Message::ERROR,
                        filename    => $filename);
    }
    if (!-f _) {
	return Amanda::Index::Message->new(
			source_filename => __FILE__,
                        source_line => __LINE__,
                        code        => 2400002,
			severity => $Amanda::Message::ERROR,
                        filename    => $filename);
    }
    open my $fh, "<", $filename ||
	return Amanda::Index::message->new(
			source_filename => __FILE__,
                        source_line => __LINE__,
                        code        => 2400003,
			severity => $Amanda::Message::ERROR,
			error       => $!,
                        filename    => $filename);
    my $buffer;
    sysread $fh, $buffer, 32768;
    close($fh);

    return $buffer;
}

sub get_header() {
    my $self = shift;

    my $buffer = $self->get_header_buffer(@_);
    return $buffer if $buffer->isa("Amanda::Message");

    my $hdr = Amanda::Header->from_string($buffer);

    return $hdr;
}

sub get_index_handle() {
    my $self = shift;
    my %params = @_;

    my $filename;
    my $need_uncompress;
    my $need_sort;
    $filename = Amanda::Logfile::getindex_sorted_fname($params{'host'},
						       $params{'disk'},
						       $params{'datestamp'},
						       0+$params{'level'});
    if (-f $filename) {
    } else {
	$filename = Amanda::Logfile::getindex_sorted_gz_fname(
				$params{'host'},
				$params{'disk'},
				$params{'datestamp'},
				0+$params{'level'});
	if (-f $filename) {
	    $need_uncompress = 1;
	} else {
	    $filename = Amanda::Logfile::getindex_unsorted_fname(
				$params{'host'},
				$params{'disk'},
				$params{'datestamp'},
				0+$params{'level'});
	    if (-f $filename) {
		$need_sort = 1;
	    } else {
		$filename = Amanda::Logfile::getindex_unsorted_gz_fname(
				$params{'host'},
				$params{'disk'},
				$params{'datestamp'},
				0+$params{'level'});
		if (-f $filename) {
		    $need_uncompress = 1;
		    $need_sort = 1;
		} else {
		    $filename = Amanda::Logfile::getindexfname(
				$params{'host'},
				$params{'disk'},
				$params{'datestamp'},
				0+$params{'level'});
		    if (-f $filename) {
			$need_uncompress = 1;
			$need_sort = 1;
		    }
		}
	    }
	}
    }

    if (!defined $need_uncompress && !defined $need_sort) {
	open my $h, "<", $filename;
	return $h;
    }
    my $pid_uc;
    if (defined $need_uncompress && !defined $need_sort) {
	#$pid_uc = open2($h1, undef, $Amanda::Constants::UNCOMPRESS_PATH,
	#			 $Amanda::Constants::UNCOMPRESS_OPT,
	#			 $filename);
	open my $h1, "-|", $Amanda::Constants::UNCOMPRESS_PATH,
			   $Amanda::Constants::UNCOMPRESS_OPT,
			   $filename;
	return $h1;
    }

    my $h1;
    if (defined $need_uncompress) {
	$pid_uc = open2(\*AAAA, undef, $Amanda::Constants::UNCOMPRESS_PATH,
				 $Amanda::Constants::UNCOMPRESS_OPT,
				 $filename);
    } else {
	open (AAAA, "<", $filename) or die("AAAAA");
    }
    my $pid_sort;
    my $new_filename = Amanda::Logfile::getindex_sorted_fname(
				$params{'host'},
				$params{'disk'},
				$params{'datestamp'},
				0+$params{'level'});
    $pid_sort = open2(undef, "<&AAAA", $Amanda::Constants::SORT_PATH,
				"-", "-o", $new_filename,
				"-T", getconf($CNF_TMPDIR));

    if ($pid_uc) {
	waitpid $pid_uc, 0;
    }
    if ($pid_sort) {
	waitpid $pid_sort, 0;
	open $h1, "<", $new_filename;
    }
    return $h1;
}

sub get_index() {
    my $self = shift;

    my $handle = $self->get_index_handle(@_);
    my $buffer;
    {
	local $/;
	$buffer = <$handle>;
    }
    close $handle;

    return $buffer;
}

1;
