#!/usr/bin/perl

use strict;

use utf8;

use POSIX qw( strftime );
use CGI qw/:standard -nosticky/;
use ColorTime;
#use Schedule::Class qw( get_list get_dow get_next load_schedule );

use DateTime;
use DateTime::Calendar::Discordian;

#use Date::Discordian;

#use Palm::PDB;
#use Palm::Datebook;
#use Palm::StdAppInfo;

#use Time::Repeat;
use Time::ParseDate;

use PhysStat2::DBI;


####################### defines ############################

my $total = 60 * 60 * 24;
my $colorbar_width = 10;
my $timebar_width = 5;
my $rss_max = 15;

# files
my $physstat_config = "/home/httpd/xavier/.physstatrc";
my $palmdb   = "/home/steve/.shared/DatebookDB.pdb";
my $schedule = "/home/geekhaus/schedules/steve.xml";
my $username = "Steve";
my $usermail = "steve\@staticfree.info";
my $creator  = "Steve Pomeroy ($usermail)";
my $cclic    = "http://creativecommons.org/licenses/by-nc/2.0/";
my ($version) = '$Revision: 1.10 $' =~ /Revision:\s*(.+?)\s*\$/;
############################################################


my $istoday = 1;
my $now = time;

my $type = param('type');

$type = 'html' unless defined $type;

if( param('time') ne '' && param('time') <= $now ){
  $istoday = 0;
  $now = param('time') if param('time');
}

if( defined param('date') ){
    my $foo = parsedate( param('date') );
    unless($foo == 0){
	$now = $foo;
	$istoday = 0;
    }
}

#load_schedule( $schedule, date => $now );

my $url = url();

# mod-perl persistance of objects
our $physstat;
unless( defined $physstat ){
  my $config = load_physstat_config( $physstat_config );

  $physstat = new PhysStat2::DBI( %$config );
}



close LOG;

if( $type eq "html" ){
    gen_html( $physstat, $now, $istoday );
}elsif( $type eq "rss" ){
    gen_rss( $physstat, $now, $istoday );
}elsif( $type eq "menow" ){
    gen_menow( $physstat, $now, $istoday );
}

exit 0;

######################################################################
##################### private subs ###################################
######################################################################

sub gen_menow{
    my ( $physstat, $now, $istoday ) = @_;

    print "content-type:application/rdf+xml;charset=utf-8\n\n";

    print<<MENOW;

<foaf:MeNowDocument rdf:about="">
   <foaf:maker rdf:resource="foaf"/>
   <foaf:primaryTopic rdf:nodeID="p1"/>
   <!-- MeNow properties -->
</foaf:MeNowDocument>

MENOW

}

sub gen_rss{

    my ( $physstat, $now, $istoday ) = @_;

    my @events = $physstat->get_last_n_events($rss_max);

    my $items = "<items>\n<rdf:Seq>\n";
    foreach my $event ( @events ){
	$items .= "<rdf:li rdf:resource=\"$url?time=".$event->date."\" />\n";
    }
    $items .= "</rdf:Seq>\n</items>\n";

    print "Content-Type: application/xml;charset=utf-8\n\n";

#<!DOCTYPE rdf:RDF [
#<!ENTITY % HTMLlat1 PUBLIC
# "-//W3C//ENTITIES Latin 1 for XHTML//EN"
# "http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent">
#\%HTMLlat1;
#]>

    print<<RSSHEAD;
<?xml version='1.0' encoding='utf-8'?>
<rdf:RDF 
  xmlns="http://purl.org/rss/1.0/"
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:admin="http://webns.net/mvcb/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:cc="http://web.resource.org/cc/"
>

  <channel rdf:about="$url">
    <title>PhysStat for $username</title>
    <link>$url</link>
    <description>Physical Status updates for $username</description>
    <dc:language>en</dc:language>
    <dc:creator>$creator</dc:creator>
    <dc:rights>Copyright $creator</dc:rights>
    <admin:generatorAgent rdf:resource="http://staticfree.info/perlsrc/physstat.pl?ver=$version" />
    <admin:errorReportsTo rdf:resource="mailto:$usermail"/>
    <cc:license rdf:resource="$cclic" />

$items

  </channel>

RSSHEAD


    foreach my $event ( @events ){
	my $status = $event->status;
	my $itemurl = "$url?time=".$event->date;
	my $itemtime = scalar localtime $event->date;
	my $itemfulldate = strftime("%Y-%m-%dT%H:%M%z", localtime $event->date );
	$itemfulldate =~ s/(..)$/:$1/;
	my $itembody = "$username changed status to ".
	    $status.": \"".$event->description."\"";

	my $itembodyescaped = escape_xml( $itembody );

	print<<EOS;
  <item rdf:about="$itemurl">
    <title>PhysStat update: $username is $status</title>
    <link>$itemurl</link>
    <description>$itembodyescaped</description>
    <dc:creator>$creator</dc:creator>
    <dc:date>$itemfulldate</dc:date>
    <content:encoded><![CDATA[$itembody]]></content:encoded>
  </item>

EOS

    }

    print<<RSSFOOT;
</rdf:RDF>
RSSFOOT

}

