>
> module ItemEntry
>   (makeItemTuple,
>    displayItemTuple,
>    normalizeItemEntry)
>   where
>   import SequenceUtilities(pam)
>   import IOutilities(trim, realFloatFromString,
>                      standardFormatRealFloat)
>   import DataEntryUtilities(spaceAfterComma, removeTrailingCommas,
>                             blank, comma, decimalPt, dollarSign)

function: normalizeItemEntry
convert string containing item entry to standard form

>   normalizeItemEntry :: String -> String
>   normalizeItemEntry = displayItemTuple . makeItemTuple


function: displayItemTuple
form display string from item tuple

>   displayItemTuple :: (String, String, String, Float) -> String
>   displayItemTuple(item, color, size, price) =
>     item ++ separator ++ color ++ separator ++ size ++ separator ++
>       [dollarSign] ++ standardFormatRealFloat 2 price


function: makeItemTuple
convert string containing an item entry to an item tuple
Notes: Assumes item comes first, but color, size, and price can be
       in any order, and any of them may be missing
       Item returned as is, except spaces added after commas if missing

>   makeItemTuple :: String -> (String, String, String, Float)
>   makeItemTuple entry =
>     (removeTrailingCommas item, color, size, priceAsFloat)
>     where
>     colorSizeAndPrice = (map cook . take 3) entryWordsReversed
>     [color, size, price] =
>        pam [getColor, getSize, getPrice] colorSizeAndPrice
>     numberPresent =
>       (length . filter(/= missingDataSignal))[color, size, price]
>     item = (unwords . reverse . drop numberPresent) entryWordsReversed
>     priceAsFloat
>       | price /= missingDataSignal   = realFloatFromString price
>       | otherwise                    = missingPriceSignal
>     entryWordsReversed = (reverse . words . spaceAfterComma) entry


function: getColor
find color among components of entry

>   getColor :: [String] -> String
>   getColor =
>     translateKeyThatMatchesTable missingDataSignal colorTable


function: getSize
find size among components of entry

>   getSize :: [String] -> String
>   getSize =
>     translateKeyThatMatchesTable missingDataSignal sizeTable


function: getPrice
find price among components of entry

>   getPrice :: [String] -> String
>   getPrice components
>     | null hereItIs   = missingDataSignal
>     | otherwise       = head hereItIs
>     where
>     hereItIs = (dropWhile(not . isPrice) .
>                         map(dropIfDollarSign)) components


function: isPrice
True iff argument is a string containing digits only, or
digits with a trailing or embedded decimal point

>   isPrice :: String -> Bool
>   isPrice string = all isDigit (beforeDecimalPt ++ afterDecimalPt)
>     where
>     (beforeDecimalPt, decimalPtAndBeyond) =
>       break (== decimalPt) string
>     afterDecimalPt = drop 1 decimalPtAndBeyond


function: translateKeyThatMatchesTable
find key that appears in table and deliver translation

>   translateKeyThatMatchesTable ::
>     (Eq t, Show t, Eq k) => t -> [(k, t)] -> [k] -> t
>   translateKeyThatMatchesTable noMatchesSignal table keys
>     | null hereItIs  = noMatchesSignal
>     | otherwise      = head hereItIs
>     where
>     hereItIs = dropWhile (== noMatchesSignal) keyTranslations
>     keyTranslations = 
>       map (maybe noMatchesSignal id) [lookup key table | key <- keys]
>     violation =
>       error("access violation, translateKeyThatMatchesTable: " ++
>             show hereItIs)


function: cook
remove leading and trailing blanks and trailing commas
and make all characters lower case

>   cook :: String -> String
>   cook = map toLower . removeTrailingCommas . trim


function: dropIfDollarSign
drop first character if it is a dollar sign

>   dropIfDollarSign :: String -> String
>   dropIfDollarSign string
>     | null string                = string
>     | head string /= dollarSign  = string
>     | otherwise                  = tail string


variable: missingPriceSignal
string to indicate missing component of entry

>   missingPriceSignal :: Float
>   missingPriceSignal = -99.99


variable: missingDataSignal
string to indicate missing component of entry

>   missingDataSignal :: String
>   missingDataSignal = "MISSING"


variable: colorTable
list of accepted colors in form of lookup table

>   colorTable :: [(String, String)]
>   colorTable = zip colors colors
>     where
>     colors = words("red orange yellow green blue purple " ++
>                    "black white brown puce")


variable: sizeTable
table of accepted sizes paired with their standard notations

>   sizeTable :: [(String, String)]
>   sizeTable = zip sizes standardSizeNotations
>     where
>     sizes = words("s small sm m medium med l large lg " ++
>                   "xl extra-large xxl double-x")
>     standardSizeNotations = words "S S S M M M L L L XL XL XXL XXL"


variable: separator
string to separate components of normalized item entry

>   separator :: String
>   separator = ", "   


------------------  unit testing --------------------

>   tst1 = makeItemTuple "shirt, red, L, $12.95"
>   tst2 = makeItemTuple "shirt and $Pants, red, L, $49"
>   tst3 = makeItemTuple "shirt and $Pants, ReD, Large, $49"
>   tst4 = makeItemTuple "shirt and $Pants, ReD, extra-Large, $49"
>   tst5 = makeItemTuple "shirt and $Pants, gray, extra-Large, $49"
>   tst6 = makeItemTuple "shirt and $Pants, gray, extra-Large, "
>   tst7 = makeItemTuple "shirt and $Pants, gray, $49, extra-Large"
>   tst8 = makeItemTuple "shirt and $Pants, extra-Large, red, $49"
>   tst9 = makeItemTuple "shirt and $Pants, extra-Large, $49, red"

>   est1 = normalizeItemEntry "shirt, red, L, $12.95"
>   est2 = normalizeItemEntry "shirt and $Pants, red, L, $49"
>   est3 = normalizeItemEntry "shirt and $Pants, ReD, Large, $49"
>   est4 = normalizeItemEntry "shirt and $Pants, ReD, extra-Large, $49"
>   est5 = normalizeItemEntry "shirt and $Pants, gray, extra-Large, $49"
>   est6 = normalizeItemEntry "shirt and $Pants, gray, extra-Large, "
>   est7 = normalizeItemEntry "shirt and $Pants, gray, $49, extra-Large"
>   est8 = normalizeItemEntry "shirt and $Pants, extra-Large, red, $49"
>   est9 = normalizeItemEntry "shirt and $Pants, extra-Large, $49, red"
Last Modified: