module Language.Css.Pretty(
    Pretty(..), prettyPrint)
where

import Text.PrettyPrint
import Language.Css.Syntax


class Pretty a where
    pretty :: a -> Doc

-- | pretty-print with the default style. 
prettyPrint :: Pretty a => a -> String
prettyPrint = render . pretty

ppMaybe :: Pretty a => Maybe a -> Doc
ppMaybe = maybe empty pretty

punctuatePretties :: Pretty a => Doc -> [a] -> Doc
punctuatePretties sep = hcat . punctuate sep . map pretty

vsep = vcat . punctuate (text "\n")


-- StyleSheet

instance Pretty StyleSheet where
    pretty (StyleSheet ch imp body) = 
               ppMaybe ch 
            $$ (vsep $ map pretty imp)
            $$ (vsep $ map pretty body)

instance Pretty StyleBody where
    pretty x = case x of
                SRuleSet    x -> pretty x
                SAtMedia    x -> pretty x
                SAtPage     x -> pretty x
                SAtFontFace x -> pretty x

-- AtRules

-- @charset
instance Pretty AtCharSet where
    pretty (AtCharSet str) = text "@charset " <> text str <+> semi

-- @import
instance Pretty AtImport where
    pretty (AtImport head ms) =
        text "@import" <+> pretty head <+>
        punctuatePretties comma ms <+> semi

instance Pretty ImportHead where
    pretty x = case x of
                IStr x -> text x
                IUri x -> pretty x
-- @page
instance Pretty AtPage where
    pretty (AtPage id pp ds) = text "@page" 
        <+> ppMaybe id <+> ppMaybe pp 
        <+> (braces $ punctuatePretties semi ds)


-- @media
instance Pretty AtMedia where
    pretty (AtMedia ms rs) = text "@media" 
        <+> punctuatePretties comma ms
        <+> punctuatePretties comma rs
        

-- @font-face
instance Pretty AtFontFace where
    pretty (AtFontFace ds) = text "@font-face" 
        <+> (braces $ punctuatePretties semi ds)


-- RuleSets

instance Pretty RuleSet where
	pretty (RuleSet sels decls) = 
                (vcat $ punctuate comma $ map pretty sels)
                <+> lbrace  
                $$ (nest 4 $ vcat $ punctuate semi $ map pretty decls)
                <+> rbrace


-- Declarations

instance Pretty Decl where
	pretty (Decl prio p v) = 
            case prio of
                Just x  -> decl <+> pretty x
                Nothing -> decl        
            where decl = pretty p <+> char ':' <+> pretty v

instance Pretty Prio where
    pretty = const $ text "!important"

-- Selectors

instance Pretty Sel where
	pretty x = case x of
		    SSel x -> pretty x
		    DescendSel x xs -> pretty x <+> space <+> pretty xs
		    ChildSel   x xs -> pretty x <+> char '>' <+> pretty xs
		    AdjSel     x xs -> pretty x <+> char '+' <+> pretty xs

instance Pretty SimpleSel where
	pretty x = case x of 
		     UnivSel    xs -> char '*' <> prettySubs xs
		     TypeSel el xs -> text el <> prettySubs xs

prettySubs :: [SubSel] -> Doc
prettySubs = hcat . map pretty

instance Pretty PseudoVal where
    pretty x = case x of 
                PIdent a -> pretty a
                PFunc  a -> pretty a

instance Pretty SubSel where
	pretty x = case x of
		    AttrSel a         -> brackets $ text $ show a
		    ClassSel v        -> char '.' <> text v
		    IdSel v           -> char '#' <> text v
		    PseudoSel v       -> char ':' <> pretty v

instance Pretty Attr where
    pretty x = case x of
		    Attr a         -> text a
		    AttrIs a v     -> text a <> equals <> (doubleQuotes $ text v)
		    AttrIncl a v   -> text a <> text "~=" <> (doubleQuotes $ text v)
		    AttrBegins a v -> text a <> text "|=" <> (doubleQuotes $ text v)
	
-- Value

instance Pretty Value where
    pretty x = case x of
        VDeg a -> pretty a
        VRad a -> pretty a
        VGrad a -> pretty a
        VColor a -> pretty a
        VHz a -> pretty a
        VKHz a -> pretty a
        VFunc a -> pretty a
        VIdent a -> pretty a
        VInt a -> int a
        VEm a -> pretty a
        VEx a -> pretty a
        VPx a -> pretty a
        VIn a -> pretty a
        VCm a -> pretty a
        VMm a -> pretty a
        VPc a -> pretty a
        VPt a -> pretty a
        VDouble a -> double a
        VPercentage a -> pretty a
        VString a -> text $ show a
        VMs a -> pretty a
        VS a -> pretty a
        VUri a -> pretty a

-- Values

instance Pretty Expr where
    pretty x = case x of
                EVal x -> pretty x
                SlashSep x e -> pretty x <+> char '/' <+> pretty e
                CommaSep x e -> pretty x <+> char ',' <+> pretty e
                SpaceSep x e -> pretty x <+> space <+> pretty e

instance Pretty Func where
    pretty (Func name arg) = text (show name) <+> parens (pretty arg)


instance Pretty Ident where
	pretty (Ident a) = text a


-- Value elems

instance Pretty Deg where
    pretty (Deg x) = (text $ show x) <> text "deg"

instance Pretty Rad where
    pretty (Rad x) = (text $ show x) <> text "rad"

instance Pretty Grad where
    pretty (Grad x) = (text $ show x) <> text "grad"

instance Pretty Color where
    pretty x = case x of 
        Cword a    -> text a 
        Crgb r g b -> (text "rgb" <> ) $ parens $ hsep $ 
                        punctuate comma $ map (text. show) [r, g, b]

instance Pretty Hz where
    pretty (Hz x) = (text $ show x) <> text "Hz"

instance Pretty KHz where
    pretty (KHz x) = (text $ show x) <> text "kHz"

instance Pretty Em where
    pretty (Em x) = (text $ show x) <> text "em"

instance Pretty Ex where
    pretty (Ex x) = (text $ show x) <> text "ex"

instance Pretty Px where
    pretty (Px x) = (text $ show x) <> text "px"

instance Pretty In where
    pretty (In x) = (text $ show x) <> text "in"

instance Pretty Cm where
    pretty (Cm x) = (text $ show x) <> text "cm"

instance Pretty Mm where
    pretty (Mm x) = (text $ show x) <> text "mm"

instance Pretty Pc where
    pretty (Pc x) = (text $ show x) <> text "pc"

instance Pretty Pt where
    pretty (Pt x) = (text $ show x) <> text "pt"

instance Pretty Percentage where
    pretty (Percentage x) = (text $ show x) <> text "%"

instance Pretty Ms where
    pretty (Ms x) = (text $ show x) <> text "ms"

instance Pretty S where
    pretty (S x) = (text $ show x) <> text "s"

instance Pretty Uri where
    pretty (Uri x) = text "url" <> (parens $ text $ show x)