packages feed

squeeze-1.0.2.4: 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,
		bisectionRatio,
		includeEmpty,
		maximumBytes,
		minimumUsageRatio,
		verbose
	),
-- * Functions
	solutionSizeBounds,
--	minimumBytes,
	setVerbose,
-- ** Predicates
	withinSizeBounds
) where

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

{- |
	* Declare a record to contain command-line options.

	* This data-type is polymorphic, but the constraint is only applied at the level of individual functions.
-}
data CommandOptions ratio	= MkCommandOptions {
	bisectionRatio		:: ratio,		-- ^ The file-list is bisected at LHS/Total, and combinations from the LHS are concatenated with each of those from the RHS.
	includeEmpty		:: Bool,		-- ^ Whether empty directories or files should be included in any solution.
	maximumBytes		:: Data.File.FileSize,	-- ^ The maximum space (in bytes) available in which to store a subset of the specified files.
	minimumUsageRatio	:: ratio,		-- ^ The minimum acceptable usage of 'maximumBytes'.
	verbose			:: Bool			-- ^ Output ancillary information.
} deriving Show

instance Fractional f => ToolShed.Defaultable.Defaultable (CommandOptions f)	where
	defaultValue	= MkCommandOptions {
		bisectionRatio		= recip 2,	--Bisection the file-list into equal halves.
		includeEmpty		= False,
		maximumBytes		= 4700000000,	--DVD-size; just under 4.4GiB.
		minimumUsageRatio	= 99 / 100,	--99% full.
		verbose			= False
	}

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

-- | Derives the minimum number of bytes, from other options.
minimumBytes :: RealFrac f => CommandOptions f -> Data.File.FileSize
minimumBytes commandOptions	= floor $ minimumUsageRatio commandOptions * realToFrac (maximumBytes 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	= (minimumBytes commandOptions, maximumBytes commandOptions)

-- | Mutator.
setVerbose :: CommandOptions f -> CommandOptions f
setVerbose commandOptions	= commandOptions { verbose = True }

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