#!/usr/bin/perl
#
# tvm2vdr.pl
#
# Converts epg-data from different sources to VDR
#
# The TCP SVDRSend and Receive functions have been used from the
# vdradmind for VDR.
#
# This software is released under the GNU GPL
#
# See the README file for copyright information and how to reach the author.
#

# todo:
# - errorhandling

use IO::Socket;
use Getopt::Std;
use Date::Manip;
&Date_Init("Language=German","DateFormat=non-US");

push (@INC, "./");
require ("config.pl");
require ("channels.pl");
require ("channels_wanted.pl");

push (@INC, "./inc");
require ("helperfunc.pl");

#---------------------------------------------------------------------------
# main

my $Usage = qq{
Usage: $0 [options]

Options: -d hostname           destination hostname (default: localhost)
         -p port               SVDRP port number (default: 2001)
         -v                    Show verbose messages
         -n                    no VDR present,write EPG direct
         -s	               Simulation Mode
         -h	               Show this help text
};

our ($sim,$verbose,$novdr) = 0;
die $Usage if (!getopts('d:p:t:x:c:b:vhsn') || $opt_h);

our $verbose = 1 if $opt_v;
our $sim = 1 if $opt_s;
$novdr = 1 if $opt_n;

our $Dest = $opt_d  || "localhost";
our $Port = $opt_p  || 2001;
$Timeout = $opt_t || 300; # max. seconds to wait for response

$heute   = UnixDate("heute", "%Y%m%d");
$gestern = UnixDate("gestern", "%Y%m%d");

if ($cleanupoldfiles) {
	print "cleanup old files ..\n";
	cleanup();
}

require ("tvmoviefetch.pl");
require ("hoerzufetch.pl");
require ("tvinfofetch.pl");
require ("infosatfetch.pl");

if (! -w $imagepath && $writeimages) {
  die "cannot write to $imagepath!\n";
  }

if (! -w $downloadprefix) {
  die "cannot write to $downloadprefix!\n";
  }

if (! -w $updateprefix) {
  die "cannot write to $updateprefix!\n";
  }

if ($writeimages) {
  eval 'use Image::Magick';
  our $ckimage = Image::Magick->new;
  }


$SIG{'INT'}  = \&SIGhandler;


print "reading channels ..\n";
our $SVDRP = SVDRP->new($Dest,$Port,$verbose,$sim) unless $novdr;
my @channels = ReadChannels($channelsfile);
my @EPG;# = ReadEPG($epgfile);
our $EXIT = false;
our %XML;

foreach $sender (keys(%chan_wanted)) {
	if ($chan_wanted{$sender} eq "1") {
	        singlesvdrp("mesg getting EPG from TV Movie ..") unless $novdr;
		ReadExternalEPG_tvmovie();
		last;
	}
}

foreach $sender (keys(%chan_wanted)) {
	if ($chan_wanted{$sender} eq "2") {
	        singlesvdrp("mesg getting EPG from TV Info ..") unless $novdr;
		ReadExternalEPG_tvinfo();
		last;
	}
}

foreach $sender (keys(%chan_wanted)) {
	if ($chan_wanted{$sender} eq "3") {
	        singlesvdrp("mesg getting EPG from Hoerzu ..") unless $novdr;
		ReadExternalEPG_hoerzu(); 
		last;
	}
}

foreach $sender (keys(%chan_wanted)) {
	if ($chan_wanted{$sender} eq "4") {
	        singlesvdrp("mesg getting EPG from Infosat ..") unless $novdr;
		ReadExternalEPG_infosat();
		last;
	}
}

if ($clearEPG eq 1 && ! $novdr) {
	print "clearing EPG\n";
	my($result) = singlesvdrp("clre");
	die "Fehler beim Löschen der EPG-Daten: $result" if ($sim == 0 && !$result =~ /EPG data cleared/);
}

if ($novdr) {
  open(EPGFILE," >$epgfile") || die "cannot write epgfile $epgfile : $!";
  }


# EPG & XML-Infos sind beide sortiert im Speicher - jetzt vergleichen.
my $chancounter = 0;
my $chancounts=0;
foreach $sender (keys(%chan)) {
	next if $chan_wanted{$sender} == "0";
	$chancounts++;
	}
	
