#!/usr/bin/perl -w
#
# TV listings toy
#
use lib qw( /Users/waider/src/perl );
use lib qw( /sw/lib/perl5 );
use DBI;
use File::Path;
use CGI;
use CGI::Carp qw( fatalsToBrowser );
use Date::Parse;
use POSIX;
use Digest::MD5;
use XMLTV;
use Data::Dumper;
use URI::Escape;
use WaiderDotIe qw( getconfig do_cookie_dance get_user_data put_user_data );

use lib qw( /Users/waider/src/perl/Movies/lib );
use Hydra::Movie::CNDB;

use strict;

my $generator = "/usr/bin/tv_grab_ie.pl";
if ( ! -x $generator ) {
    $generator = "/sw/bin/tv_grab_ie.pl";
}

my $conf = getconfig();
$conf->{cachedir} = "/var/cache/xmltv"; # hey, why not?

my ( $host, $port, $database, $dbuser, $dbpass ) =
  ( $conf->{host}, $conf->{port}, $conf->{database}, $conf->{dbuser},
    $conf->{dbpass} );
my $dbh = DBI->connect( "DBI:mysql:database=$database;host=$host;port=$port",
                        $dbuser, $dbpass ) or die $DBI::errstr;

my ( $content, $query );
my ( $cndb, $moviesonly, $nowonly, $progressive ) = ( 0, 1, 0, 0 );
my @movies;
my ( $min, $hour, $mday, $month, $year );
my $id;
my %chanlist;
my @chanlist;
my $changed = 0;

my $debug = $ENV{'DEBUG'};
$| = 1;

my $profile;

# Get date info
my $runtime = time;
my $expires = 0;
( undef, $min, $hour, $mday, $month, $year, undef ) = localtime( $runtime );
$month++;
$year = $year + 1900;

# rollover is at 5am
if ( $hour < 5 ) {
    my $date = $runtime;
    $date -= 60 * 60 * 24;
    ( undef, $min, $hour, $mday, $month, $year, undef ) = localtime( $date );
    $month++;
    $year = $year + 1900;
}

if ( $ENV{'REMOTE_ADDR' }) {
    $query = new CGI;
    $id = do_cookie_dance( $query );
    $profile = get_user_data( $dbh, $id );
    $debug = $query->param( 'debug' );

    eval {
        %chanlist = %{$profile->{'films.pl_chanlist'}};
        map { push @chanlist, $_ if $chanlist{$_} eq "new" } keys %chanlist;
    };
    if ( defined( $profile->{'films.pl_chanarray'})) {
        @chanlist = @{$profile->{'films.pl_chanarray'}};
    }

    if ( defined( $query->param( 'date' ))) {
        my $date = $query->param( 'date' );
        ( $year, $month, $mday ) = $date =~ /^(\d{4})(\d{2})(\d{2})$/;
    }
    $cndb = $query->param( 'cndb' ) || 0;
    $moviesonly = $query->param( 'moviesonly' ) || 1;
    $nowonly = $query->param( "nowonly" ) || 0;
    $progressive = $query->param( "progressive" ) || 0;
} else {
    # pull ID from command line if possible
    $id = shift;
    $cndb = $ENV{CNDB};
    $moviesonly = $ENV{MOVIESONLY};
}

if ( !defined( $year ) or !defined( $mday ) or !defined( $month )) {
    die "can't make sense of the date";
}

# Check for an XML file
my $xmlfile = sprintf( "%s/%02d%02d%02d.xml", $conf->{cachedir}, $mday, $month,
                       $year );
my $ref;

if ( -s $xmlfile ) {
    eval {
        $ref = XMLTV::parsefile( $xmlfile );
        $content = "Yay"; # keep later code happy
    };
} else {
    # We don't have a cache file that fits exactly. Let's get one.
    print STDERR "No $xmlfile found, fetching one\n" if $debug;

    # a bit clunky
    my $generate = `PERL5LIB=/sw/lib/perl5 $generator --date '$year/$month/$mday' 2>/var/tmp/tv_grab.log > $xmlfile`;
    print STDERR "generator said: $generate\n" if $debug and $generate;
    if ( ! -s $xmlfile ) {
        $generate ||= 'No XML produced';
        my $error = "";
        if ( open( my $ERR, "</var/tmp/tv_grab.log" )) {
            $error = join( "\n", <$ERR> );
        }
        my ( $exit, $signal, $core ) =
            ( $? >> 8, $? & 127, $? & 128 );
        die "Failed to create $xmlfile\n" .
            "$generator returned $exit (sig $signal, core $core)\n\n" .
            "$generate\n\n$error";
    }
    eval {
        $ref = XMLTV::parsefile( $xmlfile );
        $content = "Yay"; # also
    };
    # we'll assume success
    unlink( "/var/tmp/tv_grab.log" );
}

