module Radium.Formats.Smiles ( readSmiles
, writeSmiles ) where
import Text.ParserCombinators.Parsec
import qualified Data.Set as Set
import Data.Maybe
data Smiles = Atom String
Int
Int
Int
Int
| Aliphatic String
| Aromatic String
| Unknown
| Empty
deriving( Eq, Show )
aliphatics :: Set.Set String
aliphatics = Set.fromList ["B", "C", "N", "O", "S", "P", "F", "Cl", "Br", "I" ]
aromatics :: Set.Set Char
aromatics = Set.fromList "bcnosp"
readSmiles :: String -> Smiles
readSmiles xs = case parse atom "" xs of
Left _ -> Empty
Right val -> val
atom :: Parser Smiles
atom = bracketAtom <|> aliphaticOrganic <|> aromaticOrganic <|> unknown
bracketAtom :: Parser Smiles
bracketAtom = do
_ <- char '['
i <- optionMaybe number
s <- symbolOrUnknown
hc <- optionMaybe hcount
n <- optionMaybe charge
ac <- optionMaybe atomClass
_ <- char ']'
return $ Atom s (fromMaybe 0 i) (fromMaybe 0 hc) (fromMaybe 0 n) (fromMaybe 0 ac)
symbolOrUnknown :: Parser String
symbolOrUnknown = symbol <|> string "*"
hcount :: Parser Int
hcount = do
_ <- char 'H'
hc <- optionMaybe number
let n = fromMaybe 1 hc
return $ if n == 0 then 1 else n
charge :: Parser Int
charge = do
s <- char '-' <|> char '+'
n <- number
let m = if n == 0 then 1 else n
return $ if s == '-' then (m) else m
atomClass :: Parser Int
atomClass = do
_ <- char ':'
number
number :: Parser Int
number = do
ds <- many digit
return $ if null ds then 0 else read ds :: Int
aliphaticOrganic :: Parser Smiles
aliphaticOrganic = do
ss <- symbol
if Set.member ss aliphatics then return (Aliphatic ss) else fail ""
aromaticOrganic :: Parser Smiles
aromaticOrganic = do
ss <- lower
if Set.member ss aromatics then return (Aromatic [ss]) else fail ""
unknown :: Parser Smiles
unknown = do
_ <- char '*'
return Unknown
symbol :: Parser String
symbol = do
s <- upper
ss <- many lower
return (s:ss)
writeSmiles :: Smiles -> String
writeSmiles (Atom xs ic hc n ac) = "[" ++ showIsotopes ++ xs ++ showHyrdogen ++ showCharge ++ showClass ++ "]"
where showIsotopes = if ic > 0 then show ic else ""
showHyrdogen | hc > 1 = "H" ++ show hc
| hc == 1 = "H"
| otherwise = ""
showCharge | n < (1) = show n
| n == (1) = "-"
| n == 1 = "+"
| n > 1 = "+" ++ show n
| otherwise = ""
showClass = if ac > 0 then ":" ++ show ac else ""
writeSmiles (Aliphatic xs) = xs
writeSmiles (Aromatic xs) = xs
writeSmiles Unknown = "*"
writeSmiles Empty = ""