#!/usr/bin/perl -w

# tcm2kcal.pl -- converts a Turner Classic Movies (TCM) calendar
#                web page into a KDE calendar file.
############################################################################
# SPDX-FileCopyrightText: 2003-2004 Allen Winter <winter@kde.org>          #
# SPDX-License-Identifier: GPL-2.0-or-later                                #
############################################################################
#
# This script is used to help test konsolekalendar.
#
# Modify $konkal, $cal, and $TCM as necessary for your needs.
#
# Requirements:
#   lynx
#   konsolekalendar (from KDE).
#   Date-Calc perl module (from CPAN).
#
# Options: -d, delete entries from KDE calendar file
#          -c, change entries in KDE calendar by re-writing movie titles in all caps.
#          -m <month>, where month is an integer 1 thru 12
#                      default is current month
#          -y <year>, where year is an integer YYYY
#                     default is current year
#          -f <file>, where file is location of output KDE calendar
#                     default is $HOME/.kde/share/apps/korganizer/tcm.ics
#	   -w <konsolekalendar> where konsolekalendar is located

use strict;
use Env qw(HOME);
use Getopt::Std;
use Date::Calc qw(Today Month_to_Text
  Add_Delta_DHMS Add_Delta_Days
  Day_of_Week Day_of_Week_to_Text
  Month_to_Text);

#location of konsolekalendar program
my ($konkal) = "/usr/bin/konsolekalendar";

#location of new TCM KDE calendar
my ($cal) = "$HOME/.kde/share/apps/korganizer/tcm.ics";

#default program execution mode
my ($mode) = "--add";

#current date information
my ($year, $month, $d) = Today();

#parse command line
&parse();

my ($mmonth) = Month_to_Text($month);

#location of TCM monthly calendar web page
my ($TCM) = "https://www.tcm.com/Schedule/Print/0,,$month-$year|0|,00.html";
print "Processing $TCM ...\n";

if (open(GET, "lynx -dump -nolist -connect_timeout=3 '$TCM'|")) {
} else {
  die "Failed to get the TCM calendar page.\n";
}

if ($mode eq "--add") {
  if (!-r $cal) {
    if (system("$konkal --create --file $cal")) {
      print "Failure Condition Encountered.  Unable to Create KDE Calendar.\n";
      exit 1;
    }
  }
}