# if we failed to parse the cache/generated file, trash it. It may be
# corrupted.
if ( !defined( $ref )) {
    unlink( $xmlfile );
}

my ( $encoding, $credits, $ch, $progs ) = @{$ref};
my $langs = [ 'en' ];

# check for new channels
for my $channel ( keys %{$ch} ) {
    my ( $logchannel, $lang ) =
      @{XMLTV::best_name( $langs, $ch->{$channel}->{'display-name'})};
    if ( !defined( $logchannel )) {
        warn "no display-name for " . Dumper( $ch->{$channel} );
        next;
    }

    if ( !defined( $chanlist{$logchannel})) {
        $chanlist{$logchannel} = "new";
        push @chanlist, $logchannel;
        $changed = 1;
    }
}

# convert the programme data into something usable by the legacy code
for my $programme ( @{$progs}) {
    my %movie;
    ( $movie{channel} ) =
      @{XMLTV::best_name( $langs,
                          $ch->{$programme->{channel}}->{'display-name'} )};
    if ( !defined( $movie{channel} )) {
        die "your code is fuxored...\n" . Dumper( $programme );
    }

    if ( $chanlist{$movie{channel}} eq "hide" ) {
        next;
    }

    ( $movie{description} ) =
      @{XMLTV::best_name( $langs, $programme->{desc} )};
    ( $movie{title} ) =
      @{XMLTV::best_name( $langs, $programme->{title} )};
    $movie{start} = substr( $programme->{start}, 8, 2 ) . ":" .
      substr( $programme->{start}, 10, 2 );
    my $unixtime = $programme->{start};
    $unixtime =~ s@^(....)(..)(..)(..)(..)(..)@$1/$2/$3 $4:$5@;
    $unixtime = str2time( $unixtime );

    $movie{unixtime} = $unixtime;
    $movie{stop} = $programme->{stop};
    if ( defined( $movie{stop})) {
        my $unixtime = $movie{stop};
        $unixtime =~ s@^(....)(..)(..)(..)(..)(..)@$1/$2/$3 $4:$5@;
        $movie{stop} = str2time( $unixtime );
    }
    $movie{film} = 0;
    $movie{year} = 0;

    if ( $movie{description} =~ /^\((\d{4})(, (.+?))?\)\s*(.*)$/s ) {
        $movie{year} = $1;
        $movie{genre} = $3;
        $movie{film} = 1;
        $movie{description} = $4;
    } elsif ( $programme->{date} ) { # XXX
        $movie{year} = substr( $programme->{date}, 0, 4 );
        $movie{film} = 1;
    }

    if ( !$expires and $unixtime > $runtime ) {
        $expires = $unixtime;
    }

    push @movies, \%movie;
}
print STDERR "Expires: " . scalar( localtime( $expires )) . "\n" if $debug;

