    -- | Formats Haskell source code using mIRC codes.
    --   (see http:\/\/irssi.org\/documentation\/formats)
    module Language.Haskell.HsColour.MIRC (hscolour) where

    import Language.Haskell.HsColour.Classify as Classify
    import Language.Haskell.HsColour.Colourise

    import Data.Char(isAlphaNum)

    -- | Formats Haskell source code using mIRC codes.
    hscolour :: ColourPrefs -- ^ Colour preferences.
             -> String      -- ^ Haskell source code.
             -> String      -- ^ Coloured Haskell source code.
    hscolour pref = concatMap (renderToken pref) . tokenise

    renderToken :: ColourPrefs -> (TokenType,String) -> String
    renderToken pref (t,s) = fontify (colourise pref t) s

    -- mIRC stuff
    fontify hs =
        mircColours (joinColours hs)
        . highlight (filter (`elem`[Normal,Bold,Underscore,ReverseVideo]) hs)
      where
        highlight [] s     = s
        highlight (h:hs) s = font h (highlight hs s)

        font Normal         s = s
        font Bold           s = '\^B':s++"\^B"
        font Underscore     s = '\^_':s++"\^_"
        font ReverseVideo   s = '\^V':s++"\^V"

    -- mIRC combines colour codes in a non-modular way
    data MircColour = Mirc { fg::Colour, dim::Bool, bg::Maybe Colour, blink::Bool}

    joinColours :: [Highlight] -> MircColour
    joinColours = foldr join (Mirc {fg=Black, dim=False, bg=Nothing, blink=False})
      where
        join Blink           mirc = mirc {blink=True}
        join Dim             mirc = mirc {dim=True}
        join (Foreground fg) mirc = mirc {fg=fg}
        join (Background bg) mirc = mirc {bg=Just bg}
        join Concealed       mirc = mirc {fg=Black, bg=Just Black}
        join _               mirc = mirc

    mircColours :: MircColour -> String -> String
    mircColours (Mirc fg dim Nothing   blink) s = '\^C': code fg dim++s++"\^O"
    mircColours (Mirc fg dim (Just bg) blink) s = '\^C': code fg dim++','
                                                       : code bg blink++s++"\^O"

    code :: Colour -> Bool -> String
    code Black   False = "1"
    code Red     False = "5"
    code Green   False = "3"
    code Yellow  False = "7"
    code Blue    False = "2"
    code Magenta False = "6"
    code Cyan    False = "10"
    code White   False = "0"
    code Black   True  = "14"
    code Red     True  = "4"
    code Green   True  = "9"
    code Yellow  True  = "8"
    code Blue    True  = "12"
    code Magenta True  = "13"
    code Cyan    True  = "11"
    code White   True  = "15"