content: module MorseCode (Morse, MSym(..), toMorse) where
  
  import Data.List
  import Data.Maybe
  import qualified Data.Map as M
  
  type Morse = [MSym]
  data MSym = Dot | Dash | SGap | CGap | WGap deriving (Show)
  
  -- Based on the table of International Morse Code letters and numerals at
  -- http://en.wikipedia.org/wiki/Morse_code.
  dict = M.fromList
         [('a', m ".-"   ), ('b', m "-..." ), ('c', m "-.-." ), ('d', m "-.."  ),
          ('e', m "."    ), ('f', m "..-." ), ('g', m "--."  ), ('h', m "...." ),
          ('i', m ".."   ), ('j', m ".---" ), ('k', m "-.-"  ), ('l', m ".-.." ),
          ('m', m "--"   ), ('n', m "-."   ), ('o', m "---"  ), ('p', m ".--." ),
          ('q', m "--.-" ), ('r', m ".-."  ), ('s', m "..."  ), ('t', m "-"    ),
          ('u', m "..-"  ), ('v', m "...-" ), ('w', m ".--"  ), ('x', m "-..-" ),
          ('y', m "-.--" ), ('z', m "--.." ), ('1', m ".----"), ('2', m "..---"),
          ('3', m "...--"), ('4', m "....-"), ('5', m "....."), ('6', m "-...."),
          ('7', m "--..."), ('8', m "---.."), ('9', m "----."), ('0', m "-----")]
      where m = intersperse SGap . map toSym
            toSym '.' = Dot
            toSym '-' = Dash
  
  -- Convert a string to a stream of Morse symbols.  We enhance the usual dots
  -- and dashes with special "gap" symbols, which indicate the border between
  -- symbols, characters and words.  This allows a player to easily adjust its
  -- timing by simply looking at the current symbol, rather than trying to keep
  -- track of state.
  toMorse :: String -> Morse
  toMorse = fromWords . words . weed
      where fromWords = intercalate [WGap] . map fromWord
            fromWord  = intercalate [CGap] . map fromChar
            fromChar  = fromJust . flip M.lookup dict
            weed      = filter (\c -> c == ' ' || M.member c dict)
  