# Output Section
if ( $ENV{'REMOTE_ADDR' }) {
    # back/forward one day
    my $today = str2time( sprintf( "%02d-%02d-%04d", $month, $mday, $year ));
    my $prev = $today - ( 60 * 60 * 24 );
    my $next = $today + ( 60 * 60 * 24 );
    my $url = "/cgi-bin/films.pl?";
    $url .= "cndb=1&" if $cndb;
    $url .= "moviesonly=" . $moviesonly . "&";

    $next = $url . "date=" . strftime( "%Y%m%d", localtime( $next ));
    $prev = $url . "date=" . strftime( "%Y%m%d", localtime( $prev ));

    $expires ||= $runtime; # wrong wrong wrong
    my $cookie = $query->cookie( -name => 'rssid',
                                 -value => $id,
                                 -path => '/',
                                 -expires => '+1y' );

    print $query->header( -expires => "+" . ( $expires - $runtime ) . "s",
                          -cookie => $cookie,
                          -Cache_Control => "max-age=" .
                          ( $expires - $runtime ));
    # the doctype probably isn't strictly correct, but it's a nice idea
    print <<"EOH";
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <link rel="stylesheet" href="../../waider.css" type="text/css">
    <link rel="Next" href="$next">
    <link rel="Prev" href="$prev">
    <title>Movies for $mday/$month/$year</title>
    <script>
var fadetimer;
var outtimer;
var transid;

function lightup( e ) {
    var trans = document.getElementById( 'trans' );

    if ( trans.style.display == 'none' || e.target != transid ) {
      var top = e.pageY;
      var left = e.pageX;

      trans.innerHTML = "";
      if ( e.target.id.indexOf( 'title' ) == 0 ) {
        var name = e.target.id;
        name = name.replace( /^title/, "id" );
        var cont = document.getElementById( name );
        if ( cont ) {
          trans.innerHTML = cont.innerHTML;
        }
      }

      trans.style.display = 'block';

      top = top - ( trans.offsetHeight / 2 );
      left = left - ( trans.offsetWidth / 2 );

      trans.style.top = '' + top + 'px';
      trans.style.left = '' + left + 'px';

      //trans.addEventListener( "mouseover", lightup, false );
      trans.addEventListener( "mouseout", lightdown, false );
      transid = e.target;
    }

    if ( fadetimer ) {
      clearTimeout( fadetimer );
      fadetimer = null;
    }

    if ( outtimer ) {
      clearTimeout( outtimer );
      fadetimer = null;
    }

    trans.style.background = "green";
    trans.style.opacity = 0.7;
}

function lightdownreal() {
    var trans = document.getElementById( 'trans' );
    var i = trans.style.opacity;

    if ( i <= 0 ) {
      trans.style.display = 'none';
      transid = null;
    } else {
      i = i - 0.1;
      trans.style.opacity = i;
      fadetimer = setTimeout( "lightdownreal()", 100 );
    }
}

function lightdown( e ) {
    var trans = document.getElementById( 'trans' );
    trans.style.background = "yellow";
    outtimer = setTimeout( "lightdownreal()", 1000 );
}

    function movieshow( item, action )
    {
      var el = document.getElementById( item );
      if ( action == 1 ) {
        el.style.display = "";
//        el.style.zIndex = 1;
        el.style.backgroundColor = "#ffffff";
        el.style.color = "#000000";
        el.style.width = "200px";
        el.style.marginWidth = "5px";
        el.style.border = "thin solid red";
      } else {
        el.style.display = "none";
      }
    }

    function shownow()
    {
      var time = new Date();
      var temp = time.getHours();
      var nowel = null;

      if ( time.getHours() < 10 ) {
         temp = "0" + temp;
      }
      temp = temp + ":";
      if ( time.getMinutes() < 10 ) {
         temp = temp + "0";
      }
      temp = temp + time.getMinutes();

      nowel = document.getElementById( "t" + temp  );
      if ( nowel ) {
         window.scroll( nowel.offsetLeft, 0);
      }

      setTimeout( "shownow()", 60000 );
    }
    </script>
  </head>
  <body onload="shownow()">
EOH
    if ( !defined( $content )) {
        print <<"EOT";
    <p>Looks like we drew a blank on $mday/$month/$year\n</p>
    <p>Proxy Settings:<br>http_proxy=$ENV{http_proxy}<br>\nno_proxy=$ENV{no_proxy}</p>
  </body>
</html>
EOT
        exit;
    }

    my $prog = $url . "progressive=1";
    my $profile = "";
    print <<"EOH";
<div id="trans" style="z-index: 1; background-color: green; opacity: 0.5; position: absolute; top: 0; left: 0; display: none">TOP</div>
<p><a href="$prev">Previous</a> | <a href="$next">Next</a> | <a href="#now">Now</a> | <a href="#next">Next</a> | <a href="$prog">Full</a> | <a href="/cgi-bin/options.pl">Change User</a></p>
$profile
EOH

}

