    {-# LANGUAGE OverloadedStrings #-}
    {-# LANGUAGE RecordWildCards #-}
    {-# LANGUAGE DeriveGeneric #-}
    module Codec.Xlsx.Writer.Internal.PivotTable
      ( PivotTableFiles(..)
      , renderPivotTableFiles
      ) where

    import Data.ByteString.Lazy (ByteString)
    import Data.List (elemIndex, transpose)
    import Data.List.Extra (nubOrd)
    import qualified Data.Map as M
    import Data.Maybe (catMaybes, fromMaybe, mapMaybe)
    import Data.Text (Text)
    import GHC.Generics (Generic)
    import Safe (fromJustNote)
    import Text.XML

    import Codec.Xlsx.Types.Cell
    import Codec.Xlsx.Types.Common
    import Codec.Xlsx.Types.Internal
    import Codec.Xlsx.Types.Internal.Relationships (odr)
    import Codec.Xlsx.Types.PivotTable
    import Codec.Xlsx.Types.PivotTable.Internal
    import Codec.Xlsx.Writer.Internal

    data PivotTableFiles = PivotTableFiles
      { PivotTableFiles -> ByteString
    pvtfTable :: ByteString
      , PivotTableFiles -> ByteString
    pvtfCacheDefinition :: ByteString
      , PivotTableFiles -> ByteString
    pvtfCacheRecords :: ByteString
      } deriving (PivotTableFiles -> PivotTableFiles -> Bool
    (PivotTableFiles -> PivotTableFiles -> Bool)
    -> (PivotTableFiles -> PivotTableFiles -> Bool)
    -> Eq PivotTableFiles
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: PivotTableFiles -> PivotTableFiles -> Bool
    == :: PivotTableFiles -> PivotTableFiles -> Bool
    $c/= :: PivotTableFiles -> PivotTableFiles -> Bool
    /= :: PivotTableFiles -> PivotTableFiles -> Bool
    Eq, Int -> PivotTableFiles -> ShowS
    [PivotTableFiles] -> ShowS
    PivotTableFiles -> String
    (Int -> PivotTableFiles -> ShowS)
    -> (PivotTableFiles -> String)
    -> ([PivotTableFiles] -> ShowS)
    -> Show PivotTableFiles
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> PivotTableFiles -> ShowS
    showsPrec :: Int -> PivotTableFiles -> ShowS
    $cshow :: PivotTableFiles -> String
    show :: PivotTableFiles -> String
    $cshowList :: [PivotTableFiles] -> ShowS
    showList :: [PivotTableFiles] -> ShowS
    Show, (forall x. PivotTableFiles -> Rep PivotTableFiles x)
    -> (forall x. Rep PivotTableFiles x -> PivotTableFiles)
    -> Generic PivotTableFiles
    forall x. Rep PivotTableFiles x -> PivotTableFiles
    forall x. PivotTableFiles -> Rep PivotTableFiles x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    $cfrom :: forall x. PivotTableFiles -> Rep PivotTableFiles x
    from :: forall x. PivotTableFiles -> Rep PivotTableFiles x
    $cto :: forall x. Rep PivotTableFiles x -> PivotTableFiles
    to :: forall x. Rep PivotTableFiles x -> PivotTableFiles
    Generic)

    data CacheDefinition = CacheDefinition
      { CacheDefinition -> CellRef
    cdSourceRef :: CellRef
      , CacheDefinition -> Text
    cdSourceSheet :: Text
      , CacheDefinition -> [CacheField]
    cdFields :: [CacheField]
      } deriving (CacheDefinition -> CacheDefinition -> Bool
    (CacheDefinition -> CacheDefinition -> Bool)
    -> (CacheDefinition -> CacheDefinition -> Bool)
    -> Eq CacheDefinition
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: CacheDefinition -> CacheDefinition -> Bool
    == :: CacheDefinition -> CacheDefinition -> Bool
    $c/= :: CacheDefinition -> CacheDefinition -> Bool
    /= :: CacheDefinition -> CacheDefinition -> Bool
    Eq, Int -> CacheDefinition -> ShowS
    [CacheDefinition] -> ShowS
    CacheDefinition -> String
    (Int -> CacheDefinition -> ShowS)
    -> (CacheDefinition -> String)
    -> ([CacheDefinition] -> ShowS)
    -> Show CacheDefinition
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> CacheDefinition -> ShowS
    showsPrec :: Int -> CacheDefinition -> ShowS
    $cshow :: CacheDefinition -> String
    show :: CacheDefinition -> String
    $cshowList :: [CacheDefinition] -> ShowS
    showList :: [CacheDefinition] -> ShowS
    Show, (forall x. CacheDefinition -> Rep CacheDefinition x)
    -> (forall x. Rep CacheDefinition x -> CacheDefinition)
    -> Generic CacheDefinition
    forall x. Rep CacheDefinition x -> CacheDefinition
    forall x. CacheDefinition -> Rep CacheDefinition x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    $cfrom :: forall x. CacheDefinition -> Rep CacheDefinition x
    from :: forall x. CacheDefinition -> Rep CacheDefinition x
    $cto :: forall x. Rep CacheDefinition x -> CacheDefinition
    to :: forall x. Rep CacheDefinition x -> CacheDefinition
    Generic)

    renderPivotTableFiles :: CellMap -> Int -> PivotTable -> PivotTableFiles
    renderPivotTableFiles :: CellMap -> Int -> PivotTable -> PivotTableFiles
    renderPivotTableFiles CellMap
    cm Int
    cacheId PivotTable
    t = PivotTableFiles {ByteString
    pvtfTable :: ByteString
    pvtfCacheDefinition :: ByteString
    pvtfCacheRecords :: ByteString
    pvtfTable :: ByteString
    pvtfCacheDefinition :: ByteString
    pvtfCacheRecords :: ByteString
    ..}
      where
        pvtfTable :: ByteString
    pvtfTable = RenderSettings -> Document -> ByteString
    renderLBS RenderSettings
    forall a. Default a => a
    def (Document -> ByteString) -> Document -> ByteString
    forall a b. (a -> b) -> a -> b
    $ Int -> CacheDefinition -> PivotTable -> Document
    ptDefinitionDocument Int
    cacheId CacheDefinition
    cache PivotTable
    t
        cache :: CacheDefinition
    cache = CellMap -> PivotTable -> CacheDefinition
    generateCache CellMap
    cm PivotTable
    t
        (Document
    cacheDoc, Document
    cacheRecordsDoc) = CacheDefinition -> (Document, Document)
    writeCache CacheDefinition
    cache
        pvtfCacheDefinition :: ByteString
    pvtfCacheDefinition = RenderSettings -> Document -> ByteString
    renderLBS RenderSettings
    forall a. Default a => a
    def Document
    cacheDoc
        pvtfCacheRecords :: ByteString
    pvtfCacheRecords = RenderSettings -> Document -> ByteString
    renderLBS RenderSettings
    forall a. Default a => a
    def Document
    cacheRecordsDoc

    ptDefinitionDocument :: Int -> CacheDefinition -> PivotTable -> Document
    ptDefinitionDocument :: Int -> CacheDefinition -> PivotTable -> Document
    ptDefinitionDocument Int
    cacheId CacheDefinition
    cache PivotTable
    t =
        Text -> Element -> Document
    documentFromElement Text
    "Pivot table generated by xlsx" (Element -> Document) -> Element -> Document
    forall a b. (a -> b) -> a -> b
    $
        Name -> Int -> CacheDefinition -> PivotTable -> Element
    ptDefinitionElement Name
    "pivotTableDefinition" Int
    cacheId CacheDefinition
    cache PivotTable
    t

    ptDefinitionElement :: Name -> Int -> CacheDefinition -> PivotTable -> Element
    ptDefinitionElement :: Name -> Int -> CacheDefinition -> PivotTable -> Element
    ptDefinitionElement Name
    nm Int
    cacheId CacheDefinition
    cache PivotTable {Bool
    [DataField]
    [PositionedField]
    [PivotFieldInfo]
    Text
    CellRef
    _pvtName :: Text
    _pvtDataCaption :: Text
    _pvtRowFields :: [PositionedField]
    _pvtColumnFields :: [PositionedField]
    _pvtDataFields :: [DataField]
    _pvtFields :: [PivotFieldInfo]
    _pvtRowGrandTotals :: Bool
    _pvtColumnGrandTotals :: Bool
    _pvtOutline :: Bool
    _pvtOutlineData :: Bool
    _pvtLocation :: CellRef
    _pvtSrcSheet :: Text
    _pvtSrcRef :: CellRef
    _pvtSrcRef :: PivotTable -> CellRef
    _pvtSrcSheet :: PivotTable -> Text
    _pvtLocation :: PivotTable -> CellRef
    _pvtOutlineData :: PivotTable -> Bool
    _pvtOutline :: PivotTable -> Bool
    _pvtColumnGrandTotals :: PivotTable -> Bool
    _pvtRowGrandTotals :: PivotTable -> Bool
    _pvtFields :: PivotTable -> [PivotFieldInfo]
    _pvtDataFields :: PivotTable -> [DataField]
    _pvtColumnFields :: PivotTable -> [PositionedField]
    _pvtRowFields :: PivotTable -> [PositionedField]
    _pvtDataCaption :: PivotTable -> Text
    _pvtName :: PivotTable -> Text
    ..} =
      Name -> [(Name, Text)] -> [Element] -> Element
    elementList Name
    nm [(Name, Text)]
    attrs [Element]
    elements
      where
        attrs :: [(Name, Text)]
    attrs =
          [Maybe (Name, Text)] -> [(Name, Text)]
    forall a. [Maybe a] -> [a]
    catMaybes
            [ Name
    "colGrandTotals" Name -> Maybe Bool -> Maybe (Name, Text)
    forall a. ToAttrVal a => Name -> Maybe a -> Maybe (Name, Text)
    .=? Bool -> Maybe Bool
    justFalse Bool
    _pvtColumnGrandTotals
            , Name
    "rowGrandTotals" Name -> Maybe Bool -> Maybe (Name, Text)
    forall a. ToAttrVal a => Name -> Maybe a -> Maybe (Name, Text)
    .=? Bool -> Maybe Bool
    justFalse Bool
    _pvtRowGrandTotals
            , Name
    "outline" Name -> Maybe Bool -> Maybe (Name, Text)
    forall a. ToAttrVal a => Name -> Maybe a -> Maybe (Name, Text)
    .=? Bool -> Maybe Bool
    justTrue Bool
    _pvtOutline
            , Name
    "outlineData" Name -> Maybe Bool -> Maybe (Name, Text)
    forall a. ToAttrVal a => Name -> Maybe a -> Maybe (Name, Text)
    .=? Bool -> Maybe Bool
    justTrue Bool
    _pvtOutlineData
            ] [(Name, Text)] -> [(Name, Text)] -> [(Name, Text)]
    forall a. [a] -> [a] -> [a]
    ++
          [ Name
    "name" Name -> Text -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= Text
    _pvtName
          , Name
    "dataCaption" Name -> Text -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= Text
    _pvtDataCaption
          , Name
    "cacheId" Name -> Int -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= Int
    cacheId
          , Name
    "dataOnRows" Name -> Bool -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= (PositionedField
    DataPosition PositionedField -> [PositionedField] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` [PositionedField]
    _pvtRowFields)
          ]
        elements :: [Element]
    elements = [Element
    location, Element
    pivotFields, Element
    rowFields, Element
    colFields, Element
    dataFields]
        location :: Element
    location =
          Name -> [(Name, Text)] -> Element
    leafElement
            Name
    "location"
            [ Name
    "ref" Name -> CellRef -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= CellRef
    _pvtLocation
              -- TODO : set proper
            , Name
    "firstHeaderRow" Name -> Int -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= (Int
    1 :: Int)
            , Name
    "firstDataRow" Name -> Int -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= (Int
    2 :: Int)
            , Name
    "firstDataCol" Name -> Int -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= (Int
    1 :: Int)
            ]
        name2x :: Map PivotFieldName Int
    name2x = [(PivotFieldName, Int)] -> Map PivotFieldName Int
    forall k a. Ord k => [(k, a)] -> Map k a
    M.fromList ([(PivotFieldName, Int)] -> Map PivotFieldName Int)
    -> [(PivotFieldName, Int)] -> Map PivotFieldName Int
    forall a b. (a -> b) -> a -> b
    $ [PivotFieldName] -> [Int] -> [(PivotFieldName, Int)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip ((PivotFieldInfo -> Maybe PivotFieldName)
    -> [PivotFieldInfo] -> [PivotFieldName]
    forall a b. (a -> Maybe b) -> [a] -> [b]
    mapMaybe PivotFieldInfo -> Maybe PivotFieldName
    _pfiName [PivotFieldInfo]
    _pvtFields) [Int
    0 ..]
        mapFieldToX :: PivotFieldName -> Int
    mapFieldToX PivotFieldName
    f = String -> Maybe Int -> Int
    forall a. Partial => String -> Maybe a -> a
    fromJustNote String
    "no field" (Maybe Int -> Int) -> Maybe Int -> Int
    forall a b. (a -> b) -> a -> b
    $ PivotFieldName -> Map PivotFieldName Int -> Maybe Int
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup PivotFieldName
    f Map PivotFieldName Int
    name2x
        pivotFields :: Element
    pivotFields = Name -> [Element] -> Element
    elementListSimple Name
    "pivotFields" ([Element] -> Element) -> [Element] -> Element
    forall a b. (a -> b) -> a -> b
    $ (PivotFieldInfo -> Element) -> [PivotFieldInfo] -> [Element]
    forall a b. (a -> b) -> [a] -> [b]
    map PivotFieldInfo -> Element
    pFieldEl [PivotFieldInfo]
    _pvtFields
        maybeFieldIn :: Maybe PivotFieldName -> t PositionedField -> Bool
    maybeFieldIn Maybe PivotFieldName
    Nothing t PositionedField
    _ = Bool
    False
        maybeFieldIn (Just PivotFieldName
    name) t PositionedField
    positions = PivotFieldName -> PositionedField
    FieldPosition PivotFieldName
    name PositionedField -> t PositionedField -> Bool
    forall a. Eq a => a -> t a -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` t PositionedField
    positions
        pFieldEl :: PivotFieldInfo -> Element
    pFieldEl PivotFieldInfo { _pfiName :: PivotFieldInfo -> Maybe PivotFieldName
    _pfiName = Maybe PivotFieldName
    fName
                                , _pfiOutline :: PivotFieldInfo -> Bool
    _pfiOutline = Bool
    outline
                                , _pfiSortType :: PivotFieldInfo -> FieldSortType
    _pfiSortType = FieldSortType
    sortType
                                , _pfiHiddenItems :: PivotFieldInfo -> [CellValue]
    _pfiHiddenItems = [CellValue]
    hidden
                                }
          | Maybe PivotFieldName
    fName Maybe PivotFieldName -> [PositionedField] -> Bool
    forall {t :: * -> *}.
    Foldable t =>
    Maybe PivotFieldName -> t PositionedField -> Bool
    `maybeFieldIn` [PositionedField]
    _pvtRowFields =
            Maybe PivotFieldName
    -> Bool -> Text -> [CellValue] -> FieldSortType -> Element
    forall {a} {a} {t :: * -> *}.
    (ToAttrVal a, ToAttrVal a, Foldable t) =>
    Maybe PivotFieldName
    -> a -> a -> t CellValue -> FieldSortType -> Element
    pFieldEl' Maybe PivotFieldName
    fName Bool
    outline (Text
    "axisRow" :: Text) [CellValue]
    hidden FieldSortType
    sortType
          | Maybe PivotFieldName
    fName Maybe PivotFieldName -> [PositionedField] -> Bool
    forall {t :: * -> *}.
    Foldable t =>
    Maybe PivotFieldName -> t PositionedField -> Bool
    `maybeFieldIn` [PositionedField]
    _pvtColumnFields =
            Maybe PivotFieldName
    -> Bool -> Text -> [CellValue] -> FieldSortType -> Element
    forall {a} {a} {t :: * -> *}.
    (ToAttrVal a, ToAttrVal a, Foldable t) =>
    Maybe PivotFieldName
    -> a -> a -> t CellValue -> FieldSortType -> Element
    pFieldEl' Maybe PivotFieldName
    fName Bool
    outline (Text
    "axisCol" :: Text) [CellValue]
    hidden FieldSortType
    sortType
          | Bool
    otherwise =
            Name -> [(Name, Text)] -> Element
    leafElement Name
    "pivotField" ([(Name, Text)] -> Element) -> [(Name, Text)] -> Element
    forall a b. (a -> b) -> a -> b
    $
            [ Name
    "dataField" Name -> Bool -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= Bool
    True
            , Name
    "showAll" Name -> Bool -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= Bool
    False
            , Name
    "outline" Name -> Bool -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= Bool
    outline] [(Name, Text)] -> [(Name, Text)] -> [(Name, Text)]
    forall a. [a] -> [a] -> [a]
    ++
            [Maybe (Name, Text)] -> [(Name, Text)]
    forall a. [Maybe a] -> [a]
    catMaybes [Name
    "name" Name -> Maybe PivotFieldName -> Maybe (Name, Text)
    forall a. ToAttrVal a => Name -> Maybe a -> Maybe (Name, Text)
    .=? Maybe PivotFieldName
    fName]
        pFieldEl' :: Maybe PivotFieldName
    -> a -> a -> t CellValue -> FieldSortType -> Element
    pFieldEl' Maybe PivotFieldName
    fName a
    outline a
    axis t CellValue
    hidden FieldSortType
    sortType =
          Name -> [(Name, Text)] -> [Element] -> Element
    elementList
            Name
    "pivotField"
            ([ Name
    "axis" Name -> a -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= a
    axis
             , Name
    "showAll" Name -> Bool -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= Bool
    False
             , Name
    "outline" Name -> a -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= a
    outline
             ] [(Name, Text)] -> [(Name, Text)] -> [(Name, Text)]
    forall a. [a] -> [a] -> [a]
    ++
             [Maybe (Name, Text)] -> [(Name, Text)]
    forall a. [Maybe a] -> [a]
    catMaybes [ Name
    "name" Name -> Maybe PivotFieldName -> Maybe (Name, Text)
    forall a. ToAttrVal a => Name -> Maybe a -> Maybe (Name, Text)
    .=? Maybe PivotFieldName
    fName
                       , Name
    "sortType" Name -> Maybe FieldSortType -> Maybe (Name, Text)
    forall a. ToAttrVal a => Name -> Maybe a -> Maybe (Name, Text)
    .=? FieldSortType -> FieldSortType -> Maybe FieldSortType
    forall a. Eq a => a -> a -> Maybe a
    justNonDef FieldSortType
    FieldSortManual FieldSortType
    sortType])
            [ Name -> [Element] -> Element
    elementListSimple Name
    "items" ([Element] -> Element) -> [Element] -> Element
    forall a b. (a -> b) -> a -> b
    $
              Maybe PivotFieldName -> t CellValue -> [Element]
    forall {t :: * -> *}.
    Foldable t =>
    Maybe PivotFieldName -> t CellValue -> [Element]
    items Maybe PivotFieldName
    fName t CellValue
    hidden [Element] -> [Element] -> [Element]
    forall a. [a] -> [a] -> [a]
    ++
              [Name -> [(Name, Text)] -> Element
    leafElement Name
    "item" [Name
    "t" Name -> Text -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= (Text
    "default" :: Text)]]
            ]
        items :: Maybe PivotFieldName -> t CellValue -> [Element]
    items Maybe PivotFieldName
    Nothing t CellValue
    _ = []
        items (Just PivotFieldName
    fName) t CellValue
    hidden =
          [ Int -> CellValue -> t CellValue -> Element
    forall {t :: * -> *} {a}.
    (Foldable t, Eq a) =>
    Int -> a -> t a -> Element
    itemEl Int
    x CellValue
    item t CellValue
    hidden
          | (Int
    x, CellValue
    item) <- [Int] -> [CellValue] -> [(Int, CellValue)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip [Int
    0 ..] ([CellValue] -> [(Int, CellValue)])
    -> (Maybe [CellValue] -> [CellValue])
    -> Maybe [CellValue]
    -> [(Int, CellValue)]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [CellValue] -> Maybe [CellValue] -> [CellValue]
    forall a. a -> Maybe a -> a
    fromMaybe [] (Maybe [CellValue] -> [(Int, CellValue)])
    -> Maybe [CellValue] -> [(Int, CellValue)]
    forall a b. (a -> b) -> a -> b
    $ PivotFieldName
    -> Map PivotFieldName [CellValue] -> Maybe [CellValue]
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup PivotFieldName
    fName Map PivotFieldName [CellValue]
    cachedItems
          ]
        itemEl :: Int -> a -> t a -> Element
    itemEl Int
    x a
    item t a
    hidden =
          Name -> [(Name, Text)] -> Element
    leafElement Name
    "item" ([(Name, Text)] -> Element) -> [(Name, Text)] -> Element
    forall a b. (a -> b) -> a -> b
    $
          [Name
    "x" Name -> Int -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= (Int
    x :: Int)] [(Name, Text)] -> [(Name, Text)] -> [(Name, Text)]
    forall a. [a] -> [a] -> [a]
    ++ [Maybe (Name, Text)] -> [(Name, Text)]
    forall a. [Maybe a] -> [a]
    catMaybes [Name
    "h" Name -> Maybe Bool -> Maybe (Name, Text)
    forall a. ToAttrVal a => Name -> Maybe a -> Maybe (Name, Text)
    .=? Bool -> Maybe Bool
    justTrue (a
    item a -> t a -> Bool
    forall a. Eq a => a -> t a -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` t a
    hidden)]
        cachedItems :: Map PivotFieldName [CellValue]
    cachedItems =
          [(PivotFieldName, [CellValue])] -> Map PivotFieldName [CellValue]
    forall k a. Ord k => [(k, a)] -> Map k a
    M.fromList ([(PivotFieldName, [CellValue])] -> Map PivotFieldName [CellValue])
    -> [(PivotFieldName, [CellValue])]
    -> Map PivotFieldName [CellValue]
    forall a b. (a -> b) -> a -> b
    $ [(PivotFieldName
    cfName, [CellValue]
    cfItems) | CacheField {[CellValue]
    PivotFieldName
    cfName :: PivotFieldName
    cfItems :: [CellValue]
    cfItems :: CacheField -> [CellValue]
    cfName :: CacheField -> PivotFieldName
    ..} <- CacheDefinition -> [CacheField]
    cdFields CacheDefinition
    cache]
        rowFields :: Element
    rowFields =
          Name -> [Element] -> Element
    elementListSimple Name
    "rowFields" ([Element] -> Element)
    -> ([PositionedField] -> [Element]) -> [PositionedField] -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (PositionedField -> Element) -> [PositionedField] -> [Element]
    forall a b. (a -> b) -> [a] -> [b]
    map PositionedField -> Element
    fieldEl ([PositionedField] -> Element) -> [PositionedField] -> Element
    forall a b. (a -> b) -> a -> b
    $
          if [DataField] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [DataField]
    _pvtDataFields Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    1
            then [PositionedField]
    _pvtRowFields
            else (PositionedField -> Bool) -> [PositionedField] -> [PositionedField]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (PositionedField -> PositionedField -> Bool
    forall a. Eq a => a -> a -> Bool
    /= PositionedField
    DataPosition) [PositionedField]
    _pvtRowFields
        colFields :: Element
    colFields = Name -> [Element] -> Element
    elementListSimple Name
    "colFields" ([Element] -> Element) -> [Element] -> Element
    forall a b. (a -> b) -> a -> b
    $ (PositionedField -> Element) -> [PositionedField] -> [Element]
    forall a b. (a -> b) -> [a] -> [b]
    map PositionedField -> Element
    fieldEl [PositionedField]
    _pvtColumnFields
        fieldEl :: PositionedField -> Element
    fieldEl PositionedField
    p = Name -> [(Name, Text)] -> Element
    leafElement Name
    "field" [Name
    "x" Name -> Int -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= PositionedField -> Int
    fieldPos PositionedField
    p]
        fieldPos :: PositionedField -> Int
    fieldPos PositionedField
    DataPosition = (-Int
    2) :: Int
        fieldPos (FieldPosition PivotFieldName
    f) = PivotFieldName -> Int
    mapFieldToX PivotFieldName
    f
        dataFields :: Element
    dataFields = Name -> [Element] -> Element
    elementListSimple Name
    "dataFields" ([Element] -> Element) -> [Element] -> Element
    forall a b. (a -> b) -> a -> b
    $ (DataField -> Element) -> [DataField] -> [Element]
    forall a b. (a -> b) -> [a] -> [b]
    map DataField -> Element
    dFieldEl [DataField]
    _pvtDataFields
        dFieldEl :: DataField -> Element
    dFieldEl DataField {Text
    ConsolidateFunction
    PivotFieldName
    _dfField :: PivotFieldName
    _dfName :: Text
    _dfFunction :: ConsolidateFunction
    _dfFunction :: DataField -> ConsolidateFunction
    _dfName :: DataField -> Text
    _dfField :: DataField -> PivotFieldName
    ..} =
          Name -> [(Name, Text)] -> Element
    leafElement Name
    "dataField" ([(Name, Text)] -> Element) -> [(Name, Text)] -> Element
    forall a b. (a -> b) -> a -> b
    $
          [Maybe (Name, Text)] -> [(Name, Text)]
    forall a. [Maybe a] -> [a]
    catMaybes
            [ Name
    "name" Name -> Maybe Text -> Maybe (Name, Text)
    forall a. ToAttrVal a => Name -> Maybe a -> Maybe (Name, Text)
    .=? Text -> Maybe Text
    forall a. a -> Maybe a
    Just Text
    _dfName
            , Name
    "fld" Name -> Maybe Int -> Maybe (Name, Text)
    forall a. ToAttrVal a => Name -> Maybe a -> Maybe (Name, Text)
    .=? Int -> Maybe Int
    forall a. a -> Maybe a
    Just (PivotFieldName -> Int
    mapFieldToX PivotFieldName
    _dfField)
            , Name
    "subtotal" Name -> Maybe ConsolidateFunction -> Maybe (Name, Text)
    forall a. ToAttrVal a => Name -> Maybe a -> Maybe (Name, Text)
    .=? ConsolidateFunction
    -> ConsolidateFunction -> Maybe ConsolidateFunction
    forall a. Eq a => a -> a -> Maybe a
    justNonDef ConsolidateFunction
    ConsolidateSum ConsolidateFunction
    _dfFunction
            ]

    generateCache :: CellMap -> PivotTable -> CacheDefinition
    generateCache :: CellMap -> PivotTable -> CacheDefinition
    generateCache CellMap
    cm PivotTable {Bool
    [DataField]
    [PositionedField]
    [PivotFieldInfo]
    Text
    CellRef
    _pvtSrcRef :: PivotTable -> CellRef
    _pvtSrcSheet :: PivotTable -> Text
    _pvtLocation :: PivotTable -> CellRef
    _pvtOutlineData :: PivotTable -> Bool
    _pvtOutline :: PivotTable -> Bool
    _pvtColumnGrandTotals :: PivotTable -> Bool
    _pvtRowGrandTotals :: PivotTable -> Bool
    _pvtFields :: PivotTable -> [PivotFieldInfo]
    _pvtDataFields :: PivotTable -> [DataField]
    _pvtColumnFields :: PivotTable -> [PositionedField]
    _pvtRowFields :: PivotTable -> [PositionedField]
    _pvtDataCaption :: PivotTable -> Text
    _pvtName :: PivotTable -> Text
    _pvtName :: Text
    _pvtDataCaption :: Text
    _pvtRowFields :: [PositionedField]
    _pvtColumnFields :: [PositionedField]
    _pvtDataFields :: [DataField]
    _pvtFields :: [PivotFieldInfo]
    _pvtRowGrandTotals :: Bool
    _pvtColumnGrandTotals :: Bool
    _pvtOutline :: Bool
    _pvtOutlineData :: Bool
    _pvtLocation :: CellRef
    _pvtSrcSheet :: Text
    _pvtSrcRef :: CellRef
    ..} =
      CacheDefinition
      { cdSourceRef :: CellRef
    cdSourceRef = CellRef
    _pvtSrcRef
      , cdSourceSheet :: Text
    cdSourceSheet = Text
    _pvtSrcSheet
      , cdFields :: [CacheField]
    cdFields = [CacheField]
    cachedFields
      }
      where
        cachedFields :: [CacheField]
    cachedFields = (PivotFieldInfo -> Maybe CacheField)
    -> [PivotFieldInfo] -> [CacheField]
    forall a b. (a -> Maybe b) -> [a] -> [b]
    mapMaybe ((PivotFieldName -> CacheField)
    -> Maybe PivotFieldName -> Maybe CacheField
    forall a b. (a -> b) -> Maybe a -> Maybe b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap PivotFieldName -> CacheField
    cache (Maybe PivotFieldName -> Maybe CacheField)
    -> (PivotFieldInfo -> Maybe PivotFieldName)
    -> PivotFieldInfo
    -> Maybe CacheField
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . PivotFieldInfo -> Maybe PivotFieldName
    _pfiName) [PivotFieldInfo]
    _pvtFields
        cache :: PivotFieldName -> CacheField
    cache PivotFieldName
    name =
          CacheField
          { cfName :: PivotFieldName
    cfName = PivotFieldName
    name
          , cfItems :: [CellValue]
    cfItems =
              String -> Maybe [CellValue] -> [CellValue]
    forall a. Partial => String -> Maybe a -> a
    fromJustNote String
    "specified pivot table field does not exist" (Maybe [CellValue] -> [CellValue])
    -> Maybe [CellValue] -> [CellValue]
    forall a b. (a -> b) -> a -> b
    $
              PivotFieldName
    -> Map PivotFieldName [CellValue] -> Maybe [CellValue]
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup PivotFieldName
    name Map PivotFieldName [CellValue]
    itemsByName
          }
        ((RowIndex
    r1, ColumnIndex
    c1), (RowIndex
    r2, ColumnIndex
    c2)) =
          String
    -> Maybe ((RowIndex, ColumnIndex), (RowIndex, ColumnIndex))
    -> ((RowIndex, ColumnIndex), (RowIndex, ColumnIndex))
    forall a. Partial => String -> Maybe a -> a
    fromJustNote String
    "Invalid src ref of pivot table " (Maybe ((RowIndex, ColumnIndex), (RowIndex, ColumnIndex))
     -> ((RowIndex, ColumnIndex), (RowIndex, ColumnIndex)))
    -> Maybe ((RowIndex, ColumnIndex), (RowIndex, ColumnIndex))
    -> ((RowIndex, ColumnIndex), (RowIndex, ColumnIndex))
    forall a b. (a -> b) -> a -> b
    $ CellRef -> Maybe ((RowIndex, ColumnIndex), (RowIndex, ColumnIndex))
    fromRange CellRef
    _pvtSrcRef
        getCellValue :: (RowIndex, ColumnIndex) -> Maybe CellValue
    getCellValue (RowIndex, ColumnIndex)
    ix = (RowIndex, ColumnIndex) -> CellMap -> Maybe Cell
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup (RowIndex, ColumnIndex)
    ix CellMap
    cm Maybe Cell -> (Cell -> Maybe CellValue) -> Maybe CellValue
    forall a b. Maybe a -> (a -> Maybe b) -> Maybe b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= Cell -> Maybe CellValue
    _cellValue
        itemsByName :: Map PivotFieldName [CellValue]
    itemsByName =
          [(PivotFieldName, [CellValue])] -> Map PivotFieldName [CellValue]
    forall k a. Ord k => [(k, a)] -> Map k a
    M.fromList ([(PivotFieldName, [CellValue])] -> Map PivotFieldName [CellValue])
    -> [(PivotFieldName, [CellValue])]
    -> Map PivotFieldName [CellValue]
    forall a b. (a -> b) -> a -> b
    $
          ((ColumnIndex -> Maybe (PivotFieldName, [CellValue]))
     -> [ColumnIndex] -> [(PivotFieldName, [CellValue])])
    -> [ColumnIndex]
    -> (ColumnIndex -> Maybe (PivotFieldName, [CellValue]))
    -> [(PivotFieldName, [CellValue])]
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip (ColumnIndex -> Maybe (PivotFieldName, [CellValue]))
    -> [ColumnIndex] -> [(PivotFieldName, [CellValue])]
    forall a b. (a -> Maybe b) -> [a] -> [b]
    mapMaybe [ColumnIndex
    c1 .. ColumnIndex
    c2] ((ColumnIndex -> Maybe (PivotFieldName, [CellValue]))
     -> [(PivotFieldName, [CellValue])])
    -> (ColumnIndex -> Maybe (PivotFieldName, [CellValue]))
    -> [(PivotFieldName, [CellValue])]
    forall a b. (a -> b) -> a -> b
    $ \ColumnIndex
    c -> do
            CellText nm <- (RowIndex, ColumnIndex) -> Maybe CellValue
    getCellValue (RowIndex
    r1, ColumnIndex
    c)
            let values = (RowIndex -> Maybe CellValue) -> [RowIndex] -> [CellValue]
    forall a b. (a -> Maybe b) -> [a] -> [b]
    mapMaybe (\RowIndex
    r -> (RowIndex, ColumnIndex) -> Maybe CellValue
    getCellValue (RowIndex
    r, ColumnIndex
    c)) [(RowIndex
    r1 RowIndex -> RowIndex -> RowIndex
    forall a. Num a => a -> a -> a
    + RowIndex
    1) .. RowIndex
    r2]
            return (PivotFieldName nm, nubOrd values)

    writeCache :: CacheDefinition -> (Document, Document)
    writeCache :: CacheDefinition -> (Document, Document)
    writeCache CacheDefinition {[CacheField]
    Text
    CellRef
    cdSourceRef :: CacheDefinition -> CellRef
    cdSourceSheet :: CacheDefinition -> Text
    cdFields :: CacheDefinition -> [CacheField]
    cdSourceRef :: CellRef
    cdSourceSheet :: Text
    cdFields :: [CacheField]
    ..} = (Document
    cacheDefDoc, Document
    cacheRecordsDoc)
      where
        cacheDefDoc :: Document
    cacheDefDoc =
          Text -> Element -> Document
    documentFromElement Text
    "Pivot cache definition generated by xlsx" (Element -> Document) -> Element -> Document
    forall a b. (a -> b) -> a -> b
    $
          Name -> [(Name, Text)] -> [Element] -> Element
    elementList Name
    "pivotCacheDefinition" [(Name, Text)]
    attrs [Element]
    elements
        attrs :: [(Name, Text)]
    attrs = [Name
    "invalid" Name -> Bool -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= Bool
    True, Name
    "refreshOnLoad" Name -> Bool -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= Bool
    True, Text -> Name
    odr Text
    "id" Name -> RefId -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= Int -> RefId
    unsafeRefId Int
    1]
        elements :: [Element]
    elements = [Element
    worksheetSource, Element
    cacheFields]
        worksheetSource :: Element
    worksheetSource =
          Name -> [(Name, Text)] -> [Element] -> Element
    elementList
            Name
    "cacheSource"
            [Name
    "type" Name -> Text -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= (Text
    "worksheet" :: Text)]
            [ Name -> [(Name, Text)] -> Element
    leafElement
                Name
    "worksheetSource"
                [Name
    "ref" Name -> CellRef -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= CellRef
    cdSourceRef, Name
    "sheet" Name -> Text -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= Text
    cdSourceSheet]
            ]
        cacheFields :: Element
    cacheFields =
          Name -> [Element] -> Element
    elementListSimple Name
    "cacheFields" ([Element] -> Element) -> [Element] -> Element
    forall a b. (a -> b) -> a -> b
    $ (CacheField -> Element) -> [CacheField] -> [Element]
    forall a b. (a -> b) -> [a] -> [b]
    map (Name -> CacheField -> Element
    forall a. ToElement a => Name -> a -> Element
    toElement Name
    "cacheField") [CacheField]
    cdFields
        cacheRecordsDoc :: Document
    cacheRecordsDoc =
          Text -> Element -> Document
    documentFromElement Text
    "Pivot cache records generated by xlsx" (Element -> Document)
    -> ([Element] -> Element) -> [Element] -> Document
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
          Name -> [Element] -> Element
    elementListSimple Name
    "pivotCacheRecords" ([Element] -> Document) -> [Element] -> Document
    forall a b. (a -> b) -> a -> b
    $
          ([CacheRecordValue] -> Element)
    -> [[CacheRecordValue]] -> [Element]
    forall a b. (a -> b) -> [a] -> [b]
    map (Name -> [Element] -> Element
    elementListSimple Name
    "r" ([Element] -> Element)
    -> ([CacheRecordValue] -> [Element])
    -> [CacheRecordValue]
    -> Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (CacheRecordValue -> Element) -> [CacheRecordValue] -> [Element]
    forall a b. (a -> b) -> [a] -> [b]
    map CacheRecordValue -> Element
    recordValueToEl) [[CacheRecordValue]]
    cacheRecords
        recordValueToEl :: CacheRecordValue -> Element
    recordValueToEl (CacheText Text
    t) = Name -> [(Name, Text)] -> Element
    leafElement Name
    "s" [Name
    "v" Name -> Text -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= Text
    t]
        recordValueToEl (CacheNumber Double
    n) = Name -> [(Name, Text)] -> Element
    leafElement Name
    "n" [Name
    "v" Name -> Double -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= Double
    n]
        recordValueToEl (CacheIndex Int
    i) = Name -> [(Name, Text)] -> Element
    leafElement Name
    "x" [Name
    "v" Name -> Int -> (Name, Text)
    forall a. ToAttrVal a => Name -> a -> (Name, Text)
    .= Int
    i]
        cacheRecords :: [[CacheRecordValue]]
    cacheRecords = [[CacheRecordValue]] -> [[CacheRecordValue]]
    forall a. [[a]] -> [[a]]
    transpose ([[CacheRecordValue]] -> [[CacheRecordValue]])
    -> [[CacheRecordValue]] -> [[CacheRecordValue]]
    forall a b. (a -> b) -> a -> b
    $ (CacheField -> [CacheRecordValue])
    -> [CacheField] -> [[CacheRecordValue]]
    forall a b. (a -> b) -> [a] -> [b]
    map ([CellValue] -> [CacheRecordValue]
    itemsToRecordValues ([CellValue] -> [CacheRecordValue])
    -> (CacheField -> [CellValue]) -> CacheField -> [CacheRecordValue]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CacheField -> [CellValue]
    cfItems) [CacheField]
    cdFields
        itemsToRecordValues :: [CellValue] -> [CacheRecordValue]
    itemsToRecordValues [CellValue]
    vals =
          if (CellValue -> Bool) -> [CellValue] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all CellValue -> Bool
    isText [CellValue]
    vals
            then [CellValue] -> [CacheRecordValue]
    forall {a}. Eq a => [a] -> [CacheRecordValue]
    indexes [CellValue]
    vals
            else (CellValue -> CacheRecordValue)
    -> [CellValue] -> [CacheRecordValue]
    forall a b. (a -> b) -> [a] -> [b]
    map CellValue -> CacheRecordValue
    itemToRecordValue [CellValue]
    vals
        isText :: CellValue -> Bool
    isText (CellText Text
    _) = Bool
    True
        isText CellValue
    _ = Bool
    False
        indexes :: [a] -> [CacheRecordValue]
    indexes [a]
    vals =
          [ Int -> CacheRecordValue
    CacheIndex (Int -> CacheRecordValue)
    -> (Maybe Int -> Int) -> Maybe Int -> CacheRecordValue
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> Maybe Int -> Int
    forall a. Partial => String -> Maybe a -> a
    fromJustNote String
    "inconsistend definition" (Maybe Int -> CacheRecordValue) -> Maybe Int -> CacheRecordValue
    forall a b. (a -> b) -> a -> b
    $ a -> [a] -> Maybe Int
    forall a. Eq a => a -> [a] -> Maybe Int
    elemIndex a
    v [a]
    vals
          | a
    v <- [a]
    vals
          ]
        itemToRecordValue :: CellValue -> CacheRecordValue
    itemToRecordValue (CellDouble Double
    d) = Double -> CacheRecordValue
    CacheNumber Double
    d
        itemToRecordValue (CellText Text
    t) = Text -> CacheRecordValue
    CacheText Text
    t
        itemToRecordValue CellValue
    v = String -> CacheRecordValue
    forall a. Partial => String -> a
    error (String -> CacheRecordValue) -> String -> CacheRecordValue
    forall a b. (a -> b) -> a -> b
    $ String
    "Unsupported value for pivot tables: " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ CellValue -> String
    forall a. Show a => a -> String
    show CellValue
    v