#!/usr/bin/perl -w

use strict;
use Time::localtime;


my $version = "1.3 TEST";
if ($#ARGV > -1) {
  help();
  exit 1;
}

# Idee: Mailverschicken, Doku und Lockfile auslagern. Kann per ShellScript
#       usw. geschehen! :-)

# Ziel: siehe test1.txt (unten)
#       (alle Termine und Geburtstage usw. sortiert hintereinander)
#
# Strategie: Alle Ausgabezeilen in ein Array schreiben und sortieren:
#
# 2 Array: 1. Array: Alle Ausgabezeilen
#          2. Array: x=Zeile von Array 1, y = Datums-Differenz
#
#      sortiere 2.Array nach Datums.Differenz, dann entsprechend mit x die
#      Ausgabezeilen auslesen. (in foreach... sort keys...)

# 1.1.2000 Fehler korrigiert: Monatl. Termine am Monatsanfang wurden nicht
#                             angezeigt, wenn man am Ende des Vormonats ist.

# ----------------------------------------------------------------------
# Einrichten der benutzten Dateinamen:
my $os = "LINUX";  # "WIN9X"
my $basedir     = $ENV{HOME};
my $termindaten = "$basedir/.termine";
my $mailtxt     = "$basedir/.termine_mailtxt";
chomp(my $empfaenger  = `whoami`); # EMail-Adresse des Empfaengers per Systemkommando ermitteln
my $lockprefix = "$basedir/.termine_"; # Lockfile zusammenbauen: .termine_ttmmjjjj

if ($os eq "WIN9X") {
  $basedir     = "c:\\";
  $termindaten = "$basedir\\termine.txt";
  $mailtxt     = "$basedir\\temp\\termine_mail.txt";
  #chomp(my $empfaenger  = `whoami`); # EMail-Adresse des Empfaengers per Systemkommando ermitteln
  $lockprefix = "$basedir\\temp\\lockfile_termine_";
}
# ----------------------------------------------------------------------

# ----------------------------------------------------------------------
# Tagesdatum ermitteln:
my $nowdate = time();  # Aktuelle Zeit auslesen
my $d_now   =        localtime($nowdate) -> mday;
my $m_now   =    1 + localtime($nowdate) -> mon;
my $y_now   = 1900 + localtime($nowdate) -> year;
my $lockfile = "$lockprefix$y_now$m_now$d_now";
# ----------------------------------------------------------------------

my $ja   = 1;
my $nein = 0;

# Anpassbare Werte fuer die ausgerichtete Ausgabe:
my $einruecken = "    ";
my $normlaenge = 17;


# In dieses Array werden die auszugebenden Texte geschrieben:
my @ausgabearray = ();  my $ausgabecnt = -1;
my %diffhash     = ();  # (ausgabecnt, diff)


# Variablen zur Steuerung des Verhaltens:
my $keinmodus    = 0; my $termine      = 1; my $woechentlich = 2;
my $monatlich    = 3; my $feiertage    = 4; my $geburtstage  = 5;
my $modus = $keinmodus;

# Weitere Variablen:
my $zeile = "";
my %warnliste = ();

# Hashfeld zur Berechnung der Wochentags-Abstaende:
my %revdow = ("Mo" => "1", "Di" => "2", "Mi" => "3", "Do" => "4",
              "Fr" => "5", "Sa" => "6", "So" => "7");


my @Monatsname = ("????", "Januar", "Februar", "Maerz", "April", "Mai", "Juni", "Juli",
                  "August", "September", "Oktober", "November", "Dezember" );

my @Wochentag  = ("??", "Mo", "Di", "Mi", "Do", "Fr", "Sa", "So");

# ------------------------------------------------------------------------
# JulianDate von heute berechnen:
my $jdnow = MyJulianDate($d_now, $m_now, $y_now);
my $downow = day_of_week($jdnow); # 1..7 ??
# ------------------------------------------------------------------------

# Einlesen und Verarbeiten der Termindaten:
open(INPUT, "<$termindaten") || die "Konnte Termindatei $termindaten nicht oeffnen! :-(";

