module Calendar (cal,month,cc) where

import Zeller

-- カレンダーのプログラム

intToString :: Int -> String --カレンダーの日付けを2桁の文字列にする
intToString n = [" 123"!!a, ['0'..'9']!!b] where (a, b) = divMod n 10

intsToString :: [Int] -> Int -> String  --1行(7日分)を文字列にする
intsToString ns ld = concatMap d ns     --concatMapはmapしてappend
        where d x |x <= 0 || x > ld = "   "
                  |otherwise = intToString x ++ " "

monthnames :: [String]              -- 見出しに使う月の名前
monthnames =["January","February","March","April","May","June","July",
             "August","September","October","November","December"]

month :: Int -> String          --21文字に展開した月の名前
month m = expand (monthnames !! (m - 1))

expand :: String -> String      --文字列sの両側に空白を置き21文字に展開する
expand s = let leng = length s  --文字列s自身の長さ
               padlen = (20 - leng) `div` 2         --片側の空白の文字数
             in take 21 (replicate padlen ' ' ++ s ++ repeat ' ')

cal :: Int -> Int -> IO ()      --y年m月のカレンダーを出力
cal y m = do putStrLn head      --見出し(月 年)を出力
             putStrLn (unlines (cc y m))
               where head = expand ((monthnames !! (m - 1)) ++ " " ++ year)
                     year = show y          --西暦年yを文字列に変換

daynames :: String
daynames = " S  M Tu  W Th  F  S "
leap :: Int -> Int              --yがうるう年なら1, 平年なら0を返す
leap y = dif 4 - dif 100 + dif 400
   where dif d = div y d - div y1 d; y1 = y - 1
cc :: Int -> Int -> [String]    --y年m月のカレンダーの文字列を構成
cc y m = let z = 1 - zeller y m 1
             ld = [31,28+leap y,31,30,31,30,31,31,30,31,30,31]!!(m-1)
     in daynames : map (\x-> intsToString x ld) [[d..d+6]|d<-[z,z+7..z+35]]

-- 使い方 cal 2006 1