my ($tday, $mday);
my ($day)      = 1;
my ($lastampm) = "AM";
my ($line)     = "";
my ($event)    = "";
my ($num)      = 0;
while ($line = <GET>) {

  #prepare line
  chomp($line);
  $line = &rmleadwhite($line);

  #skip junk lines
  next if (!$line);
  next if ($line =~ m/^\[/);
  next if ($line =~ m/^All Times Eastern/);
  next if ($line =~ m/^$mmonth[[:space:]]*$year/);

  #start new day if line begins with a DD Sunday|Monday|...|Friday|Saturday
  ($tday, $mday) = split(" ", $line);
  if ($tday =~ m/^[0-9]*$/) {
    if ($tday >= 1 && $tday <= 31) {
      if ($mday =~ m/day$/) {
        &process() if ($event);

        #        print "New day starting: $tday $mday\n";
        $day   = $tday;
        $event = "";
        next;
      }
    }
  }

  #start a new event if line begins with a HH:MM[[space]]AM|PM
  if ($line =~ m/^[0-9]*:[0-9][0-9][[:space:]]*[A,P]M/) {
    &process() if ($event);
    $event = "$line";
  } else {
    $event = $event . " " . $line;
  }
}

#process remaining event, if there is one.
&process() if ($event);

close(GET);
print "$num movies processed\n";

##### END MAIN #####

sub rmleadwhite()
{
  #remove leading white space
  my ($x) = @_;
  ($x) =~ s+^[[:space:]]*++;
  return ($x);
}

sub parse()
{
  #parse command line

  our ($opt_h, $opt_d, $opt_c, $opt_m, $opt_y, $opt_f, $opt_w);
  getopts('hdcm:y:f:w:');

  $mode   = "--delete" if ($opt_d);
  $mode   = "--change" if ($opt_c);
  $month  = $opt_m     if ($opt_m);
  $year   = $opt_y     if ($opt_y);
  $cal    = $opt_f     if ($opt_f);
  $konkal = $opt_w     if ($opt_w);

  #  if( $opt_h ) {
  #   print "help here!\r\n";
  #  } // if

}

sub process()
{
  #remove any evil double quotes from the event string
  $event =~ s/\"//g;

  ### Compute starting date
  my ($date) = sprintf("%4d-%02d-%02d", $year, $month, $day);

  ### Compute starting time
  my ($ttime, $ampm) = split(" ", $event);
  my ($hour,  $min)  = split(":", $ttime);

  # adjust the hour by am or pm
  $hour += 12 if ($ampm =~ m/[Pp][Mm]/ && $hour < 12);
  $hour -= 12 if ($ampm =~ m/[Aa][Mm]/ && $hour == 12);

  my ($time) = sprintf("%02d:%02d", $hour, $min);

  # advance day (for the enddate) if we have moved from pm to am
  if ($lastampm =~ m/[Pp][Mm]/ && $ampm =~ m/[Aa][Mm]/) {
    ($year, $month, $day) = Add_Delta_Days($year, $month, $day, 1);
  }

  # format start date and time for "greping" later
  my ($gdate) = sprintf(
    "\"%s %02d %s %4d\"",
    Day_of_Week_to_Text(Day_of_Week($year, $month, $day)),
    $day, Month_to_Text($month), $year
  );
  my ($ghour) = $hour;
  if ($ghour == 12) {
    $ampm = "pm";
  }
  if ($ghour > 12) {
    $ghour -= 12;
    $ampm = "pm";
  }
  if ($ghour == 0) {
    $ghour = 12;
    $ampm  = "am";
  }
  my ($gtime) = sprintf("\"%02d:%02d %s\"", $ghour, $min, lc($ampm));

  ### Compute Movie End Datetime by adding Movie Duration to Start Datetime

  # derive duration
  my ($duration) = $event;
  $duration =~ s/CC//g;
  $duration =~ s/LBX//g;
  $duration =~ s/DVS//g;
  my (@d) = reverse(split(" ", $duration));
  $duration = $d[0];
  $duration =~ s/m\.$//g;

  #print "DURATION COMPUTATION ERROR\n" if( $duration < 1 || $duration > 300);

  my ($endyear, $endmonth, $endday, $endhh, $endmm, $endss) =
    Add_Delta_DHMS($year, $month, $day, $hour, $min, 0, 0, 0, $duration, 0);

  # format end datetime
  my ($enddate)  = sprintf("%4d-%02d-%02d", $endyear, $endmonth, $endday);
  my ($endtime)  = sprintf("%02d:%02d",     $endhh,   $endmm);
  my ($genddate) = sprintf(
    "\"%s %02d %s %4d\"",
    Day_of_Week_to_Text(Day_of_Week($endyear, $endmonth, $endday)),
    $endday, Month_to_Text($endmonth), $endyear
  );
  $ampm = "am";
  if ($endhh == 12) {
    $ampm = "pm";
  }
  if ($endhh > 12) {
    $endhh -= 12;
    $ampm = "pm";
  }
  if ($endhh == 0) {
    $endhh = 12;
    $ampm  = "am";
  }
  my ($gendtime) = sprintf("\"%02d:%02d %s\"", $endhh, $endmm, lc($ampm));

  # Derive Movie Title
  my ($tmp) = split("[)]", $event);
  my ($tmp2, $title) = split("^[0-9]*:[0-9][0-9][[:space:]]*[A,P]M", $tmp);
  $title = &rmleadwhite($title);
  $title = $title . ")";
  if ($title =~ m/\([[:space:]]\)/) {
    print "SKIPPING MOVIE WITHOUT A TITLE\n";
    return;
  }

  my ($gtitle) = "\"" . $title . "\"";

  # "Grep line".
  #  Due to events across multiple days, search for ending date/time only.
  #  my($UID)=&find_uid("$gdate,$gtime,$genddate,$gendtime,$gtitle");
  my ($UID) = &find_uid(",$genddate,$gendtime,$gtitle");

  # New Title for Change Mode
  $title = uc($title) if ($mode eq "--change");

#  print "EVENT start datetime=$date, $time, title=$title, end datetime=$enddate, $endtime, duration=$duration\n";
  $lastampm = $ampm;

  # Run konsolekalendar to insert/change/delete the event
  if (
    system(
"$konkal $mode $UID --file $cal --date $date --time $time --end-date $enddate --end-time $endtime --summary \"$title\" --description \"$event\""
    )
    )
  {
    $mode =~ s/--//;
    print "Failure Condition Encountered.  Unable to $mode Event.\n";
    exit 1;
  }

  $num++;
}

sub find_uid()
{

  my ($line);
  my ($grepline) = shift;
  my ($UID)      = "";

  if ($mode ne "--add") {
    if (open(VIEW, "$konkal --view --all --export-type csv --file $cal |")) {
      while ($line = <VIEW>) {
        if (index($line, $grepline) >= 0) {
          my (@u) = reverse(split(",", $line));
          chomp($u[0]);
          $UID = "--uid=$u[0]";
          last;
        }
      }
      if ($UID eq "") {
        print "Failure Condition Encountered.  Unable to locate Event $grepline in calendar.\n";
        exit 1;
      }
    } else {
      die "Failed to view cal $cal.\n";
    }
    close(VIEW);
  }
  return ($UID);
}

__END__
