import Data.List(elemIndex)

data Result = Valid | BadCheck | TooLong | TooShort | InvalidContent deriving Show



allMaybe :: [Maybe a] -> Maybe [a]
allMaybe = sequence

toValue :: Char -> Maybe Int
toValue c = elemIndex c $ ['0'..'9'] ++ ['A'..'Z'] ++ "*@#" 


valid :: [Int] -> Bool
valid ns0 = 
    let 
        ns1 = zipWith (\i n -> (if odd i then n else 2*n)) [1..] $ take 8 ns0

        
        sm = sum $ fmap (\s -> ( s `div` 10 ) + s `mod` 10) ns1

    in  
        ns0!!8 == (10 - (sm `mod` 10)) `mod` 10


checkCUSIP :: String -> Result
checkCUSIP cs 
       | l < 9     = TooShort
       | l > 9     = TooLong
       | otherwise = case allMaybe (fmap toValue cs) of
                         Nothing -> InvalidContent
                         Just ns -> if valid ns then Valid else BadCheck
    where l = length cs

testData =  
    [ "037833100"
    , "17275R102"
    , "38259P508"
    , "594918104"
    , "68389X106"
    , "68389X105"
    ]

main = mapM_ putStrLn (fmap (\s -> s ++ ": " ++ show (checkCUSIP s)) testData)