while(<INPUT>) {
  chomp($zeile = $_);
  # Nur Zeilen verarbeiten, die laenger als 0 sind, und nicht mit "#" anfangen:
  if (!( ($zeile =~ /^\#/) || (length($zeile) == 0) )) {
   
    if    ($zeile =~ /^Termine:/)      { $modus = $termine;      WarndatenExtrahieren(); }
    elsif ($zeile =~ /^Woechentlich:/) { $modus = $woechentlich; WarndatenExtrahieren(); }
    elsif ($zeile =~ /^W.chentlich:/)  { $modus = $woechentlich; WarndatenExtrahieren(); }    
    elsif ($zeile =~ /^Monatlich:/)    { $modus = $monatlich;    WarndatenExtrahieren(); }
    elsif ($zeile =~ /^Feiertage:/)    { $modus = $feiertage;    WarndatenExtrahieren(); }
    elsif ($zeile =~ /^Geburtstage:/)  { $modus = $geburtstage;  WarndatenExtrahieren(); }
    else {
     # Termin auslesen und Meldung generieren:
       my $tag = substr($zeile,0,2);
       my $mon = substr($zeile,3,2);
       my $jar = substr($zeile,6,4);
       my $txt = substr($zeile,11);

# --------------------------------------------------------------------------
       if ($modus == $termine) {
       
         if (($tag eq "xx") || ($tag eq "XX") || ($tag eq "??")) { 
           # Termine der Form xx.12.1999 immer ausgeben, wenn Monat und Jahr ok sind :

            if (($mon == $m_now) && ($jar == $y_now)) {
               my $tmp = LFill("Im $Monatsname[$mon]",$normlaenge," ");

               AusgabeHinzu(0, "$tmp: $txt");
               
            }
         }
         else {  # Normalfall: tt.mm.jjjj
         
         
           my $jdthen = MyJulianDate($tag,$mon,$jar);
         
           my $diff = $jdnow - $jdthen;
           if (DiffIstWarnDiff($diff)) {

             my $tmp = LFill(MakeDiffZeitString($diff ) . " (" . WochenTag($jdthen) . ")",$normlaenge," ") . ": $txt";

             AusgabeHinzu($diff, "$tmp");
#             print " Ein Termin: $tag $mon $jar $jdthen $jdnow $diff \n";

           }
           else {
#             print "Kein Termin: $tag $mon $jar $jdthen $jdnow $diff \n";
           }
         }
       }# modus == termine
# --------------------------------------------------------------------------
       
       elsif ($modus == $woechentlich) {
           my $dowthen = $revdow{$tag};
           
           if ($dowthen < $downow) {
               my $danach = $downow - $dowthen;
               my $davor  = -$dowthen - 7 + $downow;

               if (DiffIstWarnDiff($danach)) {
                   my $tmp = LFill(MakeDiffZeitString($danach). " ($tag)",$normlaenge," ") .": $txt";
                   AusgabeHinzu($danach, "$tmp");

               }
               if (DiffIstWarnDiff($davor)) {
                   my $tmp = LFill(MakeDiffZeitString($davor). " ($tag)",$normlaenge," ") .": $txt";
                   AusgabeHinzu($davor, "$tmp");

               }
           }
           elsif ($downow == $dowthen) {
               if (DiffIstWarnDiff(0)) {
                   my $tmp = LFill(MakeDiffZeitString(0). " ($tag)",$normlaenge," ") .": $txt";
                   AusgabeHinzu(0, "$tmp");

               }
           }
           else {
               my $danach = $downow + 7 - $dowthen;
               my $davor  = $downow  - $dowthen;

               if (DiffIstWarnDiff($danach)) {
                   my $tmp = LFill(MakeDiffZeitString($danach). " ($tag)",$normlaenge," ") .": $txt";
                   AusgabeHinzu($danach, "$tmp");

               }
               if (DiffIstWarnDiff($davor)) {
                   my $tmp = LFill(MakeDiffZeitString($davor). " ($tag)",$normlaenge," ") .": $txt";
                   AusgabeHinzu($davor, "$tmp");
               }
           }

       }
# --------------------------------------------------------------------------
# Fehler korrigiert, Monatlicher Termin am Anfang des naechsten Monats!
# 01.01.2000

       elsif ($modus == $monatlich) {
         my $jdthen = MyJulianDate($tag,$m_now,$y_now); # spezielle Basteltag
         my $diff = $jdnow - $jdthen;
         if (DiffIstWarnDiff($diff)) {
           my $tmp = LFill(MakeDiffZeitString($diff). " (" . WochenTag($jdthen). ")",$normlaenge," ") . ": $txt";
           AusgabeHinzu($diff, "$tmp");
         }
         else {
           if ($m_now < 12) { $jdthen = MyJulianDate($tag,$m_now+1,$y_now);   }
           else             { $jdthen = MyJulianDate($tag,$m_now+1,$y_now+1); }
           $diff = $jdnow - $jdthen;
           if (DiffIstWarnDiff($diff)) {
             my $tmp = LFill(MakeDiffZeitString($diff). " (" . WochenTag($jdthen). ")",$normlaenge," ") . ": $txt";
             AusgabeHinzu($diff, "$tmp");
           }
         }
       }
# --------------------------------------------------------------------------

       elsif ($modus == $feiertage) {
         my $jdthen = MyJulianDate($tag,$mon,$jar);
         my $diff = $jdnow - $jdthen;
         if (DiffIstWarnDiff($diff)) {
           my $tmp = LFill(MakeDiffZeitString($diff). " (" . WochenTag($jdthen). ")",$normlaenge," ") . ": FEIERTAG: $txt";
           AusgabeHinzu($diff, "$tmp");
         }
       }
# --------------------------------------------------------------------------
       elsif ($modus == $geburtstage) {
         my $jdthen = MyJulianDate($tag,$mon,$y_now);
         my $diff = $jdnow - $jdthen;
         if (DiffIstWarnDiff($diff)) {
           my $tmp = LFill(MakeDiffZeitString($diff). " (" . WochenTag($jdthen). ")",$normlaenge," ") . ": *$txt";

           # Alter des Geburtstagskindes berechnen:
           my $alter = $y_now - $jar;
           AusgabeHinzu($diff, "$tmp ($alter)");
         }
       }

    }
  } # if no comment
} # while
close(INPUT);

# Ausgaben der Termininfos:
# Sortieren der DIFF-Zeilen mit den Indizes des Ausgabearrays:


# -----------------------------------------------------------------------
# print "Liste der Ausgabezeilen:\n";
# for(my $num=0; $num <= $#ausgabearray; $num++) {
#   print "$num : $ausgabearray[$num]\n";
# }
# -----------------------------------------------------------------------

# -----------------------------------------------------------------------
# print "Liste der Diffzeilen   :\n";
# my $num = 0;
# foreach my $line (sort {$diffhash{$b} <=> $diffhash{$a}} keys %diffhash) {
#   print "$num: $line => ". $diffhash{$line} . "\n";
#   $num++;
# }
# -----------------------------------------------------------------------

# Hier erfolgt die Ausgabe der Ausgabezeilen.
# Mit einem Trick wird dafuer gesorgt, dass z.b. zwischen einem Montags- und
# einem Donnerstags-Termin 2 Leerzeilen erscheinen! :-)

my $altdiff = 0;
my $neudiff = 0;
my $first    = $ja;

#666

if ($ausgabecnt < 0) {
  print "Keine Termine.\n";
}

else {

  print "Termine:\n\n";

  foreach my $line (sort {$diffhash{$b} <=> $diffhash{$a}} keys %diffhash) {

    $neudiff = $diffhash{$line};
    
    if ($first == $ja)            {   $first = $nein;  }
    else {
      while ($altdiff > $neudiff + 1) {
        print "\n"; 
        $altdiff--;
      }
    }
    $altdiff = $neudiff;
    
    print "$ausgabearray[$line]\n";
  }
  print "\n";
}

exit;

# =======================================================================
# =======================================================================
# =======================================================================
# =======================================================================

# --------------------------------------------------------

sub LFill {
  my ($str, $len, $womit) = @_;
  while (length($str) < $len) {
    $str = "$womit$str";
  }
  return $str;
}

# --------------------------------------------------------
# Die folgende Function schreibt, soweit ich das jetzt noch verstehe, ;->
# alle Warn-Differenzen eienr Zeile wie "Termine: [-6 -5 -4 -3 -2 -1 0]"
# in das Array @warnliste.

# Aber warum wird kein Hash verwendet???

sub WarndatenExtrahieren {
  my $pos  = 0;
  my $part = "";
  
  %warnliste = ();
  my ($liste) = ( $zeile =~ /.*\[(.*)\]/ ); # Alles aus [...] -> $liste
  $liste = Trim($liste);
  
  while (length($liste) > 0) {
    $pos = index($liste," ");
    if ($pos != -1) {
      $part  = Trim(substr($liste,0,$pos));
      $liste = Trim(substr($liste,$pos+1));
    }
    else {
      $part  = $liste;
      $liste = "";
    }

    $warnliste{"$part"} = 1;
  } # wend
  
  
#  print "Warnliste = ";
#  foreach my $schnorg (keys %warnliste) {
#    print "$schnorg ";
#  }
#  print"\n";
  
}
# ---------------------------------------------
sub Trim {
  my ($line) = @_;
  if (!defined($line)) { $line = ""; }
  while ( (length($line) > 0) && (substr($line,0,1) eq " ") ) {
    $line = substr($line,1);
  }
  while ( (length($line) > 0) && (substr($line,length($line)-1,1) eq " ") ) {
    $line = substr($line,0,length($line)-2);
  }
  return $line;  
}

# ----------------------------------------------
sub DiffIstWarnDiff {
   my ($mydiff) = @_;
   
   return defined( $warnliste{$mydiff} );
}
# ----------------------------------------------
sub MakeDiffZeitString {
    my ($mydiff) = @_;
    if    ($mydiff == -2) { return "Uebermorgen"; }
    elsif ($mydiff == -1) { return "Morgen"; }
    elsif ($mydiff ==  0) { return "H e u t e"; }
    elsif ($mydiff ==  1) { return "Gestern"; }
    elsif ($mydiff < 0)   { return sprintf("In %d Tagen" , -$mydiff); }
    elsif ($mydiff > 0)   { return sprintf("Vor %d Tagen",  $mydiff); }
}
# ----------------------------------------------
sub MyJulianDate {
  my ($tt,$mm,$jj) = @_;
  my $JD = 0;
  my $J = 0;
  my $M = 0;
  my $G = 0;
  my $a = 0;

  if ($mm < 3) {
    $J = $jj -  1;
    $M = $mm + 12;
  }
  else {
    $J = $jj;
    $M = $mm;
  }

  $a = int($J / 100);
  $G = 2 - $a + int($a/4);

  $JD = int(365.25 * $J) + int(30.6001*($M + 1)) + $tt + 1720995 + $G;
  return $JD;
}
# --------------------------------------------------
sub day_of_week {
  my ($JD) = @_;
  $JD = $JD - 7 * int($JD/7);
  $JD++;
  return $JD;
}
# --------------------------------------------------------
sub WochenTag {
    my ($JD) = @_;
    return $Wochentag[day_of_week($JD)];
}
# --------------------------------------------------
sub help {
  print "\n -+-- TERMIN-ERINNERER $version --+-\n\n";
  print " Autor: Tjabo Kloppenburg <Tjabo.Kloppenburg\@unix-ag.org>\n";
  print " Datum: Januar 2000\n";
  print " Usage: termine [-h|-?]\n\n";
}

# -------------------------------------------------------------------------

sub AusgabeHinzu { my($mdiff, $mtxt) = @_;
  $ausgabecnt++; $ausgabearray[$ausgabecnt] = $mtxt;
  $diffhash{"$ausgabecnt"} = $mdiff;
}
