module Text.CSS3.Selectors.Syntax (
    SelectorGroup (..),
    Selector (..),
    SimpleSelectorSequence (..),
    HeadSimpleSelector (..),
    TailSimpleSelector (..),
    Combinator (..),
    AttributeOperator (..),
    PseudoClass (..),
    PseudoClassParameter (..),
    Specificity (..),
    specificity
) where
import Data.List
data SelectorGroup = SelectorGroup Selector [Selector]
                     deriving (Show, Read, Eq)
data Selector = Selector SimpleSelectorSequence (Maybe (Combinator, Selector))
                deriving (Show, Read, Eq)
data SimpleSelectorSequence = SimpleSelectorSequence HeadSimpleSelector [TailSimpleSelector]
                              deriving (Show, Read, Eq)
data HeadSimpleSelector = TypeSelector String  
                        | UniversalSelector    
                          deriving (Show, Read, Eq)
data TailSimpleSelector = AttributeSelector String (Maybe (AttributeOperator, String))
                          
                        | ClassSelector String     
                        | IDSelector String        
                        | PseudoClass PseudoClass  
                          deriving (Show, Read, Eq)
data Combinator = Descendant       
                | Child            
                | AdjacentSibling  
                | GeneralSibling   
                  deriving (Show, Read, Eq)
data AttributeOperator = ExactMatch     
                       | IncludesMatch  
                       | DashMatch      
                       | PrefixMatch    
                       | SuffixMatch    
                       | InfixMatch     
                         deriving (Show, Read, Eq)
data PseudoClass = Root
                 | NthChild PseudoClassParameter
                 | NthLastChild PseudoClassParameter
                 | NthOfType PseudoClassParameter
                 | NthLastOfType PseudoClassParameter
                 | FirstChild
                 | LastChild
                 | FirstOfType
                 | LastOfType
                 | OnlyChild
                 | OnlyOfType
                 | Empty
                 | Not (Either HeadSimpleSelector TailSimpleSelector)
                   
                   
                   deriving (Show, Read, Eq)
data PseudoClassParameter = PseudoClassParameter Integer Integer
                            deriving (Show, Read, Eq)
data Specificity = Specificity !Int !Int !Int deriving (Show, Read, Eq, Ord)
specificity :: Selector -> Specificity
specificity (Selector (SimpleSelectorSequence hSel tSels) mbComb) =
    maybe spec ((spec .+) . specificity . snd) mbComb
    where
        spec = foldl1' (.+) $ hSpec hSel : map tSpec tSels
        hSpec h = case h of
                      TypeSelector _    -> Specificity 0 0 1
                      UniversalSelector -> Specificity 0 0 0
        tSpec t = case t of
                      AttributeSelector _ _  -> Specificity 0 1 0
                      ClassSelector _        -> Specificity 0 1 0
                      IDSelector _           -> Specificity 1 0 0
                      PseudoClass (Not eSel) -> either hSpec tSpec eSel
                      PseudoClass _          -> Specificity 0 1 0
        (.+) (Specificity a b c) (Specificity a' b' c') = Specificity (a + a') (b + b') (c + c')