my $next = "";
my $now = "";
if ( defined( $query) and $progressive ) {
    if ( $progressive == 2 ) {
        my %channels;
        my %times;
        # date-sort the movies
        @movies = sort { $a->{unixtime} <=> $b->{unixtime}} @movies;

        map {
            my @s;
            if ( defined( $channels{$_->{channel}} )) {
                @s = @{$channels{$_->{channel}}};
            }
            if (( $_->{stop}||$_->{unixtime} ) >= $runtime ) {
                if ( $_->{unixtime} < $runtime ) {
                    $_->{unixtime} = $runtime;
                }
                push @s, $_;
                $channels{$_->{channel}} = \@s;
                $times{$_->{unixtime}} = 1;
            }
        } @movies;

        print "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" style=\"z-index: 2\">\n";
        print "<tr><td class='tvchan'>";
        print "Showtime";
        print "</td>";
        for my $time ( sort keys %times ) {
            print "<td class='tvtime' id='t" . strftime( "%H:%M", localtime( $time )) . "'>";
            if ( $time == $runtime ) {
                print "NOW";
            } else {
                print strftime( "%H:%M", localtime( $time ));
            }
            print "</td>";
        }
        print "</tr>\n";
        my $idx = 0;
        for my $channel ( @chanlist ) {
            print "<tr><td class='tvchan'>";
            print $channel;
            print "</td>";

            my @times = sort keys %times;
            for my $time ( @times ) {
                next if !defined( $channels{$channel});
                my @shows = @{$channels{$channel}};
                my $filler = "";
                my $cols = 1;
                my $style = "";
                while ( !defined( $shows[0])) {
                    shift @shows;
                }

                if ( $time eq $times[0] and $shows[0]->{unixtime} != $time ) {
                    $filler = "<nobr>" .
                      strftime( "%H:%M: ", localtime( $time ));
                    $filler .= "no show until ";
                    $filler .=
                      strftime( "%H:%M",
                                localtime( $shows[0]->{unixtime} ));
                    $filler .= "</nobr>";
                    for my $t ( @times ) {
                        last if $shows[0]->{unixtime} == $t;
                        $cols++;
                    }
                    $cols--;
                } else {
                    for my $s ( @shows ) {
                        $s->{stop} = $times[-1] unless $s->{stop};
                        next if $s->{stop} < $time;
                        next if $s->{unixtime} > $time;
                        if ( $s->{unixtime} == $time ) {
                            $filler = "<div id=\"title$idx\" onclick=\"movieshow('id$idx',1)\">";
                            $filler .= "<nobr>";
                            $filler .= $s->{title};
                            if ( $s->{film}) {
                                $style = " style=\"background-color: blue\"";
                            }
                            $filler .= "</nobr></div>";

#                            $filler .=<<"EOF";
#<script>var item = document.getElementById( 'title$idx' ); item.addEventListener( "mouseover", lightup, false );</script>
#EOF

                            $filler .= "<div style=\"text-align: justify; display: none\" id=\"id$idx\" onclick=\"movieshow('id$idx',0)\" z-index: \"1\">";
                            $filler .= $s->{channel} . "<br>\n";
                            $filler .= $s->{start};
                            $filler .= " - " . strftime( "%H:%M", localtime( $s->{stop}))
                              if defined( $s->{stop});
                            $filler .= "<br>\n";
                            $filler .= $s->{title} . "<br>\n";
                            $filler .= ( $s->{description} || "no info");
                            $filler .= "</div>";

                            # how many cols does it span?
                            if (defined( $s->{stop})) {
                                for my $t ( sort keys %times ) {
                                    if ( $t >= $s->{stop} ) {
                                        last;
                                    }
                                    if ( $t > $s->{unixtime }) {
                                        $cols++;
                                    }
                                }
                            }
                        }
                    }
                }
                if ( $filler ) {
                    print "<td colspan=\"$cols\"$style>";
                    print "$filler";
                    print "</td>";
                }
                $idx++;
            }
            print "</tr>\n";
        }
        print "</table>\n";
    } else {
        my @starts;
        my $oldchannel = "";
        # date-sort the movies
        @movies = sort { $a->{unixtime} <=> $b->{unixtime}} @movies;
        my $basetime = $movies[0]->{unixtime};
        if ( $nowonly ) {
            $basetime = $runtime;
        }
        push @starts, [ $runtime, "now", $runtime ];
        my $x = 20;
        my $y = 0;
        my $idx = 0;
        for my $channel ( @chanlist ) {
            next if $channel eq $oldchannel; # dedupe
            $oldchannel = $channel;
            $x += 20;

            print "<div style=\"position: absolute; top: ${x}px\">";
            print "$channel";
          MOVIE:
            for my $midx ( 0..$#movies ) {
                my $m = $movies[$midx];
                next MOVIE unless $m->{channel} eq $channel;
                $y = $m->{unixtime} - $basetime;
                if ( $y < 0 ) {
                    if ( defined( $m->{stop})) {
                        $y = $m->{stop} - $basetime;
                        if ( $y > 0 ) {
                            $y = 0;
                        } else {
                            next MOVIE;
                        }
                    }
                }
                $y /= 5;
                $y += 150;

                # not working yet - width
                my $w = "";
                if ( defined( $m->{stop})) {
                    $w = $m->{stop} - $m->{unixtime};
                    $w /= 5;
                    $w = " width: $ {w}px";
                }

                print "<div style=\"position: absolute; top: 0px; left: $ {y}px\" onclick=\"movieshow('id$idx',1)\">";
                print $m->{title};
                print "</div>";
                print "<div style=\"text-align: justify; position: absolute; top: 0px; left: $ {y}px; display: none\" id=\"id$idx\" onclick=\"movieshow('id$idx',0)\">";
                print $m->{channel} . "<br>\n";
                print $m->{start};
                print " - " . strftime( "%H:%M", localtime( $m->{stop}))
                  if defined( $m->{stop});
                print "<br>\n";
                print $m->{title} . "<br>\n";
                print ( $m->{description} || "no info");
                print "</div>";
                $idx++;
                push @starts, [ $m->{unixtime}, $m->{start}, $m->{stop}||$m->{unixtime} ];
            }
            print "</div>\n";
        }

        # Print time markers
        for my $t ( @starts ) {
            $y = $t->[0] - $basetime;
            next if $y < 0;
        $y /= 5;
            $y += 150;
            print "<div style=\"position: absolute; top 0px; left: $ {y}px\">";
            print $t->[1];
            print "</div>";
        }
    }
} else {
    print "<dl>\n" if defined( $query );
    for my $movie ( sort { $a->{unixtime} <=> $b->{unixtime}} @movies ) {
        next if ( !$movie->{film} and $moviesonly );

        my $searchurl = uri_escape( $movie->{title} .
                                    ( $movie->{year}? " (" . $movie->{year} . ")" : "")) . '"';

        my $bgcolor = "";
        if ( $runtime >= $movie->{unixtime} and
             $runtime <= ( $movie->{stop}||$movie->{unixtime})) {
            $bgcolor = "class=\"tvnow\"" unless $nowonly;
            $searchurl .= "\" name=\"now\"" unless $now;
            $now = $movie->{title} unless $now;
        } else {
            next if $nowonly;
        }

        if ( defined( $query )) {
            print "<dt $bgcolor>";
        }

        # Mark what's up next.
        if ( !$next && $movie->{unixtime} >= $runtime ) {
            if ( defined( $query )) {
                $searchurl .= "\" name=\"next\"";
            } else {
                print "NEXT >>>";
            }
            $next = $movie;
        }

        if ( defined( $query ) && $movie->{film} ) {
            print "<a href=\"http://www.imdb.com/Tsearch?title=$searchurl>";
        } else {
            if ( defined( $query ) && $searchurl =~ /name="(now|next)"/) {
                print "<a name=\"$1\"></a>";
            }
        }

        print $movie->{title};
        if ( $movie->{film}) {
            print " (" . ($movie->{year}||"????") . "):"
        } else {
            print ":";
        }
        print "</a>" if $query && $movie->{film};
        print " " . $movie->{channel} . ", " . $movie->{start};
        print strftime( " - %H:%M", localtime( $movie->{stop} )) if $movie->{stop};

        if ( $query ) {
            my $beg = $movie->{unixtime};
            my $stop = $movie->{stop};
            my $desc = uri_escape( $movie->{title} . " @ " . $movie->{channel} );
            my $detail = uri_escape( $movie->{description}||"" );

            if ( defined( $beg ) && defined( $stop ) && defined( $desc ) && defined ( $detail )) {
                print <<"CAL";
 <a href="/cgi-bin/vcalify.pl?start=$beg&end=$stop&description=$desc&attach=$detail">[reminder]</a>
CAL
            }
        }

        print "</dt>" if $query;
        print "\n";

        if ( defined( $query )) {
            print "<dd $bgcolor>" . $movie->{'description'};
        }

        # The "too much free time on my hands" section
        if (( $cndb||0 ) && $movie->{film}) {
            my @urls;
            my $urls = Hydra::Movie::CNDB::search( $movie->{title} );
            for my $m ( @{$urls->{exact}} ) {
                if ( defined( $m->{year} ) and
                     abs( $m->{year} - $movie->{year} ) <=1 ) {
                    push @urls, $m;
                } else {
                    # hmm.
                    push @urls, $m if !defined( $m->{year} );
                }
            }

            for my $url ( @urls ) {
                $url->detail();
                # don't bother with no-skin movies that are in CNDB
                next unless $url->{skin};
                my $title = $url->{title};
                print "<p>Skin in <a href=\"" . $url->{cndb} . "\">$title</a>:\n<ul>";
                for my $actor ( keys %{$url->{skin}} ) {
                    print "<li>$actor (";
                    if ( defined( $url->{skin}->{$actor} )) {
                        printf( "%.2f", $url->{skin}->{$actor} );
                    } else {
                        print "unrated";
                    }
                    print ")</li>\n";
                }
                print "</ul>\n";
                print "</p>\n";
            }
        }
        print "</dd>\n" if $query;
    }
    print "</dl>\n" if $query;
}

# trailer
if ( defined( $query )) {
    print "</body>\n";
    print "</html>\n";

    if ( $changed ) {
        #$profile->{'films.pl_chanlist'} = \%chanlist;
        $profile->{'films.pl_chanarray'} = \@chanlist;
        put_user_data( $dbh, $id, $profile );
    }
}
