module Codec.Xlsx.Types.AutoFilter where
import GHC.Generics (Generic)
import Control.Lens (makeLenses)
import Data.Default
import Data.Map (Map)
import Data.Maybe (catMaybes)
import qualified Data.Map as M
import Data.Text (Text)
import Text.XML
import Text.XML.Cursor
import Codec.Xlsx.Parser.Internal
import Codec.Xlsx.Types.Common
import Codec.Xlsx.Writer.Internal
data FilterColumn
= Filters { _fltValues :: [Text]}
| ACustomFilter CustomFilter
| CustomFiltersOr CustomFilter
CustomFilter
| CustomFiltersAnd CustomFilter
CustomFilter
deriving (Eq, Show, Generic)
data CustomFilter = CustomFilter
{ cfltOperator :: CustomFilterOperator
, cfltValue :: Text
} deriving (Eq, Show, Generic)
data CustomFilterOperator
= FltrEqual
| FltrGreaterThan
| FltrGreaterThanOrEqual
| FltrLessThan
| FltrLessThanOrEqual
| FltrNotEqual
deriving (Eq, Show, Generic)
data AutoFilter = AutoFilter
{ _afRef :: Maybe CellRef
, _afFilterColumns :: Map Int FilterColumn
} deriving (Eq, Show, Generic)
makeLenses ''AutoFilter
instance Default AutoFilter where
def = AutoFilter Nothing M.empty
instance FromCursor AutoFilter where
fromCursor cur = do
_afRef <- maybeAttribute "ref" cur
let _afFilterColumns = M.fromList $ cur $/ element (n_ "filterColumn") >=> \c -> do
colId <- fromAttribute "colId" c
fcol <- c $/ anyElement >=> fltColFromNode . node
return (colId, fcol)
return AutoFilter {..}
fltColFromNode :: Node -> [FilterColumn]
fltColFromNode n | n `nodeElNameIs` (n_ "filters") = do
let _fltValues = cur $/ element (n_ "filter") >=> fromAttribute "val"
return Filters{..}
| n `nodeElNameIs` (n_ "customFilters") = do
isAnd <- fromAttributeDef "and" False cur
let cFilters = cur $/ element (n_ "customFilter") >=> \c -> do
op <- fromAttributeDef "operator" FltrEqual c
val <- fromAttribute "val" c
return $ CustomFilter op val
case cFilters of
[f] ->
return $ ACustomFilter f
[f1, f2] ->
if isAnd
then return $ CustomFiltersAnd f1 f2
else return $ CustomFiltersOr f1 f2
_ ->
fail "bad custom filter"
| otherwise = fail "no matching nodes"
where
cur = fromNode n
instance FromAttrVal CustomFilterOperator where
fromAttrVal "equal" = readSuccess FltrEqual
fromAttrVal "greaterThan" = readSuccess FltrGreaterThan
fromAttrVal "greaterThanOrEqual" = readSuccess FltrGreaterThanOrEqual
fromAttrVal "lessThan" = readSuccess FltrLessThan
fromAttrVal "lessThanOrEqual" = readSuccess FltrLessThanOrEqual
fromAttrVal "notEqual" = readSuccess FltrNotEqual
fromAttrVal t = invalidText "CustomFilterOperator" t
instance ToElement AutoFilter where
toElement nm AutoFilter {..} =
elementList
nm
(catMaybes ["ref" .=? _afRef])
[ elementList
(n_ "filterColumn")
["colId" .= colId]
[fltColToElement fCol]
| (colId, fCol) <- M.toList _afFilterColumns
]
fltColToElement :: FilterColumn -> Element
fltColToElement Filters {..} =
elementListSimple
(n_ "filters")
[leafElement (n_ "filter") ["val" .= v] | v <- _fltValues]
fltColToElement (ACustomFilter f) =
elementListSimple (n_ "customFilters") [toElement (n_ "customFilter") f]
fltColToElement (CustomFiltersOr f1 f2) =
elementListSimple
(n_ "customFilters")
[toElement (n_ "customFilter") f | f <- [f1, f2]]
fltColToElement (CustomFiltersAnd f1 f2) =
elementList
(n_ "customFilters")
["and" .= True]
[toElement (n_ "customFilter") f | f <- [f1, f2]]
instance ToElement CustomFilter where
toElement nm CustomFilter {..} =
leafElement nm ["operator" .= cfltOperator, "val" .= cfltValue]
instance ToAttrVal CustomFilterOperator where
toAttrVal FltrEqual = "equal"
toAttrVal FltrGreaterThan = "greaterThan"
toAttrVal FltrGreaterThanOrEqual = "greaterThanOrEqual"
toAttrVal FltrLessThan = "lessThan"
toAttrVal FltrLessThanOrEqual = "lessThanOrEqual"
toAttrVal FltrNotEqual = "notEqual"