-- | Run the yaku checker with the given grouping.
runYakuCheck :: ValueInfo -> Grouping -> YakuCheck Yaku -> Maybe Yaku
runYakuCheck info grouping = fmap fst . (`runStateT` grouping) . iterM f
    where
        f :: Check (StateT Grouping Maybe Yaku) -> StateT Grouping Maybe Yaku
        f (YakuMentsu  mp s)            = get >>= lift . findMatch mp >>= putRes >>  s
        f (YakuMentsu' mp s)            = get >>= lift . findMatch mp >>= putRes >>= s
        f (YakuStateful s)              = s info
        f (YakuHandConcealedDegrades s) = if isConcealed  then s            else s <&> (yHan -~ 1)
        f (YakuHandConcealed s)         = if isConcealed  then s            else lift Nothing
        f (YakuHandOpen s)              = if isConcealed  then lift Nothing else s
        f (YakuRequireFlag flag s)      = if hasFlag flag then s           else lift Nothing
        f YakuFailed                    = lift Nothing

        putRes (tg, g) = put g >> return tg
        isConcealed    = null $ info^..vHand.handCalled.each.filtered
            (maybe True ((`onotElem` [Ron, Chankan]) . shoutKind) . mentsuShout)
        hasFlag flag   = elem flag $ info^.vKyoku.pFlags

-- @MentsuProp@s
runYakuCheck :: ValueInfo -> Grouping -> YakuCheck Yaku -> Maybe Yaku
runYakuCheck info grouping = fmap fst . (`runStateT` grouping) . iterM f
    where
        f :: Check (StateT Grouping Maybe Yaku) -> StateT Grouping Maybe Yaku
        f (YakuMentsu  mp s)            = get >>= lift . findMatch mp >>= putRes >>  s
        f (YakuMentsu' mp s)            = get >>= lift . findMatch mp >>= putRes >>= s
        f (YakuStateful s)              = s info
        f (YakuHandConcealedDegrades s) = if isConcealed  then s            else s <&> (yHan -~ 1)
        f (YakuHandConcealed s)         = if isConcealed  then s            else lift Nothing
        f (YakuHandOpen s)              = if isConcealed  then lift Nothing else s
        f (YakuRequireFlag flag s)      = if hasFlag flag then s           else lift Nothing
        f YakuFailed                    = lift Nothing

        putRes (tg, g) = put g >> return tg
        isConcealed    = null $ info^..vHand.handCalled.each.filtered
            (maybe True ((`onotElem` [Ron, Chankan]) . shoutKind) . mentsuShout)
        hasFlag flag   = elem flag $ info^.vKyoku.pFlags

-- @MentsuProp@s
runYakuCheck info grouping = fmap fst . (`runStateT` grouping) . iterM f
    where
        f :: Check (StateT Grouping Maybe Yaku) -> StateT Grouping Maybe Yaku
        f (YakuMentsu  mp s)            = get >>= lift . findMatch mp >>= putRes >>  s
        f (YakuMentsu' mp s)            = get >>= lift . findMatch mp >>= putRes >>= s
        f (YakuStateful s)              = s info
        f (YakuHandConcealedDegrades s) = if isConcealed  then s            else s <&> (yHan -~ 1)
        f (YakuHandConcealed s)         = if isConcealed  then s            else lift Nothing
        f (YakuHandOpen s)              = if isConcealed  then lift Nothing else s
        f (YakuRequireFlag flag s)      = if hasFlag flag then s           else lift Nothing
        f YakuFailed                    = lift Nothing

        putRes (tg, g) = put g >> return tg
        isConcealed    = null $ info^..vHand.handCalled.each.filtered
            (maybe True ((`onotElem` [Ron, Chankan]) . shoutKind) . mentsuShout)
        hasFlag flag   = elem flag $ info^.vKyoku.pFlags

-- @MentsuProp@s