
import Data.Char
import Data.Function (on)
import Data.List
import Data.Maybe
import Database.HDBC.Sqlite3
import System (getArgs)
import Text.Regex (mkRegex, splitRegex)

import AnsiEscape
import Parse
import Search

trim = f . f
    where f = dropWhile isSpace . reverse

replace _ _ [] = []
replace a b (x:xs) = (if x == a then b else x) : replace a b xs

paragraphs :: String -> [String]
paragraphs = splitRegex (mkRegex "\n+") . (dropWhile (== '\n'))

mungeText :: String -> String
mungeText [] = []
mungeText ('\'':'\'':'\'':xs) = mungeText xs
mungeText ('\n':'=':xs) = let (x, y) = break (== '=') (dropWhile (== '=') xs)
                           in x ++ (dropWhile (== '=') y)
mungeText ('<':'b':'i':'g':'>':xs) = mungeText xs
mungeText ('<':'/':'b':'i':'g':'>':xs) = mungeText xs
mungeText (x:xs) = x : mungeText xs

toText :: [WikiText] -> String
toText xs = concat $ mapMaybe toText' xs
    where toText' (Text s) = Just s
          toText' (Link a b) = Just a
          toText' (Template _ _) = Nothing

isText (Text _) = True
isText _ = False

mungeWiki :: [WikiText] -> [WikiText]
mungeWiki (Template _ _ : xs) = mungeWiki xs
mungeWiki (Text "" : xs) = mungeWiki xs
mungeWiki (Text s : l@(Link _ _) : xs)
    | trim s `elem` ["", "|"] = mungeWiki xs
    | otherwise = (Text s : l : xs)
mungeWiki (Text s : xs)
    | "__NOTOC__" `isPrefixOf` s = mungeWiki (Text (drop 9 s) : xs)
    | isSpace (head s) = mungeWiki (Text (dropWhile isSpace s) : xs)
    | otherwise = (Text s : xs)
mungeWiki xs = xs

summary :: [WikiText] -> String
summary = take 70 . trim . replace '\n' ' ' . mungeText . toText . mungeWiki

highlight _ [] = empty
highlight s t@(x:xs)
    | s `isPrefixLower` t = let (start, rest) = splitAt (length s) t in
                                underline start # highlight s rest
    | otherwise = [x] # highlight s xs
    where isPrefixLower = isPrefixOf `on` map toLower

recipeSummary :: [WikiText] -> Maybe WikiText
recipeSummary [] = Nothing
recipeSummary (t@(Template "recipesummary" _) : xs) = Just t
recipeSummary (_ : xs) = recipeSummary xs

readInt :: String -> Maybe Int
readInt s = case reads s of
                [(n, "")] -> Just n
                _ -> Nothing

difficulty :: [WikiText] -> Maybe Int
difficulty text = do
    (Template _ args) <- recipeSummary text
    case map snd args of
        (_:_:_:[Text d]:_) -> readInt d
        _ -> Nothing

main = do
    [query] <- getArgs
    conn <- connectSqlite3 "cookbook.db"
    search conn query >>= putStr . concat . (intersperse "\n") .
        map (\(title, text) -> ansi $ format query title text)
    where format query title text =
              bold (highlight query title # stars text) # "\n  " #
                  (highlight query . summary) text # "\n"
          stars text = fromMaybe empty $ difficulty text >>=
                           \n -> Just . (" " #) . red $ replicate n '*'

