#! /usr/bin/perl
# nws-diary -- fetch weather forecast for inclusion in Emacs diary

# Copyright (c) 2003 Christopher League <league@contrapunctus.net>
# $Id: nws-diary,v 1.6 2006/05/01 17:22:28 league Exp $

# This is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2, or (at your option) any later
# version.
#
# This is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Emacs; see the file COPYING.  If not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
# MA 02111-1307, USA.

## Usage:

# This script interprets "zone" weather forecasts as produced by the
# National Weather Service <http://www.nws.noaa.gov/>.  Unfortunately,
# that means it is likely useful only to residents of the United
# States.

# The script should be run roughly once per day, ideally as a cron
# job.  It will fetch the latest weather forecast for your area, and
# format the report for inclusion in the next 6 or so days of your
# Emacs diary.

# First, look over all the settings below and modify as necessary.
# Then add a line like this to your Emacs diary-file:

#include ~/.nws-diary

# The default setting for diary-file in Emacs is "~/diary".  The
# filename containing the weather forecast can be configured below
# too. The inclusion feature works only with the fancy diary display,
# and you must set the following hooks in your .emacs file:

#   (add-hook 'diary-display-hook 'fancy-diary-display)
#   (add-hook 'list-diary-entries-hook 'sort-diary-entries)
#   (add-hook 'list-diary-entries-hook 'include-other-diary-files)
#   (add-hook 'mark-diary-entries-hook 'mark-included-diary-files)

## Settings:

# Nation-wide forecasts are all available on one server, but you will
# need to determine your zone code.  The best way to do this is to
# start at <http://www.nws.noaa.gov/> and enter your City, State or
# Zip code.  The resulting page should have your zone code in the URL.
# Usually it is of the form SSZNNN, where SS is the state code, Z is
# Z, and NNN is a 3-digit number.  Replace the state code and zone
# code in the following URL:
my $nws_url = "ftp://weather.noaa.gov/data/forecasts/zone/ny/nyz072.txt";

# Each time this script runs, it will overwrite the following file
# with the latest daily weather forecast data.  Unfortunately, you 
# cannot use ~ here.
my $nws_diary_file = "$ENV{HOME}/v/diary-nws";

# Date format string should be "%D" (equivalent to "%m/%d/%y") for
# US-style dates.  If you have european-calendar-style set, use
# "%d/%m/%y" instead.
my $date_format_string = "%d/%m/%y";

# How should we fetch from the FTP site?  This command takes the URL
# and sends the file contents to standard output.
my $get_cmd = "wget -q -O- $nws_url |";

# This script wraps the text of the weather report.  Usually this works
# well, but sometimes emacs wants to do its own word wrapping.  If you
# see strange line breaks and other word wrapping errors, set this to 1
# Otherwise, leave it as 0.
my $let_emacs_word_wrap = 1;

# Some emacs setups have trouble with the % sign.  Set this to 1 if
# you get "Not enough arguments for format string" error messages 
# when you try to view diary entries with dates containing percent
# signs.
my $replace_percent_sign = 1;

## Change log:

## Code:
use strict;
use Getopt::Long;
use Text::Wrap;
use POSIX qw(strftime);

my $sec_per_day = 60 * 60 * 24;
my $time = time() - $sec_per_day;
my $first = 1;
my $date;
my $text;

open(DATA, $get_cmd)
     or die "cannot retrieve: $!";

open(DIARY, ">$nws_diary_file")
    or die "cannot open $nws_diary_file: $!";

sub next_day 
{
    &format_text unless $first;
    $first = 0;
    $time += $sec_per_day;
    $date = strftime $date_format_string, localtime($time);
    $text = "";
}

sub format_text
{
    # delete 'a' and 'the'
    $text =~ s/\bA\b//g;
    $text =~ s/\bTHE\b//g;
    # abbreviate 'and' and 'percent'
    $text =~ s/\bAND\b/&/g;
    $text =~ s/\b\s+PERCENT\b/%/g;
    # squash contiguous whitespace
    $text =~ s/\s+/ /g;
    # two spaces after period
    $text =~ s/\. /\.  /g;
    # lowercase whole thing
    $text = lc $text;
    # capitalize first words
    $text = ucfirst $text;
    $text =~ s/\.  ([a-z])/\.  \u$1/g;
    # prepend date
    $text = "&" . $date . " Weather: " . $text;
    # remove %
    $replace_percent_sign and $text =~ s/\%/ percent/g;

    if ($let_emacs_word_wrap) {
      print DIARY $text, "\n\n";
    } else {
      # word-wrap
      print DIARY wrap('', '  ', $text) . "\n\n";
    }
}


while(<DATA>) {
    if (m!^\.(.+)NIGHT\.\.\.(.+)$!i) {
        &next_day if $first;
        $text .= "Night: $2 ";
    }
    elsif (m!^\.(.+)DAY\.\.\.(.+)$!) {
        &next_day;
        $text .= "$2 ";
    }
    else {
        chop;
        $text .= "$_ " unless $first;
    }
}

close(DIARY);
close(DATA);

# EOF
