#!perl

use strict;
use warnings;
use open OUT => ':utf8';

use CGI;
use File::Copy;
use File::Util;
use Template;
use XML::Twig;
use Data::Dumper;

use TCE::Config;
use Pica::Records;
use Pica::Converter;

# global variables
our @messages;
our $go = 1;

my $dmdsec = '';
my @new_tree = ();
my $max_level = 0;
my $vol_recs = undef;
my $structmap = '';
my $structlink = '';
my $volumeid = undef;
my $metshdr = undef;


our $msg_ok = $TCE::Config::MSG_SYMBOLS{'ok'};
our $msg_fail = $TCE::Config::MSG_SYMBOLS{'fail'};
our $msg_warn = $TCE::Config::MSG_SYMBOLS{'warn'};

# create the File::Util object
my $fu = File::Util->new();

# create the CGI object
my $cgi = CGI->new();

# create the converter object
my $converter = Pica::Converter->new();

# create the Template object
my $template = Template->new({'INCLUDE_PATH' => $TCE::Config::TEMPLATES_DIR, 'PLUGINS' => {'ResolvePND' => 'TCE::Filter::ResolvePND'} });

#receive cgi parameter
my $item_id    = $cgi->param('itemid') || $ARGV[0] || error($msg_fail.' Es wurde kein Vorgangstitel angegeben. Daher ist ein Export nicht möglich.');