my $SVDRP = SVDRP->new($Dest,$Port,$verbose,$sim);  
foreach $sender (keys(%chan)) {
	next if $chan_wanted{$sender} == "0";
	
	$epgcount = $#{$EPG{$sender}};      # Anzahl EPG-Einträge für diesen Sender
	$xmlcount = $#{$XML{$sender}};      # Anzahl XML-Einträge für diesen Sender

	# EPG-Sendername suchen
	my $found=0;
	for my $channel (@channels) {
		if ($channel->{epg_id} eq $chan{$sender}[0]) {
			$sendername = $channel->{name};
			$found=1;
			print "EPG-Info for $sender:  $#{$EPG{$sender}} / $#{$XML{$sender}}\n";
			last;
		}
	}

	if ($found eq 0) {
		print "\n\n!!!WARNING!!! $sender configured for fetching EPG,\n";
		print "but ".$chan{$sender}[0]." not found in channels.conf!\n";
		print "Please use contrib/printchannels.pl to sync channels.pl!!\n\n";
	}

  	
	
	$i=0;
	unless ($novdr) {
	  $chancounter++;
	  $SVDRP->SendCMD("MESG writing EPG for $sendername ($chancounter "."/ $chancounts)") if $chancounter % 10 eq 0;
          my($result) = $SVDRP->SendCMD("PUTE");
          die "Fehler beim Vorbereiten der EPG-Daten" if ($sim == 0 && !$result =~ /Enter EPG data/);
          }
        WriteEPG("C $chan{$sender}[0] $sendername");
        doexit() if $please_exit;
          
	for ($i=0; $i<=$xmlcount ;$i++) {
		doexit() if $please_exit;
		$found_orig_event = 0;
		if ($i <= $epgcount) { # mit bestehenden Daten abgleichen
			$eline = "@{$EPG{$sender}}[$i]->{event_id} @{$EPG{$sender}}[$i]->{start} @{$EPG{$sender}}[$i]->{duration} 0";
			$tline = "@{$EPG{$sender}}[$i]->{title}";
			$sline = "@{$EPG{$sender}}[$i]->{subtitle}";
			$dline = "@{$EPG{$sender}}[$i]->{summary}";

			for ($j=0; $j<=$xmlcount ;$j++) {
				doexit() if $please_exit;
				if (   (abs(@{$EPG{$sender}}[$i]->{start}    -  @{$XML{$sender}}[$j]->{start})    < 600)
					&& (abs(@{$EPG{$sender}}[$i]->{duration} -  @{$XML{$sender}}[$j]->{duration}) < 600)
					&& (similarity(@{$EPG{$sender}}[$i]->{title},@{$XML{$sender}}[$j]->{title}) >= 0.4)) { 
					$found_orig_event = 1;
					$dline = "@{$XML{$sender}}[$j]->{summary}" if (length(@{$XML{$sender}}[$j]->{summary}) > length($dline));
					last;
				}
			}
		}

		if ($epgcount < $i && $i <= $xmlcount && @{$XML{$sender}}[$i]->{state} > 0) {
			$eline = "@{$XML{$sender}}[$i]->{event_id} @{$XML{$sender}}[$i]->{start} @{$XML{$sender}}[$i]->{duration} 0";
			$tline = "@{$XML{$sender}}[$i]->{title}";
			$sline = "@{$XML{$sender}}[$i]->{subtitle}";
			$dline = "@{$XML{$sender}}[$i]->{summary}";
		}


		WriteEPG("E $eline"); 
		WriteEPG("T $tline");
		WriteEPG("S $sline") if ($sline ne "");
		WriteEPG("D $dline") if ($dline ne "");
		WriteEPG("e");
	}
	WriteEPG("c");
	unless($novdr) {
	  my($result) = $SVDRP->SendCMD(".");
	  die "Fehler bei der Verarbeitung der EPG-Daten:$result" if ($sim == 0 && !$result =~ /EPG data processed/);
	  }
}

if ($novdr) {
  close EPGFILE;
  }


unless($novdr) {
  $SVDRP->SendCMD("mesg EPG imported successfully.");
  my($result) = $SVDRP->SendCMD("QUIT");
  die "Fehler beim Beenden der Verbindung:$result" if ($sim == 0 && !$result =~ /vdr closing connection/);
  $SVDRP->close;
  }
exit;





sub WriteEPG {
my $line = pack "U0C*", unpack "C*", shift;
  if ($novdr) {
    use bytes;
    print EPGFILE $line;
    print EPGFILE "\n";
    no bytes;
    } else {
    $SVDRP->command($line);
    }
  }

################################################################################
# read epg.data into memory
################################################################################
sub ReadEPG {
	print "reading current EPG from file into memory\n";
	my $epgfile = shift;
	my $EPGSOCKET;
	open($EPGSOCKET,$epgfile) || die "cannot open $epgfile file: $!";
	my($i, @events);
	my($id, $bc) = (1, 0);
	my (@EPG);
	while(<$EPGSOCKET>) {
		chomp;
		if(/^C ([^ ]+) *(.*)/) {
			my $chanfound="";
			for my $channel (@channels) {
				if ($channel->{epg_id} eq $1) {
					$chanfound = $channel->{rfc2838};
					last;
				}
			}

			next if ($chanfound eq ""); # epg-daten überspringen, wenn dieser Sender nicht in den XML-Daten vorhanden ist.

			$bc++;
			undef(@events);
			my($channel_id, $channel_name) = ($1, $2);
			while(<$EPGSOCKET>) {
				if(/^E (.*) (.*) (.*) (.*)/ || /^E (.*) (.*) (.*)/) {
				my($event_id, $time, $duration, $stream_id) = ($1, $2, $3, $4);
				my($title, $subtitle, $summary);
				while(<$EPGSOCKET>) {
					if(/^T (.*)/) { $title = $1 }
					if(/^S (.*)/) { $subtitle = $1 }
					if(/^D (.*)/) { $summary = $1 }
					if(/^e/) {
						# last if (UnixDate("heute", "%s") > $time + $duration); # ist die Sendung schon vorbei ?
						push(@events, {
							start        => $time,
							stop         => $time + $duration,
							duration     => $duration,
							title        => $title,
							subtitle     => $subtitle,
							summary      => $summary,
							id           => $id,
							event_id     => $event_id,
							stream_id    => $stream_id
						});
						$id++;
						last;
					} # if(/^e/)
				} # while(<$EPGSOCKET>)
				} elsif(/^c/) {
					my($last) = 0;
					my(@temp);
					for(sort({ $a->{start} <=> $b->{start} } @events)) {
						next if($last == $_->{start});
						push(@temp, $_);
						$last = $_->{start};
					}
					$EPG{$chanfound} = [ @temp ]; 
					last;
				} # elsif(/^c/)
			} # while(<$EPGSOCKET>)
		} # if(/^C ([^ ]+) *(.*)/)
	} # while(<$EPGSOCKET>) 
	close $EPGSOCKET;
	return (@EPG);
} # sub

sub Error
{
  print STDERR "Fehler: @_\n";
  close(SOCK);
  exit 0;
}


