{- |
Module : Chemistry.Formula
Copyright : Copyright (C) 2014 Krzysztof Langner
License : BSD3

Maintainer : Krzysztof Langner <klangner@gmail.com>
Stability : alpha
Portability : portable

Formula parser. 
.
Formula can be entered as H2O, SO4+2 (Sulfate) or (CH3)2CO (Acetone)
-}

module Chemistry.Formula ( Formula(..)
                          , parseFormula
                          ) where

import Text.ParserCombinators.Parsec

type ElementSymbol = String

data Formula = FGroup [(Formula, Int)] 
             | FElement ElementSymbol 
             deriving (Eq, Show)

-- | Parse formula 
--
-- > parseFormula "C2H4" `shouldBe` Formula [(element 6, 2), (element 1, 4)]  
parseFormula :: String -> Formula
parseFormula xs = case parse formula "" xs of
    Left _ -> FGroup []
    Right val -> FGroup val


-- Parse whole formula
formula :: Parser [(Formula, Int)]
formula = many elementSymbol
    
-- Parse element
-- Element is max 3 letter long
-- Starts with upper case
-- has 0, 1 or 2 lower letters
elementSymbol :: Parser (Formula, Int)
elementSymbol = do
    l1 <- upper
    l2 <- many lower
    let e = FElement (l1:l2) 
    ds <- many digit
    let n = if null ds then 1 else read ds :: Int
    return (e, n)