packages feed

vision-0.0.2.2: src/Properties/Property.hs

-- -*-haskell-*-
--  Vision (for the Voice): an XMMS2 client.
--
--  Author:  Oleg Belozeorov
--  Created: 2 Mar. 2010
--
--  Copyright (C) 2009-2010 Oleg Belozeorov
--
--  This program is free software; you can redistribute it and/or
--  modify it under the terms of the GNU General Public License as
--  published by the Free Software Foundation; either version 3 of
--  the License, or (at your option) any later version.
--
--  This program is distributed in the hope that it will be useful,
--  but WITHOUT ANY WARRANTY; without even the implied warranty of
--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
--  General Public License for more details.
--

{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}

module Properties.Property
  ( PropertyType (..)
  , Property (..)
  , readValue
  , showValue
  , lookup
  , builtinProperties
  , builtinPropertyMap
  ) where

import Prelude hiding (lookup)

import Control.Applicative
import Control.Monad

import qualified Data.Map as Map

import Text.Printf
import Text.JSON

import qualified XMMS2.Client.Types as X

import Utils


data PropertyType
  = PropertyString
  | PropertyInt
    deriving (Read, Show, Enum)

instance JSON PropertyType where
  showJSON PropertyInt    = showJSON "int"
  showJSON PropertyString = showJSON "string"
  readJSON (JSString s) =
    case fromJSString s of
      "int"    -> return PropertyInt
      "string" -> return PropertyString
      _        -> fail "Unable to read PropertyType"
  readJSON _ = fail "Unable to read PropertyType"


type PropertyShow = X.Property -> String
type PropertyRead = String -> IO X.Property

data Property
  = Property { propName      :: String
             , propKey       :: String
             , propType      :: PropertyType
             , propCustom    :: Bool
             , propReadOnly  :: Bool
             , propReadValue :: Maybe PropertyRead
             , propShowValue :: Maybe PropertyShow }

instance Read Property where
  readsPrec x s = map (mapFst mk) (readsPrec x s)

instance Show Property where
  show p = show (propName p, propKey p, propType p, propReadOnly p)

instance JSON Property where
  showJSON p = showJSON (propName p, propKey p, propType p, propReadOnly p)
  readJSON v = mk <$> readJSON v `mplus` fail "Unable to read Property"

mk (pn, pk, pt, pr) =
  case Map.lookup pk builtinPropertyMap of
    Just prop ->
      prop { propName   = pn
           , propCustom = True }
    _ ->
      Property { propName      = pn
               , propKey       = pk
               , propType      = pt
               , propCustom    = True
               , propReadOnly  = pr
               , propReadValue = Nothing
               , propShowValue = Nothing }




readValue p s  = liftM Just read `catch` \_ -> return Nothing
  where read   = maybe rdef id (propReadValue p) $ s
        rdef s = case (propType p) of
                   PropertyInt    -> X.PropInt32 <$> readIO s
                   PropertyString -> return $ X.PropString s

showValue p v = maybe sdef id (propShowValue p) $ v
  where sdef (X.PropInt32  n) = show n
        sdef (X.PropString s) = s


lookup p m = do
  res <- (showValue p) <$> Map.lookup (propKey p) m
  when (null res) mzero
  return res


builtinPropertyMap =
  Map.fromList $ map (\p -> (propKey p, p)) builtinProperties

builtinProperties =
  map (\(pn, pk, pt, ro, pr, ps) ->
         Property { propName      = pn
                  , propKey       = pk
                  , propType      = pt
                  , propCustom    = False
                  , propReadOnly  = ro
                  , propReadValue = pr
                  , propShowValue = ps })
      [ ("Artist", "artist",
         PropertyString, False, Nothing, Nothing)
      , ("Album", "album",
         PropertyString, False, Nothing, Nothing)
      , ("Date", "date",
         PropertyString, False, Nothing, Nothing)
      , ("Track", "tracknr",
         PropertyInt, False, Nothing, Nothing)
      , ("Title", "title",
         PropertyString, False, Nothing, Nothing)
      , ("Comment", "comment",
         PropertyString, False, Nothing, Nothing)
      , ("Duration", "duration",
         PropertyInt, True, Nothing, Just showDuration)
      , ("URL", "url",
         PropertyString, True,  Nothing, Just showURL)
      , ("Composer", "composer",
         PropertyString, False, Nothing, Nothing)
      , ("Work", "work",
         PropertyString, False, Nothing, Nothing)
      , ("Catalog", "catalog",
         PropertyString, False, Nothing, Nothing)
      , ("Movement", "movement",
         PropertyString, False, Nothing, Nothing)
      , ("Performer", "performer",
         PropertyString, False, Nothing, Nothing)
      , ("Conductor", "conductor",
         PropertyString, False, Nothing, Nothing)
      , ("Orchestra", "orchestra",
         PropertyString, False, Nothing, Nothing)
      , ("Chorus master", "chorus_master",
         PropertyString, False, Nothing, Nothing)
      , ("Chorus", "chorus",
         PropertyString, False, Nothing, Nothing) ]


showDuration (X.PropInt32  n) =
  if h == 0 then mss else (show h) ++ (':' : mss)
  where d   = n `div` 1000
        h   = d `div` 3600
        m   = (d - (h * 3600)) `div` 60
        s   = d - h * 3600 - m * 60
        mss = printf "%02d:%02d" m s

showURL (X.PropString u) = decodeURL u