{-
	Copyright (C) 2010-2015 Dr. Alistair Ward

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
-}
{- |
 [@AUTHOR@]	Dr. Alistair Ward

 [@DESCRIPTION@]

	* Defines those options relating to the "RegExDot.RegEx"-runtime.

	* These tend to be options which don't affect the result, only the means by which it is achieved.

	* Whilst similar structures are present in other regex-implementations, there's no standardisation of the fields.
-}

module RegExDot.ExecutionOptions(
-- * Types
-- ** Data-types
        ExecutionOptions(..),
-- * Functions
-- ** Mutators
        setVerbose
) where

import qualified        Data.Default
import qualified        ToolShed.Options

-- | The switches used to control execution of the /regex/-engine.
data ExecutionOptions   = MkExecutionOptions {
        abortTrialRepetitionsOnInherentFailure  :: Bool,        -- ^ If an /alternative/ can't match, irrespective of the subsequent /RegExDot.RegEx.Concatenation/, then avoid futile trial /RegExDot.Repeatable.Repetitions/. The converse of 'checkForUnconsumableData'.
        abortTrialRepetitionsOnZeroConsumption  :: Bool,        -- ^ Check for zero data-consumption by the @n@-th /RegExDot.Repeatable.Repeatable RegExDot.RegEx.CaptureGroup/, before attempting @n+1@.
        bypassInputDataForLiberalConsumer       :: Bool,        -- ^ Whether to bypass reading of the input data, if the mapping to specific /RegExDot.RegEx.RepeatablePattern/s isn't required, & the /RegExDot.RegEx.ExtendedRegEx/ can consume the required quantity of anything.
        catchIncompatibleAnchors                :: Bool,        -- ^ Avoid futile trial solutions, involving repetitions of anchored alternatives, which must consume data.
        checkExistenceOfInelasticTail           :: Bool,        -- ^ If the /RegExDot.RegEx.ExtendedRegEx/ ends in an inelastic (zero /Star-height/) tail, confirm its existence at the end of the /RegExDot.RegEx.InputData/.
        checkForUnconsumableData                :: Bool,        -- ^ Check whether there's no possibility of consuming some of the input data. The converse of 'abortTrialRepetitionsOnInherentFailure'.
        moderateGreed                           :: Bool,        -- ^ Greedily consume data, only up to the limit beyond which, future requirements would be compromised.
        permitReorderingOfAlternatives          :: Bool,        -- ^ Permit /RegExDot.RegEx.Alternatives/ to be re-ordered, in an attempt to more quickly locate a result.
        preferAlternativesWhichFeedTheGreedy    :: Bool,        -- ^ Within the /RegExDot.RegEx.MatchedData/ from which each candidate /RegExDot.RegEx.Match/ amongst sequences of /RegExDot.RegEx.Alternatives/, is ultimately composed, prefer /RegExDot.ConsumptionBounds.ConsumptionBounds/ of /RegExDot.RegEx.InputData/, beyond /RegExDot.Repeatable.getFewest/, by /RegExDot.Repeatable.isGreedy RegExDot.RegEx.RepeatablePattern/s.
        preferAlternativesWhichMimickUnrolling  :: Bool,        -- ^ Compare /RegExDot.ConsumptionBounds.ConsumptionBounds/ on successive /RegExDot.Repeatable.Repetitions/ of /RegExDot.RegEx.CaptureGroup/, between candidate /RegExDot.RegEx.Match/es, to mimic the behaviour of the unrolled /RegExDot.Repeatable.Repetitions/.
        preferFewerRepeatedAlternatives         :: Bool,        -- ^ Prefer fewer /RegExDot.Repeatable.Repetitions/ of /RegExDot.RegEx.Alternatives/, to discourage the capture of null lists of /RegExDot.RegEx.InputData/.
        requireMatchList                        :: Bool,        -- ^ If merely interested in a 'Bool' result, rather than the optimal mapping of input data to /RegExDot.RegEx.RepeatablePattern/s, avoid unnecessary evaluation of the /RegEx.Match/.
        unrollRepeatedSingletonAlternative      :: Bool,        -- ^ Check whether /RegExDot.RegEx.Alternatives/ consists of just a singleton /RegExDot.RegEx.ExtendedRegEx/, & has therefore been used merely as a capture-group. Though this doesn't affect the result, it vastly improves efficiency.
        useFirstMatchAmongAlternatives          :: Bool,        -- ^ Rather than performing an exhaustive search for the optimal choice amongst /RegExDot.RegEx.Alternatives/, merely select the first that matches; conform to /Perl/ rather than /POSIX/.
        validateMinConsumptionOfAlternatives    :: Bool         -- ^ When the number of repetitions of a /RegExDot.RegEx.CaptureGroup/ is precisely specified, check whether the resulting minimum data-requirement is available.
} deriving (Eq, Show)

