#!/usr/bin/perl
$^W=1;
use strict;

# vi(1) :se tabstop=4

use File::Basename;
use Date::Calc qw(
		Add_Delta_Days
		Nth_Weekday_of_Month_Year
		Today
	)
;

sub usage{
	die("usage: ",basename($0),": [{+|-}n] {1[st]|first,2[nd]|second,3[rd]|third,[45]th|fourth|fifth,last} {Sundays,Mondays,Tuesdays,Wednesdays,Thursdays,Fridays,Saturdays - or can be truncated as remains unique}\n");
};

# Delta_Days
my $Dd=0;
if( $#ARGV == 2 && $ARGV[0] =~ /^[-+]\d+$/ ){
	$Dd=shift()+0;
}

if($#ARGV!=1){
	&usage;
};

$_=shift();
my $n;
if(/^(?:1(?:st)?|first)$/io){		$n=1;
}elsif(/^(?:2(?:nd)?|second)$/io){	$n=2;
}elsif(/^(?:3(?:rd)?|third)$/io){	$n=3;
}elsif(/^(?:4(?:th)?|fourth)$/io){	$n=4;
}elsif(/^(?:5(?:th)?|fifth)$/io){	$n=5;
}elsif(/^last$/io){		$n='l';
}else{
	&usage;
};

# Must be in same order as used by Date::Calc:Nth_Weekday_of_Month_Year:
my @days_of_week=qw(
	Monday
	Tuesday
	Wednesday
	Thursday
	Friday
	Saturday
	Sunday
);
my @dow_lc_strings=();
for(@days_of_week){
	push(@dow_lc_strings,lc($_) . 's');
};
# How many leading characters must we match to uniquely match?
my @dowcm=();
for(@dow_lc_strings){
	my $min=1;
	while(1){
		my $matches=0;
		for my $s (@dow_lc_strings){
			++$matches if substr($_,0,$min) eq substr($s,0,$min);
		}
		if($matches == 1){
			# $min is sufficient for unique
			push(@dowcm,$min);
			last;
		}elsif($matches >=2){
			# $min is not sufficient for unique
			++$min;
			next;
		}else{
			# should be unreachable
			die(basename($0),": internal error, aborting");
		}
	}
};

sub my_dow(){
	$#_ == 0 or die(basename($0),": internal error on &my_dow(), aborting");
	my $t = lc($_[0]);
	for(0..$#dow_lc_strings){
		return($_+1) if
			substr($t,0,$dowcm[$_])
			eq
			substr($dow_lc_strings[$_],0,$dowcm[$_])
	}
	&usage;
};

my $dow=&my_dow(shift);

my ($year,$month,$day) = Add_Delta_Days(Today(), $Dd);

if($n ne 'l'){
	my $day2=(Nth_Weekday_of_Month_Year($year,$month,$dow,$n))[2];
	printf(
			"%04d-%02d-%02d\n",
			($year,$month,$day2)
		) if defined($day2) && $day2 >= $day;
	undef $day2;

	while(1){
		++$month;
		if($month>12){
			exit(0) if ++$year > 9999;
			$month=1;
		};
		$day=(Nth_Weekday_of_Month_Year($year,$month,$dow,$n))[2];
		printf("%04d-%02d-%02d\n",$year,$month,$day) if defined($day);
	};
}else{
	my $day2=(Nth_Weekday_of_Month_Year($year,$month,$dow,5))[2];
	$day2=(Nth_Weekday_of_Month_Year($year,$month,$dow,4))[2]
		if !defined($day2);
	printf(
			"%04d-%02d-%02d\n",
			($year,$month,$day2)
		) if $day2 >= $day;
	undef $day2;

	while(1){
		++$month;
		if($month>12){
			exit(0) if ++$year > 9999;
			$month=1;
		};
		$day=(Nth_Weekday_of_Month_Year($year,$month,$dow,5))[2];
		$day=(Nth_Weekday_of_Month_Year($year,$month,$dow,4))[2]
			if !defined($day);
		printf("%04d-%02d-%02d\n",$year,$month,$day);
	};
};