sub gen_html{
    my ( $physstat, $now, $istoday ) = @_;
    my $tcolor = ColorTime::colorClock(time);


    my $stoday = startOfDay($now);
    my $etoday = endOfDay($now);
    my $pday   = $stoday - 1;
    my $nday   = endOfDay($etoday + 1);

    my $when;

    #my $disc_time = DateTime::Calendar::Discordian->from_object(object => DateTime->now());
    my $disctime = "";#$disc_time->strftime("%A, %B %d, %Y%N(%H)");#discordian($now);

    my $time = strftime("%a %b %d, %Y", localtime $now);
    if( $istoday ){
	$when = "so far today, $time";
    }else{
	$when = "on $time";
    }

    # only shift the color bar left if the timebar is displayed
    my $colorbar_leftpx = ($colorbar_width + 
			   ($istoday ? $timebar_width: 0 ))."px";
    my $timebar_widthpx = $timebar_width."px";
    my $colorbar_widthpx = $colorbar_width."px";

    # all this style information is for rendering-specific stuff.
    # any look-specific stuff should be included in the physlog.css
    my $style=<<EOS;
    html{
      margin: 1em;
    }

    body{
      margin: 0;
    }
body{
width: 80%;
height: 90%;
margin: 1em;
text-align: center;
}
h1, h2{
text-align: center;
}

h1{
margin: 0 1em;
}


h2{
font-size: inherit;
}

#physstat_nav{
position: fixed;
right: 0;
margin: 1em;
width: 18%;
text-align: center;
}


#physstat_nav input[type="text"]{
max-width: 95%;
}
    .grid {
	    height: 80%;
            width: 60%;
            position: absolute;
            margin: 1em;
            margin-left: 30px;
            background-color: #000;
          }

ol{
margin: 0;
padding: 0;
height: 100%;
width: 100%;
position: absolute;
}

