#!/usr/bin/ruby

# kfdiary.rb
# Copyright (C) 2004 Kaname Funakoshi
# usage
#	% kfdiary.rb 9 2004 | psnup | lpr

require 'date'
require 'getoptlong'

ProgName = "kf-diary"

Day = Array["", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]

# CMYK Colors
Red = "0 1 1 0"
Black = "0 0 0 1"
Blue = "1 1 0 0"

class LogPad
	def initialize
		@frame_width = 0.8
		@line_width = 0.2
		@left_margin = 40
		@bottom_margin = 20 
		@top_margin = 120

		@line_skip = 22
		@head_line_skip = 30

		@hour_separator = 130
		@paper = "A4"
		@nmemo = 6
		@dayhours = 24

		@morning = 5	# hour that the date start

		@two_up = false
		@two_up_stack = true
		@left_page = nil
		@pp = 0
	end

	def setDate (date)
		@date = date
		if (@date == nil)
			return
		end

		if (@two_up == true)
			@left_page = false
			if (@two_up_stack == true)
				if (@date.mday < 16)
					@left_page = true
				end
			else
				if (@date.mday.modulo(2) == 1)
					@left_page = true
				end
			end
		end
	end

	def setMorning (h)
		@morning = h
	end

	def setTwoUp
		@two_up = true
	end

	def setStack
		@two_up_stack = true
	end

	def setNoStack
		@two_up_stack = false
	end

	def ps_manifest
		@hour_offset = @left_margin + 5
		@date_offset = @left_margin + 5
		
		if (@paper =~ /^A4$/)
			@pheight = 842
			@pwidth = 595
		else
			$stderr.print("unrecognized paper size\n")
			exit 1
		end

		@line_skip = 
			(@pheight - @bottom_margin - @top_margin) / (@dayhours + @nmemo + 1.5)
		@head_line_skip = @line_skip * 1.5

		print <<"__MANIFEST__"
%!PS-Adobe-2.0
%%Creator: kf-diary.rb
%%Title: report.ps
%%Pages: (atend)
%%BoundingBox: 0 0 #{@pwidth} #{@pheight}
%%DocumentPaperSizes: #{@paper}
%%Orientation: Portrait
%%EndComments
%

/DateFont
	/Helvetica-Bold findfont 20 scalefont def
/HourFont
	/helvetica-Roman findfont 15 scalefont def
