module analog_clock

import StdEnv, StdIO

:: TimerState :== Time

addSeconds :: Int Time -> Time
addSeconds 1 time=:{hours,minutes,seconds}
| seconds < 59 = {time & seconds=seconds+1}
| minutes < 59 = {time & minutes=minutes+1, seconds=0}
| hours   < 11 = {hours=hours+1, minutes=0, seconds=0}
| otherwise    = {hours=0, minutes=0, seconds=0}
addSeconds n time
| n < 0        = abort "Negative not allowed"
| n == 0       = time
| otherwise    = addSeconds 1 (addSeconds (n-1) time)

Start :: *World -> *World
Start world
# (wid, world) = openId world
# (time, world) = getCurrentTime world
= clock time wid world

clock :: Time Id *World -> *World
clock time wid world = startIO SDI Void (snd o seqList [openWindow Void wdef, openTimer time tdef]) [ProcessClose closeProcess] world
where
    windowEdge = 200
    viewDomain = { corner1 = {x= ~windowEdge/2, y= ~windowEdge/2},
                   corner2 = {x=  windowEdge/2, y=  windowEdge/2} }
    clockRadius = 90

    wdef = Window "Clock" NilLS [ WindowId wid,
                                  WindowInit (noLS (appPIO (appWindowPicture wid (drawClock time)))),
                                  WindowViewSize (rectangleSize viewDomain),
                                  WindowViewDomain viewDomain,
                                  WindowClose (noLS closeProcess) ]

    tdef = Timer ticksPerSecond NilLS [TimerFunction tick]
    where
        tick _ (time, pst)
            # newTime = addSeconds 1 time
            # pst = appPIO (appWindowPicture wid (drawClock newTime o unfill viewDomain)) pst
            = (newTime, pst)

    drawClock :: Time *Picture -> *Picture
    drawClock time=:{hours,minutes,seconds} picture 
    # minutes` = toReal minutes + (toReal seconds / 60.0)
    # hours` = toReal hours + minutes` / 60.0
    = seq ([
        setPenSize 2,
        setPenColour (let scale=225 in RGB {r=scale,g=scale,b=scale}),
        fill {oval_rx=clockRadius, oval_ry=clockRadius},
        setPenColour Black,
        draw {oval_rx=clockRadius, oval_ry=clockRadius}] ++ 
        [drawAt {x=clock_x 0.88 12 h - 5,y=clock_y 0.88 12 h + 5} (toString h) \\ h <- [1..12]] ++ [
        setPenSize 3,
        drawLine zero {x=clock_x h_factor 12 hours`,   y=clock_y h_factor 12 hours`},
        setPenSize 2,
        drawLine zero {x=clock_x m_factor 60 minutes`, y=clock_y m_factor 60 minutes`},
        setPenSize 1,
        setPenColour Red,
        drawLine zero {x=clock_x s_factor 60 seconds,  y=clock_y s_factor 60 seconds}]) picture
    where
        s_factor = 0.75
        m_factor = 0.75
        h_factor = 0.5

        clock_x factor max n = toInt (sin (toReal n / (toReal max) * PI * 2.0) * (toReal clockRadius) * factor)
        clock_y factor max n = 0 - toInt (cos (toReal n / (toReal max) * PI * 2.0) * (toReal clockRadius) * factor)