.gradient, .time, .block{
border-top: 1px solid black;
border-bottom: 1px solid black;
}

    .gradient{
               height: 100%;
               width: $colorbar_widthpx;
               left: -$colorbar_leftpx;
               position: absolute;
	       margin: 0;
	       padding: 0;
            }
    .time    { background-color: \#$tcolor;
	       width: $timebar_widthpx;
               height: 100%;
	       position: absolute;
	       left: -$timebar_widthpx;
            }

    .block   { position: absolute;
  	       width: 100%;
	       z-index: 1;
               margin: 0;
               text-align: center;
               list-style: none;
               width: 100%;
            }
    .block:hover, .block *:hover { z-index: 2; 
				   font-size: larger; 
                                   width: 102%; 
                                   left: -1%;}


    .away    { background-color: #9f0000; color: #fcc;}

    .here    { background-color: #008F40; color: #afa;}
    .asleep  { background-color: #000080; color: #ddf;}
    .afk     { background-color: #006040; color: #afa;}
EOS


    my $content_type = 'application/xhtml+xml';
    $content_type = "text/html" 
	if $ENV{HTTP_USER_AGENT} =~ /MSIE/ or $ENV{HTTP_USER_AGENT} =~ /Lynx/;



    print header( -type=> $content_type, 
		  -charset => "utf-8");
	       print start_html( -lang => 'en_US',
				 -encoding => 'utf-8', 
		  -head  => [Link({ -rel => 'alternate',
			      -type => 'application/rss+xml',
			      -title => 'RSS',
			      -href => "$url?type=rss" }),
			     # these show up in some browsers
			     Link({ -rel => 'Previous',
				    -title => "Previous day",
				    -href => "$url?time=$pday" }),
			     # hide the next rel link when it's showing today
			     ( $istoday ? () : 
			       Link({ -rel => 'Next',
				    -title => "Next day",
				    -href => "$url?time=$nday" })),
			     "<style type='text/css'>\n$style</style>"],
		  -title => "My life $when",
		  -style => { -src => ['/style.css'] } );


print h1("My life $when");
#  print h2("($disctime)");

# navigation bar
print div({-id=>"physstat_nav", -class=>"section"},
	  h4( {-class=>"title"}, "Navigation"),
	  div({-class=>"secbody"},
	      start_form(-action => $url, -method => "get"),
		   p(
		     textfield('date'),
		     submit("Go to date"),
		    ),
	      end_form,
	     p(
	       ( $pday > 0 ? a({-href=>"$url?time=$pday"}, "&#8592;") : "" ),
	       a({-href=>"$url"}, "Today"),
	       ( $istoday ? "" : a({-href=>"$url?time=$nday"}, "&#8594;" ) ),

	      ),
	      p( a( {-class=>"xmlbutton", -href=>"$url?type=rss"}, "RSS 1.0" ),
		 ),
	     ),
	 );

if( $now < 0 ){
  print h2("Please specify a positive value for the date"), end_html;
  exit;
}

print "<p>\n";
my @events = ();
#@events    = load_palm( $stoday, $etoday );
#@events    = (@events, load_class( $stoday, $etoday ));

draw_untimed( @events );

print "</p>\n";


print "<div class='grid'>\n";
print img({-class=>"gradient", src=>'/gradient_s.png',  alt=>""});
print div({-class=>"time"}) if $istoday;

print <<EOF;
<ol>

EOF


    my @physstat_events = $physstat->get_events_from_range($stoday, $etoday);

    # Add on the last event from the previous day, as we store events
    # by their start date.
    my($prevday) = $physstat->get_last_n_events( 1, $stoday );
    unshift @physstat_events, $prevday if $prevday;

    #   print blank space before the day if no info is present
    printcell( $stoday, $etoday,
	       $physstat_events[0]->date, $stoday, "", "", \@events )
    unless $prevday;


    if (@physstat_events) {
      # print all the physstat events
      for ( my $i = 0; $i < (@physstat_events - 1); $i++ ) {
	printcell( $stoday, $etoday,
		   $physstat_events[$i+1]->date, $physstat_events[$i]->date,
		   $physstat_events[$i]->status,
		   $physstat_events[$i]->description, \@events);
      }
    } else {

      printcell( $stoday, $etoday, $etoday, $stoday, "",
		 "<em>No data available for this day</em>", \@events );
    }

      my $lasttime = $now;
      $lasttime = $etoday unless $istoday;
      # print the last element along with the closing blank space
      printcell( $stoday, $etoday,
		 $lasttime, $physstat_events[@physstat_events-1]->date,
		 $physstat_events[@physstat_events-1]->status,
		 $physstat_events[@physstat_events-1]->description,\@events);

      # finish up with a blank cell if it's today
#      printcell( $stoday, $etoday, $etoday, $now, "", "",\@events) if $istoday;


print <<EOF;
</ol>
</div>
</body>
</html>

EOF


}

sub ftime {
   my ($time) = @_;
   my $out = "";
#   $time /= 1000;
   $out .= sprintf "%dd ", $time/60/60/24 if int( $time/60/60/24) > 0; 
   $out .= sprintf "%d:%02d:%-2.2d", $time/60/60 % 24, $time/60 % 60, $time % 60;
   return $out;

}

=head1 printcell($stoday,$etoday,$ctime,$time,$mode,$message,$events)

$ctime - end time
$time  - start time

=cut
sub printcell {

    my ( $sday, $eday, $ctime, $time, $mode, $mesg, $events ) = @_;

    # make all prior events start at the start of the day
    $time = $sday if $time < $sday;

    my $diff  = $ctime - $time;

    my $height = sprintf( '%0.02f', ($diff / $total ) * 100 );

    return if $height < 0;

    # round up or add units
    if( $height < 2 ){
	$height = "1.2em";
    }else{
	$height = $height."%";
    }

    my $sec_of_start = $time - $sday;
    my $sec_of_end = $ctime - $sday;
    my $min_of_end = int ($sec_of_end/60);

    my $top = sprintf ( '%0.02f', ($sec_of_start / $total) * 100 );
    my $title =  ftime( $sec_of_start ) . " - " . ftime( $sec_of_end );
    my $style= "top: ".$top."%; height: $height";

    my $mode_class = ( $mode ? $mode : "pending" );

    print <<EOL;
    <li class="block $mode_class" title="$title" style="$style">
EOL
    
    print escape_xml($mesg);

    print '('.ftime( $diff ).')' if $diff > 0;

    my $min_start = int($sec_of_start / 60);
    my @evts = ();
    @evts = grep{ $min_start <= $_->{'start_mins'} && $min_of_end >= $_->{'end_mins'} } @{$events};

    print "    <br />\n" if @evts;

    draw_table( @evts );

print <<EOL;
    </li>
EOL

}

sub startOfDay {

  my ($time) = @_;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
      localtime($time);

  return $time - $hour * 60 * 60 - $min * 60 - $sec;

}

sub endOfDay {

  my ($time) = @_;

  return startOfDay($time) + 60 * 60 * 24 - 1;

}

sub draw_table{
  my( @events ) = @_;

  @events = grep{ $_->{'start_mins'} != 0 } @events;  
  @events = sort{ $a->{'start_mins'} <=> $b->{'start_mins'} } @events;

  my $last_mins = 0;
  my $width     = 1;
  foreach my $event( @events ){
  print ftime($event->{'start_mins'}*60);
  print "-".ftime($event->{'end_mins'}*60);
  print " - ";
  print "$event->{description}<br />\n";
    if( $event->{'start_mins'} <= $last_mins ){
      foreach my $check_evt ( @events ){
        
      }
      $last_mins = $event->{'end_mins'};
    }
  }
}

sub draw_untimed{
  my( @events ) = @_;

  @events = grep{ $_->{'start_mins'} == 0 } @events;

  foreach my $event( @events ){
    if( $event->{note} =~ /^(?:href|url|link):\s*(.+)\s*/im ){
      print "<a href=\"$1\">$event->{description}</a><br />\n";
    }else{
      print "$event->{description}<br />\n";
    }
  }
}

# sub load_palm{

#   my ( $start, $end ) = @_;

#   my $pdb = new Palm::Datebook;
#   $pdb->Load( $palmdb );
#   my @events = ();  

#   foreach my $record (@{$pdb->{records}}){

#     pdbToRepeat( $record );
#     foreach my $repeat (getRepeat( $record, $start, $end )){

#       my %event = ();
#       unless( $record->{description} =~ /^\-/ ){
#         if($record->{start_hour} != 0xff){
#           $event{'start_mins'} = $record->{start_hour}*60 + $record->{start_minute};
#           $event{'end_mins'} = $record->{end_hour}*60 + $record->{end_minute};
#         }
#         $event{description} = $record->{description};
#         $event{note}        = $record->{note};
#         push @events, \%event;
#       }
#     }
#   }
#   return @events;
# }

# sub load_class{
#   my ( $start, $end ) = @_;
#   my @events;
#   foreach my $class (get_list( $start, $end, "" )){
#     my %event = ();
#     @{$class}[0] =~ /(\d+)\:(\d+)\-(\d+)\:(\d+)/;
#     $event{'start_mins'} = $1 * 60 + $2;
#     $event{'end_mins'} = $3 * 60 + $4;
#     $event{'description'} = "@{$class}[1] @{$class}[2]";
# #    print "@{$class}[0]\t@{$class}[1]\t@{$class}[2]\<br\>\n";
#     push @events, \%event;
#   }
#   return @events;
# }

sub escape_xml{
    my ($x) = @_;

    $x =~ s/\&/&amp;/g;
    $x =~ s/\>/&gt;/g;
    $x =~ s/\</&lt;/g;

    return $x;
}

sub load_physstat_config{
    my( $config ) = @_;

    my( $file ) = glob( $config );
    if( !$file || ! -e $file ){
        die "unable to load config file: $config: $!\n";
    }

    open CFG, "<$file" or die "Cannot load config file $file: $!\n";

    my $cfg_text = join "", <CFG>;

    our( $config ); 
    eval $cfg_text;

    close CFG;

    return $config;
}