/hline {#{@pwidth - (2 * @left_margin)} 0 rlineto stroke} def
/startpoint {0 exch add moveto} def

/FrameLineWidth #{@frame_width} def
/HourLineWidth #{@line_width} def
/LeftMargin #{@left_margin} def
/HourOffset {#{@hour_offset} 5} def
/DateOffset {#{@date_offset} 5} def
/LineSkip #{@line_skip} def
/DateLineSkip #{@head_line_skip} def
/HourFieldHeight #{@line_skip * @dayhours} def % LineSkip x 24
/HourSeparatorOffset #{@hour_separator} def

__MANIFEST__
	end

	def single_hour (h)
		hour = sprintf("%2d", h)
		print <<"__SINGLE_HOUR__"
% hour #{hour}
HourOffset moveto (#{hour}) show
LeftMargin 0 startpoint
hline
0 LineSkip translate
__SINGLE_HOUR__
	end

	def single_date
		if (@two_up == true)
			if (@left_page == true)
				@pp = @pp + 1
				print <<"__LEFT_PAGE__"
%%Page: #{@pp} #{@pp}
gsave
%504 20 translate
570 -5 translate
90 rotate
.7 .7 scale
__LEFT_PAGE__
			else
				print <<"__RIGHT_PAGE__"
gsave
%504 416 translate
570 386 translate
90 rotate
.7 .7 scale
__RIGHT_PAGE__
			end
		elsif (@date != nil)
			print "%%Page: #{@date.mday} #{@date.mday}\n"
		end

		print <<"__MEMO_FIELD__"
#{Blue} setcmykcolor /Helvetica-Roman findfont 10 scalefont setfont
#{(@pwidth - @left_margin) - 50} 5 moveto (#{ProgName}) show

#{Black} setcmykcolor

FrameLineWidth setlinewidth

% Under-most frame line
0 #{@bottom_margin} translate LeftMargin 0 startpoint hline

% memo field
HourLineWidth setlinewidth
#{@nmemo} {
	LeftMargin 0 startpoint
	hline
	0 LineSkip translate
} repeat

% separator between hours and memo
FrameLineWidth setlinewidth
LeftMargin 0 startpoint hline

HourLineWidth setlinewidth
HourFont setfont

% vertical separator
HourSeparatorOffset 0 startpoint
0 HourFieldHeight rlineto stroke
__MEMO_FIELD__

		(@morning-1).downto(0) do |h|
			single_hour(h)
		end
		
		23.downto(@morning) do |h|
			single_hour(h)
		end

		if (@date != nil)
			if (@date.cwday > 5)
			print "#{Red} setcmykcolor\n"
			end

			print <<"__DATE_FIELD__"
% show date
DateFont setfont
DateOffset moveto (#{@date} (#{Day[@date.cwday]})) show
__DATE_FIELD__

			if (@date.cwday > 5)
				print "#{Black} setcmykcolor\n"
			end
		end

		print <<"__DATE_FINISH__"
FrameLineWidth setlinewidth
LeftMargin 0 startpoint
hline
0 DateLineSkip translate
LeftMargin 0 startpoint
hline
__DATE_FINISH__
		if (@two_up == true)
			if (@left_page == true)
				print("grestore\n")
			else
				print("showpage\ngrestore\n")
			end
		else
			print("showpage\n")
		end
	end
end

# Main
pad = LogPad.new

opts = GetoptLong.new(
	["--help",	"-h",	GetoptLong::NO_ARGUMENT],
	["--start-hour",	"-s",	GetoptLong::REQUIRED_ARGUMENT],
	["--single",	GetoptLong::NO_ARGUMENT],
	["--two-up",	"-2",	GetoptLong::NO_ARGUMENT],
	["--stack",		GetoptLong::NO_ARGUMENT],
	["--no-stack",	GetoptLong::NO_ARGUMENT]
	)

$two_up = false
$two_up_stack = true

opts.each do |opt, arg|
	if (opt =~ /^--help$/) 
		$stderr.printf "usage: %s month year\n", __FILE__
		exit 0
	elsif (opt =~ /^--start-hour$/) 
		str = arg.inspect.delete("\"")
		pad.setMorning(str.to_i)
	elsif (opt =~ /^--single$/)
		pad.setDate(nil)
		pad.ps_manifest
		pad.single_date
		exit 0
	elsif (opt =~ /^--two-up$/)
		pad.setTwoUp
		$two_up = true
	elsif (opt =~ /^--stack$/)
		pad.setStack
		$two_up_stack = true
	elsif (opt =~ /^--no-stack$/)
		pad.setNoStack
		$two_up_stack = false
	end
end

if (ARGV.length != 2)
	today = Date.today
	month = today.month
	year = today.year
else 
	month = ARGV[0].to_i
	year = ARGV[1].to_i
end

if (Date.exist?(year, month, 1) == nil)
	$stderr.printf "Usage: %s month year", __FILE__
	exit 1
end

pad.ps_manifest

if (($two_up == false) or ($two_up_stack == false))
	1.upto(31) do |i|
		if (Date.exist?(year,month,i) != nil)
			d = Date.new(year,month,i)
			pad.setDate(d)
			pad.single_date
		else
			break
		end
	end
else
	1.upto(15) do |i|
		d = Date.new(year, month, i)
		pad.setDate(d)
		pad.single_date

		if (Date.exist?(year, month, 15 + i))
			d = Date.new(year, month, 15+i)
			pad.setDate(d)
			pad.single_date
		else
			break
		end
	end
	if (Date.exist?(year, month, 31))
		d = Date.new(year, month, 31)
		pad.setDate(d)
		pad.single_date
	end
end


