module Day18 where

import AoC

import Control.Applicative
import Data.Maybe
import Text.ParserCombinators.ReadP
import Text.Read.Lex

data Expression = Literal Int
                | Addition Expression Expression
                | Multiplication Expression Expression
                | Bracketed Expression

type ApplicationSequencer = Expression -> String -> Expression -> Expression

parseLiteral :: ReadP Expression
parseLiteral = Literal <$> readDecP

parseBracketed :: ApplicationSequencer -> ReadP Expression
parseBracketed seq = Bracketed <$> between (char '(') (char ')') (parseExpression seq)

parseOperations :: ApplicationSequencer -> ReadP Expression
parseOperations seq =
    do l <- parseLiteral <|> parseBracketed seq
       apps <- many1 $ parseApplication seq
       return $ foldl (\l (op, r) -> seq l op r) l apps

parseApplication :: ApplicationSequencer -> ReadP (String, Expression)
parseApplication seq =
    do skipSpaces
       op <- choice $ map string ["*", "+"]
       skipSpaces
       r <- parseLiteral <|> parseBracketed seq
       return $ (op, r)

parseExpression :: ApplicationSequencer -> ReadP Expression
parseExpression seq = parseLiteral <|> parseOperations seq <|> parseBracketed seq

sequenceLeftToRight :: ApplicationSequencer
sequenceLeftToRight l op r = toOperation op l r
    where toOperation "*" = Multiplication
          toOperation "+" = Addition

sequenceAdditionPrecedence :: ApplicationSequencer
sequenceAdditionPrecedence (Multiplication l r) "+" rr = Multiplication l (Addition r rr)
sequenceAdditionPrecedence l op r = sequenceLeftToRight l op r

eval :: Expression -> Int
eval (Literal n) = n
eval (Addition l r) = eval l + eval r
eval (Multiplication l r) = eval l * eval r
eval (Bracketed x) = eval x

main = runAoC lines (run sequenceLeftToRight) (run sequenceAdditionPrecedence)
    where run seq = sum . map (eval . fromJust . oneCompleteResult (parseExpression seq))