instance Data.Default.Default ExecutionOptions  where
        def = setVerbose False $ ToolShed.Options.blankValue {
                abortTrialRepetitionsOnInherentFailure  = True,         -- Regrettably, this slightly reduces performance for most non-pathological patterns.
                catchIncompatibleAnchors                = True,
                checkExistenceOfInelasticTail           = True,
                checkForUnconsumableData                = True,         -- Expensive, particularly when (not requireMatchList), & only typically useful in failure-scenarios.
                moderateGreed                           = True,         -- Cost may exceed benefit. TODO: confirm.
                preferAlternativesWhichFeedTheGreedy    = True,
                preferAlternativesWhichMimickUnrolling  = True,
                preferFewerRepeatedAlternatives         = True,
                unrollRepeatedSingletonAlternative      = True,         -- Affects only efficiency, not the result.
                useFirstMatchAmongAlternatives          = False,        -- Perl-style matching may be faster, but may also yield a sub-optimal Match.
                validateMinConsumptionOfAlternatives    = False         -- The cost outweighs the small infrequent dividend.
        }

instance ToolShed.Options.Options ExecutionOptions      where
        blankValue      = MkExecutionOptions {
                abortTrialRepetitionsOnInherentFailure  = undefined,
                abortTrialRepetitionsOnZeroConsumption  = undefined,
                bypassInputDataForLiberalConsumer       = undefined,
                catchIncompatibleAnchors                = undefined,
                checkExistenceOfInelasticTail           = undefined,
                checkForUnconsumableData                = undefined,
                moderateGreed                           = undefined,
                permitReorderingOfAlternatives          = undefined,
                preferAlternativesWhichFeedTheGreedy    = undefined,
                preferAlternativesWhichMimickUnrolling  = undefined,
                preferFewerRepeatedAlternatives         = undefined,
                requireMatchList                        = undefined,
                unrollRepeatedSingletonAlternative      = undefined,
                useFirstMatchAmongAlternatives          = undefined,
                validateMinConsumptionOfAlternatives    = undefined
        }

-- | Sets those fields which depend crucially on whether the caller wants to retrieve any /RegExDot.RegEx.MatchList/ from the /RegExDot.RegEx.Result/, or just query whether there is one.
setVerbose :: Bool -> ExecutionOptions -> ExecutionOptions
setVerbose verbose e    = e {
        abortTrialRepetitionsOnZeroConsumption  = verbose,      -- The corresponding check, involves evaluation of a /RegExDot.RegEx.MatchList/, which is too expensive if the /RegExDot.RegEx.Matchlist/ isn't otherwise required.
        bypassInputDataForLiberalConsumer       = not verbose,  -- Potentially bypasses reading of /RegExDot.RegEx.InputData/, which is inappropriate if the mapping into a /RegExDot.RegEx.Result/ is required.
        permitReorderingOfAlternatives          = not verbose,  -- Doesn't help when 'requireMatchList', since an exhaustive search of /RegExDot.RegEx.Alternatives/, for the optimal solution, is performed.
        requireMatchList                        = verbose
}