# convert struct tree to picaplus
if ($go)
{
	# get the collections if any
	my @collections = ();
	if (-e $TCE::Config::ITEMS.$item_id.'/'.$TCE::Config::DATA_STORAGE{'collections'})
	{
		open FILE, '<'.$TCE::Config::ITEMS.$item_id.'/'.$TCE::Config::DATA_STORAGE{'collections'};
		while (my $collection = <FILE>)
		{
			chomp $collection;
			push @collections, $collection if ($collection =~ /[A-Za-z1-9]/);
		}
		close FILE;
	}
	if (@collections)
	{
		foreach my $collection (@collections)
		{
			message("$msg_ok Dieser Vorgang ist der digitalen Sammlung $collection zugeordnet.");
		}
	}
	else
	{
		message("$msg_warn Dieser Vorgang ist keiner digitalen Sammlung zugeordnet.")
	}
	

	# check if all necessary files are available
	unless (-e $TCE::Config::ITEMS.$item_id.'/'.$TCE::Config::DATA_STORAGE{'volume'})
	{
		$go = 0;
		error("$msg_fail Die bibliographischen Daten für den Band und das Gesamtwerk wurden nicht gefunden.");
	}
	unless (-e $TCE::Config::ITEMS.$item_id.'/'.$TCE::Config::DATA_STORAGE{'struct'})
	{
		$go = 0;
		error("$msg_fail Der Strukturbaum wurde nicht gefunden.");
	}
	unless (-e $TCE::Config::ITEMS.$item_id.'/'.$TCE::Config::DATA_STORAGE{'goobi'})
	{
		$go = 0;
		error("$msg_fail Die ursprüngliche METS-Datei (Goobi-Download) wurde nicht gefunden.");
	}		
	unless (-e $TCE::Config::ITEMS.$item_id.'/'.$TCE::Config::DATA_STORAGE{'pages'})
	{
		$go = 0;
		error("$msg_fail Die Paginierungssequenz wurde nicht gefunden.");
	}
	unless (-e $TCE::Config::ITEMS.$item_id.'/'.$TCE::Config::DATA_STORAGE{'agents'})
	{
		$go = 0;
		error("$msg_fail $TCE::Config::DATA_STORAGE{'agents'}, eine Datei, die für den METS Header benötigt wird, wurde nicht gefunden.");
	}
	unless (-e $TCE::Config::ITEMS.$item_id.'/'.$TCE::Config::DATA_STORAGE{'createdate'})
	{
		$go = 0;
		error("$msg_fail $TCE::Config::DATA_STORAGE{'createdate'}, eine Datei, die für den METS Header benötigt wird, wurde nicht gefunden.");
	}
		
	if ($go)
	{
		# convert the volume and host item
		$vol_recs = Pica::Records->new($TCE::Config::ITEMS.$item_id.'/'.$TCE::Config::DATA_STORAGE{'volume'});
		message("$msg_ok Datensätze für Band- und Gesamtwerk konvertiert");		

		# convert the struct tree
		my $structtree = read_file($TCE::Config::ITEMS.$item_id.'/'.$TCE::Config::DATA_STORAGE{'struct'});
		foreach my $elem (@{$structtree})
		{
			my $p3_record = $elem->{'metadata'};
			# downcast from utf-8
			utf8::decode($p3_record);
			# in a later version, all data should be stored and handled in UTF-8
			# in order to enable the use of non-roman scripts etc.
			
			$elem->{'metadata'} = $converter->to_picaplus($p3_record);
			# create a new Pica::Record object
			my $object = Pica::Record->new();
			   # fill the object
			   $object->read_fields($elem->{'metadata'});
			   $object->start_page($elem->{'startpage'});
			   $object->end_page($elem->{'endpage'});
			   $object->id($elem->{'id'});
			   $object->hierarchy_level($elem->{'hierarchyLevel'});
 
		        # set the maximum hierarchy level if necessary
		        $max_level = $elem->{'hierarchyLevel'} if ($elem->{'hierarchyLevel'} > $max_level);
			push @new_tree, $object;
		}
		message("$msg_ok Datensätze für die Strukturelemente konvertiert");
		# increase the maximum hierarchy level for root element
		$max_level += 1;
		
		
		# write mets:dmdSec elements

		
		my $output = '';
   	        $template->process('mets_firstdmdsec.tmpl',{'records' => $vol_recs->all_records, 'collections' => \@collections},\$output) || error("$msg_fail Fehler beim Schreiben der deskriptiven Metadaten (mets:dmdSec): ".$template->error());
		$dmdsec .= $output;
		   
		foreach my $object (@new_tree)
		{
			$output = '';
			$template->process('mets_otherdmdsec.tmpl',{'record' => $object},\$output) || error("$msg_fail Fehler beim Schreiben der deskriptiven Metadaten (mets:dmdSec): ".$template->error());
		        $dmdsec .= $output;	
		}
		message("$msg_ok Schreiben der deskriptiven Metadaten (mets:dmdSec) erfolgreich abgeschlossen.") if ($go);	

	}
	if ($go)
	{
		
		my $volume = $vol_recs->next_record;
		$volume->hierarchy_level($max_level);
		$volumeid = $volume->id;
		unshift(@new_tree,$volume);
		
		# write structLink
		my $pages = read_file($TCE::Config::ITEMS.$item_id.'/'.$TCE::Config::DATA_STORAGE{'pages'});
		$new_tree[0]->start_page($pages->[0]);
		$new_tree[0]->end_page($pages->[$#{$pages}]);
		
		$template->process('mets_structlink.tmpl',{'tree' => \@new_tree, 'pages' => $pages},\$structlink) || error("$msg_fail Fehler bei der Zuordnung der Images zur logischen Dokumentstruktur (mets:structLink)");
		message("$msg_ok Erstellen der Zuordnung der Images zur logischen Dokumentstruktur (mets:structLink) erfolgreich abgeschlossen.") if ($go);
	
	}
	if ($go)
	{
		if ($new_tree[0]->hostitem)
		{
			my $host = $new_tree[0]->hostitem;
			$host->hierarchy_level($max_level + 1);
			$host->pointer($TCE::Config::POINTER.'PPN'.$host->id);
			$host->id($host->id.'_'.$new_tree[0]->id);
			unshift(@new_tree,$host);
		}
		# write mets:structMap
		$template->process('mets_structmap.tmpl',{'tree' => \@new_tree},\$structmap) || error("$msg_fail Fehler beim Schreiben der logischen Dokumentstruktur (mets:structMap): ".$template->error());
		message("$msg_ok Erstellen der logischen Dokumentstruktur (mets:structMap) erfolgreich abgeschlossen.") if ($go);	
	}
	if ($go)
	{
		my $agents = read_file($TCE::Config::ITEMS.$item_id.'/'.$TCE::Config::DATA_STORAGE{'agents'});
		my $createdate = read_file($TCE::Config::ITEMS.$item_id.'/'.$TCE::Config::DATA_STORAGE{'createdate'});
		my $lastmoddate = get_timestamp(0);
		$template->process('mets_header.tmpl',{'agents' => $agents, 'createdate' => $createdate, 'lastmoddate' => $lastmoddate},\$metshdr) || error("$msg_fail Fehler beim Schreiben des METS Headers: ".$template->error());;
		message("$msg_ok Erstellen des METS Headers erfolgreich abgeschlossen.") if ($go);
		
	}
	if ($go)
	{
		# extract physical structmap and filesec
		# use SAXON !!!
 		$| = 1;
 		my $output = '';
 		$template->process('mets_mets.tmpl',{'metshdr' => $metshdr, 'dmdsec' => $dmdsec, 'structmap' => $structmap, 'structlink' => $structlink, 'volumeid' => $volumeid },\$output) || error("$msg_fail Fehler bei der Erstellung der METS-Datei");
		message("$msg_ok Vorläufige METS Datei erfolgreich erstellt") if ($go);   
		
		open FILE, ">".$TCE::Config::ITEMS.$item_id.'/temp.xml';
		print FILE $output;
		close FILE;
		
		my $stylesheet=$TCE::Config::STYLESHEET_DIR.'makemymets.xsl';
		my $metsfile = $TCE::Config::ITEMS.$item_id.'/'.$item_id.'.xml';
		my $sourcefileparam = "sourcefile=".$TCE::Config::ITEMS.$item_id.'/'.$TCE::Config::DATA_STORAGE{'goobi'};
		my $tmpfile = $TCE::Config::ITEMS.$item_id.'/temp.xml';
		my $xslt_errors = $TCE::Config::ITEMS.$item_id.'/xsltstderr';
		
		# problems with running system() from a CGI script on a Windows machine
		unlink ($TCE::Config::ITEMS.$item_id.'/runsaxon.bat') if (-e $TCE::Config::ITEMS.$item_id.'/runsaxon.bat');
		open FILE, ">".$TCE::Config::ITEMS.$item_id.'/runsaxon.bat';
		print FILE '@echo off';
		print FILE "\n";
		print FILE "$TCE::Config::PATH_TO_SAXON -o:$metsfile -xsl:$stylesheet -s:$tmpfile $sourcefileparam 2>$xslt_errors";
		print FILE "\n";
		close FILE;
		
		if (system($TCE::Config::ITEMS.$item_id.'/runsaxon.bat') == 0)
		{
			message("$msg_ok Endgültige METS Datei erfolgreich erstellt");
			copy($metsfile,$TCE::Config::OUTPUT_DIR.$item_id.'.xml');
			message("$msg_ok Datei $item_id.xml in das Ausgabeverzeichnis kopiert");
			
		}
		else
		{
			error("$msg_fail Es ist ein Fehler beim Erstellen der endgültigen METS Datei aufgetreten.");
		}
	}
	
}

#output success/error messages to browser
print $cgi->header( -type=>"text/html" );
$template->process('tce_exportitem.tmpl',{'messages' => \@messages, 'success' => $go, 'itemid' => $item_id }) || die $template->error();	

exit(1);


#
sub error
{
	my $text = shift;
	push @messages, $text;
	$go = 0;
	return undef; 

}

sub message
{
	my $text = shift;
	push @messages, $text;
	return 1;
}

sub read_file
{
  my $filename = shift;
  open FILE, '<'.$filename;
  my @lines = <FILE>;
  close FILE;
  my $object = join('',@lines);
  my $VAR1;
  eval ($object);
  return $VAR1;	
}

sub get_timestamp
{
	my $offset = shift;
	my @t = gmtime(time + $offset);
	return ($t[5] + 1900).'-'.sprintf("%02d",($t[4] + 1)).'-'.sprintf("%02d",$t[3]).'T'.sprintf("%02d",$t[2]).':'.sprintf("%02d",$t[1]).':'.sprintf("%02d",$t[0]).'Z';
}