packages feed

squeeze-1.0.3.0: src/Squeeze/Data/CommandOptions.hs

{-
	Copyright (C) 2010 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 options for program-operation.

	* Defines an appropriate default value, which is expected to be over-ridden on the command-line.

	* Self-validates.
-}

module Squeeze.Data.CommandOptions(
-- * Types
-- ** Data-types
	CommandOptions(
--		MkCommandOptions,
		getIncludeEmpty,
		getMaybeRandomSeed,
		getMaximumBytes,
		getMinimumUsageRatio,
		getVerbosity
	),
-- * Functions
	solutionSizeBounds,
	deriveMinimumBytes,
-- ** Predicates
	isWithinSizeBounds
) where

import qualified	Distribution.Verbosity
import qualified	Factory.Data.Interval
import qualified	Squeeze.Data.File	as Data.File
import qualified	ToolShed.Defaultable
import qualified	ToolShed.SelfValidate

-- | Declares a record to contain command-line options.
data CommandOptions ratio	= MkCommandOptions {
	getIncludeEmpty		:: Bool,				-- ^ Whether empty directories or files should be included in any solution.
	getMaximumBytes		:: Data.File.FileSize,			-- ^ The maximum space (in bytes) available in which to store a subset of the specified files.
	getMaybeRandomSeed	:: Maybe Int,				-- ^ Optionally seed the random-number generator to produce a repeatable pseudo-random sequence.
	getMinimumUsageRatio	:: ratio,				-- ^ The minimum acceptable usage of 'getMaximumBytes'.
	getVerbosity		:: Distribution.Verbosity.Verbosity	-- ^ Set the threshold for ancillary information-output.
} deriving Show

instance Fractional f => ToolShed.Defaultable.Defaultable (CommandOptions f)	where
	defaultValue	= MkCommandOptions {
		getIncludeEmpty		= False,
		getMaximumBytes		= 4700000000,	--DVD-size; just under 4.4GiB.
		getMaybeRandomSeed	= Nothing,
		getMinimumUsageRatio	= 99 / 100,	--99% full.
		getVerbosity		= Distribution.Verbosity.normal
	}

instance (Num ratio, Ord ratio, Show ratio) => ToolShed.SelfValidate.SelfValidator (CommandOptions ratio)	where
	getErrors commandOptions	= map snd $ filter (($ commandOptions) . fst) [
		((< 0) . getMaximumBytes,	"Invalid maximumBytes=" ++ show (getMaximumBytes commandOptions) ++ "."),
		((< 0) . getMinimumUsageRatio,	"Invalid minimumUsageRatio='" ++ show (getMinimumUsageRatio commandOptions) ++ "'."),
		((> 1) . getMinimumUsageRatio,	"Invalid minimumUsageRatio='" ++ show (getMinimumUsageRatio commandOptions) ++ "'.")
	 ]

-- | Derives the minimum number of bytes, from other options.
deriveMinimumBytes :: RealFrac f => CommandOptions f -> Data.File.FileSize
deriveMinimumBytes commandOptions	= floor $ getMinimumUsageRatio commandOptions * realToFrac (getMaximumBytes commandOptions)

-- | The bounds on the aggregate size of the set of files.
solutionSizeBounds :: RealFrac f => CommandOptions f -> Factory.Data.Interval.Interval Data.File.FileSize
solutionSizeBounds commandOptions	= (deriveMinimumBytes commandOptions, getMaximumBytes commandOptions)

-- | Whether a file of the specified size is an acceptable component of any solution.
isWithinSizeBounds :: CommandOptions f -> Data.File.FileSize -> Bool
isWithinSizeBounds commandOptions size	= all ($ size) [
	if getIncludeEmpty commandOptions
		then (>= 0)
		else (> 0),
	(<= getMaximumBytes commandOptions)
 ]