-- | a leading question mark is removed, possibly a session id is returned
anaQuery :: [QueryPair] -> [String] -> Either String (Maybe Int, QueryKind)
anaQuery q' globals =
       let (atP, q'') = partition ((== "autoproof") . fst) q'
           (atC, q) = partition ((== "consistency") . fst) q''
           (q1, qm) = partition (\ l -> case l of
                        (x, Nothing) -> isNat x || elem x
                               (displayTypes ++ globals
                                ++ ["include", "autoproof"]
                                ++ nodeCommands ++ edgeCommands)
                        _ -> False) q
           (q2, qr) = partition (\ l -> case l of
                        (x, Just y) ->
                            elem x (["dg", "id", "session"]
                                    ++ edgeCommands)
                            && isNat y
                               || x == "command" &&
                                  elem y globals
                               || x == "format" && elem y displayTypes
                               || elem x ("name" : tail proveParams
                                          ++ nodeCommands)
                                  -- note: allows illegal timeout values
                               || x == "timeout"
                                  -- without timeout, see above
                        _ -> False) qm
           (fs, r1) = partition (`elem` displayTypes) $ map fst q1
           (gs, r2) = partition (`elem` globals) r1
           (ns, r3) = partition (`elem` nodeCommands) r2
           (es, r4) = partition (`elem` edgeCommands) r3
           (incls, is) = partition (== "include") r4
           (fs2, p1) = partition ((== "format") . fst) q2
           (cs2, p2) = partition ((== "command") . fst) p1
           (is2, p3) = partition ((`elem` ["dg", "session"]) . fst) p2
           (ns2, p4) = partition ((`elem` nodeCommands) . fst) p3
           (es2, p5) = partition ((`elem` edgeCommands) . fst) p4
           (nns, p6) = partition ((== "name") . fst) p5
           (ids, pps) = partition ((== "id") . fst) p6
           snds = mapMaybe snd
           afs = nubOrd $ fs ++ snds fs2
           ags = nubOrd $ gs ++ snds cs2
           ans = nubOrd $ ns ++ map fst ns2
           aes = nubOrd $ es ++ map fst es2
           ais = nubOrd $ is ++ snds is2
           aids = nubOrd . snds $ ns2 ++ es2 ++ ids ++ nns
           mi = fmap read $ listToMaybe ais
           (theorems, qqr) = partition ((== Just "on") . snd) qr
           noPP = null pps && null incls && null theorems
       -- TODO i kind of abused this functions structure for autoproofs here
       in if not $ null atP then Right (mi, GlShowProverWindow GlProofs) else
          if not $ null atC then Right (mi, GlShowProverWindow GlConsistency)
          else
          if null qqr && length ais < 2 then case (afs, ags, ans, aes, aids) of
         (_, [], [], [], []) | noPP -> if length afs > 1
           then Left $ "non-unique format " ++ show afs
           else Right (mi, DisplayQuery $ listToMaybe afs)
         (_, c : r, [], [], []) | noPP -> if null r
           then Right (mi, GlobCmdQuery c)
           else Left $ "non-unique command " ++ show r
         (_, [], _, [], [_]) -> fmap (\ qk -> (mi, qk)) $
           anaNodeQuery ans (getIdOrName ids nns ns2) (map fst theorems)
             incls pps
         (_, [], [], e : r, i : s) | noPP ->
           if null r && null s && null nns && null ns2
           then Right (mi, EdgeQuery (read i) e)
           else Left $ "non-unique edge " ++ show (aes ++ aids)
         _ -> Left $ "non-unique query " ++ show q
       else Left $ if null qqr then "non-unique dg " ++ show q else
                       "ill-formed query " ++ show qqr
