{-|
    Parse a query, that may have come from either a CGI variable
    or the command line arguments.

    Need to return the following pieces of information:

    * Was there a query, or was nothing entered

    * Are you wanting to operate in Web mode or Command Line mode. Adding a
    Web parameter to Command Line gives you Web mode.

    * Which flags were specified, and which were erroneous.
-}

module CmdLine.Query(cmdQuery, CmdQuery(..)) where

import General.Code
import Text.ParserCombinators.Parsec

import CmdLine.Flag
import General.CGI
import Hoogle.Query.All


data CmdQuery = CmdQuery {
    queryWeb :: Bool, -- ^ Are you operating from the web (via CGI)
    queryText :: String, -- ^ The string the user entered, @\"\"@ for no string
    query :: Either ParseError Query, -- ^ The actual query
    queryFlags :: [CmdFlag], -- ^ The flags from the query
    queryBadFlags :: [String] -- ^ The bad flags
    } deriving Show


-- | Left (query text, error message), null query text = no query given
--   Right (query, command line flags, unparsable/unsupported flags)
cmdQuery :: IO CmdQuery
cmdQuery = do
    r <- cgiArgs
    case r of
        Just y -> cmdQueryCGI y
        Nothing -> cmdQueryArgs =<< getArgs


cmdQueryCGI :: [(String,String)] -> IO CmdQuery
cmdQueryCGI [("",x)] = cmdQueryCGI [("q",x)]
cmdQueryCGI xs = do
    (flags1,bad1) <- flagsWebArgs notq
    case parseQuery str of
        Left err -> return $ CmdQuery True str (Left err) flags1 bad1
        Right res -> do
            (flags2,bad2) <- flagsWebQuery $ queryArgs res
            return $ CmdQuery True str (Right res) (flags2++flags1) (bad2++bad1)
    where
        (q,notq) = partition ((`elem` ["q","hoogle"]) . fst) xs
        str = unwords $ map snd q


-- TODO: Checking for web and debug specifically are both hacks
--       Should parse any arguments it can separately
cmdQueryArgs :: [String] -> IO CmdQuery
cmdQueryArgs xs = case parseCmdLineQuery xs of
    Left err -> return $ CmdQuery (hasFlag ["w","web"]) orig (Left err) [Debug | hasFlag ["debug"]] []
    Right res -> do
        (flags,bad) <- flagsCmdLine $ queryArgs res
        return $ CmdQuery (Web `elem` flags) orig (Right res) flags bad
    where orig = unwords $ map quote xs
          hasFlag names = or [(a++b) `elem` xs | a <- ["/","--"], b <- names]


quote :: String -> String
quote x | any isSpace x = "\"" ++ x ++ "\""
        | otherwise = x


queryArgs :: Query -> [(String,String)]
queryArgs q = [(a,b) | Flag a b <- flags q]