#!/usr/bin/perl -w
# -*- mode: CPerl; tab-width: 8; fill-column: 70; -*- 

use lib qw( /usr/share/docs-build/docs_genspec );
#use lib qw( ../data/docs_genspec );

use Heap::Config;
use Heap::Tags;
use Heap::Hooks;
use Heap::Archive;

use Template;
use File::Temp qw/ tempdir /;
use Getopt::Long;
use Pod::Usage;

my $help;
my $archivefile = "";
my $specfile = "";
my $changelog = "";
my $rootdoc = "";
my $destdir = "";
my $output = "";
my $version = "0";

GetOptions('h|help' 		=> \$help,
	   'a|archive=s'	=> \$archivefile,
	   's|spec=s'		=> \$specfile,
	   'c|changelog=s'	=> \$changelog,
	   'r|rootdoc=s'	=> \$rootdoc,
	   'o|output=s' 	=> \$output,
	   'V|version=i'	=> \$version,
	  ) or pod2usage( -exitval => 1, -output => \*STDERR );
pod2usage(1) if $help;
pod2usage( -msg => "Error: Incorrect argument for the -a option", -exitval => 1, -output => \*STDERR ) if ! -f $archivefile;
pod2usage( -msg => "Error: Incorrect argument for the -r option", -exitval => 1, -output => \*STDERR ) if $rootdoc eq "";

sub error($$) {
  my ( $message, $fatal ) = @_;
  printf STDERR "Error: %s\n", $message;
  exit(1) if $fatal;
}

sub compare_rpmver($$) {
  my ($ver1, $ver2) = @_;
  my $rc = `/usr/bin/rpmevrcmp '$ver1' '$ver2'`;
  return ($rc);
}

sub parse_docinfo($) {
  my ($docinfo_file) = @_;
  my $out_hash = {};
  open(DOCINFO, $docinfo_file) or error("Can't open docinfo file: $docinfo_file", 1);
  while(<DOCINFO>) {
    /([^$Heap::Tags::field_sep]+)$Heap::Tags::field_sep\s*(.*)$/;
    my $tag = lc($1) or next;
    my $value = $2 or next;

    next unless exists $Heap::Tags::docinfo_tags->{$tag};
    $value =~ /^\s*(.*)\s*$/;
    $out_hash->{$tag} = $1;
  }
  close(DOCINFO);
  return ($out_hash);
}

sub translate_tags($) {
  my ($input_hash) = @_;
  my $out_hash = {};

  foreach (keys %{$Heap::Tags::translate}) {
    next unless exists $input_hash->{$_};
    my $rpmtag = $Heap::Tags::translate->{$_};
    my $value = $input_hash->{$_};

    # Use common hooks
    $value = $Hooks::tags->{$rpmtag}($value) if exists $Hooks::tags->{$rpmtag};
    $out_vars->{$rpmtag} .= $value;
  }
  return ($out_vars);
}

sub add_defaults($) {
  my ($in) = @_;
  map { $in->{$_} = $Heap::Tags::defaults->{$_} if ! exists $in->{$_} and exists $Heap::Tags::defaults->{$_} }
    keys %{$Heap::Tags::defaults};
  return ($in);
}

my $dir_template = 'tempdir.XXXXXXXXXXX';
my $temp = tempdir( $dir_template, CLEANUP => 1, TMPDIR => 1 );

my $archive = new Heap::Archive($archivefile);
my $archive_info = $archive->get_info();
my $fileslist = $archive->list('^[^\/]+\/docinfo$');
error ("Can't find archive root directory", 1) if @{$fileslist} != 1;
$archive->get_file($fileslist->[0], { DEST_DIR => $temp } );

# Read docinfo
error ("Can't extact docinfo file",1) unless -f "$temp/docinfo";
my $docinfo = parse_docinfo("$temp/docinfo");

# Check necessary docinfo tags
map { error("$_ field must be present in docinfo", 1) unless exists $docinfo->{$_} }
  qw { id archive timestamp };

# Translate Docinfo tags to RPM tags.
my $vars = {};
$vars = translate_tags($docinfo);

# Add default tags
$vars = add_defaults($vars);

# Tags Hacks
{
  $archivefile =~ /\/?([^\/]+)$/;
  $vars->{SOURCE0} = $1;
  $vars->{ROOTDOC} = $rootdoc unless $rootdoc eq "";
  $vars->{ARCHIVENAME} = exists $vars->{ARCHIVE} ? ($vars->{ARCHIVE} =~ /^([^.]*)/ and $1) : "???" ;
  $vars->{NAME} = join('-', "docs", $vars->{ARCHIVENAME}, $vars->{ID}) if exists $vars->{ARCHIVENAME} and exists $vars->{ID};
  $vars->{VERSION} = $version if $version > 0;
  $vars->{VERSION} = $vars->{TIMESTAMP} if $vars->{VERSION} eq "default";
  $vars->{FORMAT}  =~ s/"//g;
  $vars->{ROOTDOC} =~ s/"//g;

  if (exists $docinfo->{language}) {
    my $lang = $docinfo->{language};
    unless (exists $Heap::Config::translate_lang->{$lang} ) {
      printf STDERR "Warning: Encoding for document language undefined, using default(%s)\n", $Heap::Config::translate_lang->{default};
      $vars->{ENCODING} = $Heap::Config::translate_lang->{default};
    }
    else {
      $vars->{ENCODING} = $Heap::Config::translate_lang->{$lang};
    }
  }

  if ( -f "$specfile" ) {
    open(OLD_SPEC, "$specfile") or die "Can't open new spec";
    $vers = "";
    $rels = "";
    while(<OLD_SPEC>) {
      $vers = "$1" if !$vers && /^Version:\s+([^\s]+)$/;
      $rels = "$1" if !$rels && /^Release:\s+(alt[^\s]+)$/;
      last if $vers and $rels;
    }
    close(OLD_SPEC);

    my $rc = compare_rpmver("$vers", "$vars->{VERSION}");
    if ($rc == 1) {
	printf STDERR "Warning: Version downgrade: docinfo < old spec. Old version preserved, release updated instead";
      $vars->{VERSION} = "$vers";
      $rels =~ s/alt([0-9]+).*$/$1/ ;
      $rels = $rels+1 ;
      $vars->{RELEASE} = "alt".$rels ;
    }
    elsif ($rc == 0) {
      $rels =~ s/alt([0-9]+).*$/$1/ ;
      $rels = $rels+1 ;
      $vars->{RELEASE} = "alt".$rels ;
    }
    elsif ($rc == -1) {
      $vars->{RELEASE} = "alt1";
    }
  }
}