anaQuery :: [QueryPair] -> [String] -> Either String (Maybe Int, QueryKind)
anaQuery q' globals =
       let (atP, q'') = partition ((== "autoproof") . fst) q'
           (atC, q) = partition ((== "consistency") . fst) q''
           (q1, qm) = partition (\ l -> case l of
                        (x, Nothing) -> isNat x || elem x
                               (displayTypes ++ globals
                                ++ ["include", "autoproof"]
                                ++ nodeCommands ++ edgeCommands)
                        _ -> False) q
           (q2, qr) = partition (\ l -> case l of
                        (x, Just y) ->
                            elem x (["dg", "id", "session"]
                                    ++ edgeCommands)
                            && isNat y
                               || x == "command" &&
                                  elem y globals
                               || x == "format" && elem y displayTypes
                               || elem x ("name" : tail proveParams
                                          ++ nodeCommands)
                                  -- note: allows illegal timeout values
                               || x == "timeout"
                                  -- without timeout, see above
                        _ -> False) qm
           (fs, r1) = partition (`elem` displayTypes) $ map fst q1
           (gs, r2) = partition (`elem` globals) r1
           (ns, r3) = partition (`elem` nodeCommands) r2
           (es, r4) = partition (`elem` edgeCommands) r3
           (incls, is) = partition (== "include") r4
           (fs2, p1) = partition ((== "format") . fst) q2
           (cs2, p2) = partition ((== "command") . fst) p1
           (is2, p3) = partition ((`elem` ["dg", "session"]) . fst) p2
           (ns2, p4) = partition ((`elem` nodeCommands) . fst) p3
           (es2, p5) = partition ((`elem` edgeCommands) . fst) p4
           (nns, p6) = partition ((== "name") . fst) p5
           (ids, pps) = partition ((== "id") . fst) p6
           snds = mapMaybe snd
           afs = nubOrd $ fs ++ snds fs2
           ags = nubOrd $ gs ++ snds cs2
           ans = nubOrd $ ns ++ map fst ns2
           aes = nubOrd $ es ++ map fst es2
           ais = nubOrd $ is ++ snds is2
           aids = nubOrd . snds $ ns2 ++ es2 ++ ids ++ nns
           mi = fmap read $ listToMaybe ais
           (theorems, qqr) = partition ((== Just "on") . snd) qr
           noPP = null pps && null incls && null theorems
       -- TODO i kind of abused this functions structure for autoproofs here
       in if not $ null atP then Right (mi, GlShowProverWindow GlProofs) else
          if not $ null atC then Right (mi, GlShowProverWindow GlConsistency)
          else
          if null qqr && length ais < 2 then case (afs, ags, ans, aes, aids) of
         (_, [], [], [], []) | noPP -> if length afs > 1
           then Left $ "non-unique format " ++ show afs
           else Right (mi, DisplayQuery $ listToMaybe afs)
         (_, c : r, [], [], []) | noPP -> if null r
           then Right (mi, GlobCmdQuery c)
           else Left $ "non-unique command " ++ show r
         (_, [], _, [], [_]) -> fmap (\ qk -> (mi, qk)) $
           anaNodeQuery ans (getIdOrName ids nns ns2) (map fst theorems)
             incls pps
         (_, [], [], e : r, i : s) | noPP ->
           if null r && null s && null nns && null ns2
           then Right (mi, EdgeQuery (read i) e)
           else Left $ "non-unique edge " ++ show (aes ++ aids)
         _ -> Left $ "non-unique query " ++ show q
       else Left $ if null qqr then "non-unique dg " ++ show q else
                       "ill-formed query " ++ show qqr
anaQuery q' globals =
       let (atP, q'') = partition ((== "autoproof") . fst) q'
           (atC, q) = partition ((== "consistency") . fst) q''
           (q1, qm) = partition (\ l -> case l of
                        (x, Nothing) -> isNat x || elem x
                               (displayTypes ++ globals
                                ++ ["include", "autoproof"]
                                ++ nodeCommands ++ edgeCommands)
                        _ -> False) q
           (q2, qr) = partition (\ l -> case l of
                        (x, Just y) ->
                            elem x (["dg", "id", "session"]
                                    ++ edgeCommands)
                            && isNat y
                               || x == "command" &&
                                  elem y globals
                               || x == "format" && elem y displayTypes
                               || elem x ("name" : tail proveParams
                                          ++ nodeCommands)
                                  -- note: allows illegal timeout values
                               || x == "timeout"
                                  -- without timeout, see above
                        _ -> False) qm
           (fs, r1) = partition (`elem` displayTypes) $ map fst q1
           (gs, r2) = partition (`elem` globals) r1
           (ns, r3) = partition (`elem` nodeCommands) r2
           (es, r4) = partition (`elem` edgeCommands) r3
           (incls, is) = partition (== "include") r4
           (fs2, p1) = partition ((== "format") . fst) q2
           (cs2, p2) = partition ((== "command") . fst) p1
           (is2, p3) = partition ((`elem` ["dg", "session"]) . fst) p2
           (ns2, p4) = partition ((`elem` nodeCommands) . fst) p3
           (es2, p5) = partition ((`elem` edgeCommands) . fst) p4
           (nns, p6) = partition ((== "name") . fst) p5
           (ids, pps) = partition ((== "id") . fst) p6
           snds = mapMaybe snd
           afs = nubOrd $ fs ++ snds fs2
           ags = nubOrd $ gs ++ snds cs2
           ans = nubOrd $ ns ++ map fst ns2
           aes = nubOrd $ es ++ map fst es2
           ais = nubOrd $ is ++ snds is2
           aids = nubOrd . snds $ ns2 ++ es2 ++ ids ++ nns
           mi = fmap read $ listToMaybe ais
           (theorems, qqr) = partition ((== Just "on") . snd) qr
           noPP = null pps && null incls && null theorems
       -- TODO i kind of abused this functions structure for autoproofs here
       in if not $ null atP then Right (mi, GlShowProverWindow GlProofs) else
          if not $ null atC then Right (mi, GlShowProverWindow GlConsistency)
          else
          if null qqr && length ais < 2 then case (afs, ags, ans, aes, aids) of
         (_, [], [], [], []) | noPP -> if length afs > 1
           then Left $ "non-unique format " ++ show afs
           else Right (mi, DisplayQuery $ listToMaybe afs)
         (_, c : r, [], [], []) | noPP -> if null r
           then Right (mi, GlobCmdQuery c)
           else Left $ "non-unique command " ++ show r
         (_, [], _, [], [_]) -> fmap (\ qk -> (mi, qk)) $
           anaNodeQuery ans (getIdOrName ids nns ns2) (map fst theorems)
             incls pps
         (_, [], [], e : r, i : s) | noPP ->
           if null r && null s && null nns && null ns2
           then Right (mi, EdgeQuery (read i) e)
           else Left $ "non-unique edge " ++ show (aes ++ aids)
         _ -> Left $ "non-unique query " ++ show q
       else Left $ if null qqr then "non-unique dg " ++ show q else
                       "ill-formed query " ++ show qqr