{-# LANGUAGE NoMonomorphismRestriction, TypeFamilies, FlexibleContexts #-}

module Music.Graphics.Diagrams (
        draw,
        writeGraphic,
        openGraphic
) where

import Music.Score
import Music.Pitch
import Diagrams.Prelude hiding (Time, Duration)
import qualified Diagrams.Backend.SVG as SVG

-- test       
import Music.Prelude.Basic
import Control.Lens
import System.Process
import Text.Blaze.Svg.Renderer.Utf8 (renderSvg)
import qualified Data.ByteString.Lazy as ByteString


timeToDouble :: Time -> Double
timeToDouble = realToFrac . (.-. origin)
durationToDouble :: Duration -> Double
durationToDouble = realToFrac
pitchToDouble :: Music.Pitch.Pitch -> Double
pitchToDouble = realToFrac . semitones . (.-. c)

draw :: (Renderable (Path R2) b, Real a) => Score a -> Diagram b R2
draw = bg whitesmoke . scaleX 20{-TODO-} . mconcat . fmap drawNote . fmap (map1 timeToDouble . map2 durationToDouble . map3 realToFrac) . (^. events)
    where
        map1 f (a,b,c) = (f a,b,c)
        map2 f (a,b,c) = (a,f b,c)
        map3 f (a,b,c) = (a,b,f c)
        drawNote (t,d,x) = translateY x $ translateX (t.+^(d^/2)) $ scaleX d $ noteShape
        noteShape = lcA transparent $ fcA (blue  `withOpacity` 0.5) $ square 1

writeGraphic :: FilePath -> Score Double -> IO ()
writeGraphic path x = do
    let dia = draw x
    let svg = renderDia SVG.SVG (SVG.SVGOptions (Dims 1800 (1800/20)) Nothing) dia
    let bs  = renderSvg svg
    ByteString.writeFile path bs
        
openGraphic :: Score Double -> IO ()
openGraphic x = do
    writeGraphic "test.svg" x
    -- FIXME find best reader
    system "open -a Firefox test.svg"
    return ()

-- drawScores
--     :: (Integral p, p ~ Pitch b, HasPitch b, Voice b ~ NotePart, HasVoice b)
--     => Score b -> Score c -> Diagram SVG R2
-- drawScores notes cmds = notes1D <> notes2D <> cmdsD <> middleLines <> crossLines
--     where
--         notes1 = mfilter (\x -> getPartGroup (getVoice x) == 1) notes
--         notes2 = mfilter (\x -> getPartGroup (getVoice x) == 2) notes
-- 
--         notes1D     = mconcat $ fmap (drawNote 1) $ perform notes1
--         notes2D     = mconcat $ fmap (drawNote 2) $ perform notes2
--         cmdsD       = mconcat $ fmap drawCmd $ perform cmds
--         middleLines = translateX ((/ 2) $ totalDur) (hrule $ totalDur)
--         crossLines  = mconcat $ fmap (\n -> translateX ((totalDur/5) * n) (vrule 100)) $ [0..5]
-- 
--         drawNote n (t,d,x) = translateY (getP x + off n) $ translateX (getT (t.+^(d^/2))) $ scaleX (getD d) $ noteShape n
--         off 1 = 50
--         off 2 = (-50)
--         drawCmd (t,d,x) = translateY 0 $ translateX (getT t) $ cmdShape
-- 
--         noteShape 1 = lcA transparent $ fcA (blue  `withOpacity` 0.3) $ square 1
--         noteShape 2 = lcA transparent $ fcA (green `withOpacity` 0.3) $ square 1
--         cmdShape = lcA (red `withOpacity` 0.3) $ vrule (200)
-- 
--         totalDur = getD $ duration notes
--         getT = fromRational . toRational
--         getD = fromRational . toRational
--         getP = (subtract 60) . fromIntegral . getPitch