# check necessary RPM tags
map { $vars->{$_} = "$_ field must be present in package" unless exists $vars->{$_} }
  qw { NAME VERSION RELEASE SUMMARY LICENSE DESCRIPTION };

# SPEC Generation
unless ( -f "$specfile" ) {
#  print "# Generation\n";
  $output = $ENV{PWD}."/docs-".$vars->{ARCHIVENAME}."-".$vars->{ID}.".spec" unless -e $output;
  $output .= "/docs-".$vars->{ARCHIVENAME}."-".$vars->{ID}.".spec" if -d $output;
  my $template = Template->new({
				INCLUDE_PATH 	=> $Heap::Config::include_path,
				INTERPOLATE  	=> 1,
				PRE_CHOMP   	=> 0,
				POST_CHOMP   	=> 0,
				TRIM		=> 0,
				EVAL_PERL    	=> 1,
				OUTPUT		=> "$output",
			       });
#  print "# $output\n";
  $template->process($Heap::Config::template, $vars) or die $template->error();
}
else {
#  print "# Modify\n";
  $output = $ENV{PWD} unless -e $output;
  if ( -d $output ) {
    $specfile =~ /^(.*\/)?([^\/]+)$/;
    $output .= "/".$2;
  }

  open(NEW_SPEC, ">$temp/new.spec") or die "Can't open new spec";
  open(OLD_SPEC, "$specfile") or die "Can't open new spec";

  {
    undef $/;
    while (<OLD_SPEC>) {
      s/(\n\s*%setup_docs_module\s+\w+\s+\w+\s+)(\d+)(\s+\w+)\s*\n/$1$vars->{TIMESTAMP}$3\n/;
      s/(\nVersion\s*:\s*)(.*?)\n/$1$vars->{VERSION}\n/i;
      s/(\nRelease\s*:\s*)(.*?)\n/$1$vars->{RELEASE}\n/i;
      s/(\nLicense\s*:\s*)(.*?)\n/$1$vars->{LICENSE}\n/i;
      s/(\nUrl\s*:\s*)(.*?)\n/$1$vars->{URL}\n/i;
      if ( $docinfo->{language} eq "en") {
	s/(\nSummary\s*:\s*)(.*?)\n/$1$vars->{SUMMARY}\n/i;
	s/(\n%description)\s*\n.*?(\n\s*\n%)/$1\n$vars->{DESCRIPTION}$2/gs;
      }
      else {
	s/(\nSummary\($vars->{ENCODING}\)\s*:\s+)(.+?)\n/$1$vars->{SUMMARY}\n/i;
	s/(\n%description\s+-l\s+$vars->{ENCODING}).*?(\n\s*\n%)/$1\n$vars->{DESCRIPTION}$2/gs;
      }
      s/(\n\s*%docs_build\s+)"[^"]+"(\s+"[^"]+")\s*\n/$1"$vars->{FORMAT}"$2\n/;
      s/(\n\s*%docs_build\s+"[^"]+"\s+)"[^"]+"\s*\n/$1"$vars->{ROOTDOC}"\n/;
      print NEW_SPEC;
    }
  }

  close(OLD_SPEC);
  close(NEW_SPEC);
  rename ("$temp/new.spec", "$output")
    or error "Can't rename new spec",1;
}

# Add changelog
if ( $changelog ne "" ) {
  if ( -f $output) {
    $changelog =~ s/\([\W\s]\)/\\$1/g;
    system ("/usr/bin/add_changelog --entry='$changelog' '$output'") == 0
      or print STDERR "couldn't exec add_changelog: $!";
  }
}

__END__

=head1 NAME

docs_genspec - simple helper script to generate RPM spec file.

=head1 DESCRIPTION

This B<program> will extract the given DOCINFO from ALT Linux Docs Heap archive and generate simple RPM spec file.

=head1 SYNOPSIS

docs_genspec [options] -a ARCHIVENAME -r DOCROOT

=head1 OPTIONS

=over 25

=item B<-h, --help>

Print a brief help message and exits.

=item B<-a, --archive=ARCHIVENAME>

This the option is used for the definition of heap archive.

=item B<-c, --changelog=ENTRY>

Add changelog ENTRY text.

=item B<-r, --rootdoc=FILENAME>

root document filename (single or main document which include all the other in parts);

=item B<-s --spec=FILE>

update existing spec (once generated by docs_genspec);

=item B<-o, --output=[FIlE|DIR]>

Place for the generated RPM spec file.

=item B<-V, --version=VERSION>

use given VERSION instead of docinfo's Version or Timestamp.

=back

=cut
