-- | Fills the bottom rows, which contain the tags, memo, and-- filename. These rows are formatted as follows:---- * If the columns for TotalDrCr, TotalCmdty, and TotalQty are all-- present, AND if there are at least TWO other columns present, then-- there will be a hanging indent. The bottom rows will begin at the-- SECOND column and end with the last column to the left of-- TotalDrCr. In this case, each bottom row will have three cells: one-- padding on the left, one main content, and one padding on the-- right.---- * Otherwise, if there are NO columns in the top row, these rows-- will take the entire width of the report. Each bottom row will have-- one cell.---- * Otherwise, the bottom rows are as wide as all the top cells-- combined. Each bottom row will have one cell.modulePenny.Cabin.Posts.BottomRows(BottomOpts(..),bottomRows,Fields(..),TopRowCells(..),mergeWithSpacers,topRowCells)whereimportControl.Applicative((<$>),Applicative(pure,(<*>)))importqualifiedData.FoldableasFdblimportControl.Monad(guard)importData.List(intersperse,find)importqualifiedData.List.NonEmptyasNEimportData.Maybe(catMaybes)importData.Monoid(mappend,mempty,First(First,getFirst))importqualifiedData.SequenceasSeqimportqualifiedData.TextasXimportqualifiedData.TraversableasTimportqualifiedSystem.Console.RainbowasRbimportqualifiedPenny.Cabin.SchemeasEimportqualifiedPenny.Cabin.RowasRimportqualifiedPenny.Cabin.TextFormatasTFimportqualifiedPenny.Cabin.Posts.AllocatedasAimportqualifiedPenny.Cabin.Posts.FieldsasFimportqualifiedPenny.Cabin.Posts.GrowersasGimportqualifiedPenny.Cabin.Posts.MetaasMimportPenny.Cabin.Posts.Meta(Box)importqualifiedPenny.Cabin.Posts.SpacersasSimportqualifiedPenny.Cabin.Posts.TypesasTyimportqualifiedPenny.LincolnasLimportqualifiedPenny.Lincoln.HasTextasHTimportqualifiedPenny.Lincoln.QueriesasQdataBottomOpts=BottomOpts{growingWidths::G.Fields(MaybeInt),allocatedWidths::A.Fields(MaybeInt),fields::F.FieldsBool,reportWidth::Ty.ReportWidth,spacers::S.SpacersInt}bottomRows::E.Changers->BottomOpts->[Box]->Fields(Maybe[[Rb.Chunk]])bottomRowschosbs=makeRowsbspcswherepcs=infoProcessorschtopSpecs(reportWidthos)wantedwanted=requestedMakersch(fieldsos)topSpecs=topCellSpecs(growingWidthsos)(allocatedWidthsos)(spacersos)dataFieldsa=Fields{tags::a,memo::a,filename::a}deriving(Show,Eq)instanceFdbl.FoldableFieldswherefoldrfzd=f(tagsd)(f(memod)(f(filenamed)z))instanceFunctorFieldswherefmapf(Fieldstmfn)=Fields(ft)(fm)(ffn)instanceApplicativeFieldswherepurea=Fieldsaaaff<*>fa=Fields{tags=(tagsff)(tagsfa),memo=(memoff)(memofa),filename=(filenameff)(filenamefa)}bottomRowsFields::F.Fieldsa->FieldsabottomRowsFieldsf=Fields{tags=F.tagsf,memo=F.memof,filename=F.filenamef}dataHanginga=Hanging{leftPad::a,mainCell::a,rightPad::a}deriving(Show,Eq)newtypeSpacerWidth=SpacerWidthIntderiving(Show,Eq)newtypeContentWidth=ContentWidthIntderiving(Show,Eq)hanging::E.Changers->[TopCellSpec]->Maybe((Box->Int->((E.Label,E.EvenOdd),R.ColumnSpec))->Box->[Rb.Chunk])hangingchspecs=hangingWidthsspecs>>=return.hangingInfoProcessorchhangingInfoProcessor::E.Changers->HangingInt->(Box->Int->((E.Label,E.EvenOdd),R.ColumnSpec))->Box->[Rb.Chunk]hangingInfoProcessorchwidthsmkrinfo=rowwhererow=R.rowch[left,mid,right](ts,mid)=mkrinfo(mainCellwidths)mkPadw=R.ColumnSpecR.LeftJustify(R.Widthw)ts[]left=mkPad(leftPadwidths)right=mkPad(rightPadwidths)widthOfTopColumns::E.Changers->[TopCellSpec]->Maybe((Box->Int->((E.Label,E.EvenOdd),R.ColumnSpec))->Box->[Rb.Chunk])widthOfTopColumnschts=ifnulltsthenNothingelseJust$makeSpecificWidthchwwherew=Fdbl.foldl'f0tsfacc(_,maySpcWidth,(ContentWidthcw))=acc+cw+maybe0(\(SpacerWidthsw)->sw)maySpcWidthwidthOfReport::E.Changers->Ty.ReportWidth->(Box->Int->((E.Label,E.EvenOdd),R.ColumnSpec))->Box->[Rb.Chunk]widthOfReportch(Ty.ReportWidthrw)fninfo=makeSpecificWidthchrwfninfochooseProcessor::E.Changers->[TopCellSpec]->Ty.ReportWidth->(Box->Int->((E.Label,E.EvenOdd),R.ColumnSpec))->Box->[Rb.Chunk]chooseProcessorchspecsrwfn=letfirstTwo=First(hangingchspecs)`mappend`First(widthOfTopColumnschspecs)incasegetFirstfirstTwoofNothing->widthOfReportchrwfnJustr->rfninfoProcessors::E.Changers->[TopCellSpec]->Ty.ReportWidth->Fields(Maybe(Box->Int->((E.Label,E.EvenOdd),R.ColumnSpec)))->Fields(Maybe(Box->[Rb.Chunk]))infoProcessorschspecsrwflds=letchooser=chooseProcessorchspecsrwmkProcessormayFn=casemayFnofNothing->NothingJustfn->Just$chooserfninmkProcessor<$>fldsmakeRows::[Box]->Fields(Maybe(Box->[Rb.Chunk]))->Fields(Maybe[[Rb.Chunk]])makeRowsisflds=letmkRowfn=mapfnisinfmap(fmapmkRow)flds-- | Calculates column widths for a Hanging report. If it cannot-- calculate the widths (because these cells do not support hanging),-- returns Nothing.hangingWidths::[TopCellSpec]->Maybe(HangingInt)hangingWidthsls=doletlen=lengthlsguard(len>4)letmatchColumnx(c,_,_)=x==ctotDrCr<-find(matchColumnETotalDrCr)lstotCmdty<-find(matchColumnETotalCmdty)lstotQty<-find(matchColumnETotalQty)lslet(first:middle)=take(len-3)lsmid<-NE.nonEmptymiddlereturn$calcHangingWidthsfirstmid(totDrCr,totCmdty,totQty)typeTopCellSpec=(ETopRowCells,MaybeSpacerWidth,ContentWidth)-- | Given the first column in the top row, at least one middle-- column, and the last three columns, calculate the width of the-- three columns in the hanging report.calcHangingWidths::TopCellSpec->NE.NonEmptyTopCellSpec->(TopCellSpec,TopCellSpec,TopCellSpec)->HangingIntcalcHangingWidthslmr=HangingleftmiddlerightwherecalcWidth(_,maybeSp,(ContentWidthc))=c+maybe0(\(SpacerWidthw)->absw)maybeSpleft=calcWidthlmiddle=Fdbl.foldl'f0mwherefaccc=acc+calcWidthc(totDrCr,totCmdty,totQty)=rright=calcWidthtotDrCr+calcWidthtotCmdty+calcWidthtotQtytopCellSpecs::G.Fields(MaybeInt)->A.Fields(MaybeInt)->S.SpacersInt->[TopCellSpec]topCellSpecsgFldsaFldsspcs=letallFlds=topRowCellsgFldsaFldscws=fmap(fmapContentWidth)allFldsmerged=mergeWithSpacerscwsspcstriplere(cw,maybeSpc)=(e,(fmapSpacerWidthmaybeSpc),cw)list=Fdbl.toList$tripler<$>eTopRowCells<*>mergedtoMaybe(e,maybeS,maybeC)=casemaybeCofNothing->NothingJustc->Just(e,maybeS,c)incatMaybes(maptoMaybelist)-- | Merges a TopRowCells with a Spacers. Returns Maybes because-- totalQty has no spacer.mergeWithSpacers::TopRowCellsa->S.Spacersb->TopRowCells(a,Maybeb)mergeWithSpacersts=TopRowCells{globalTransaction=(globalTransactiont,Just(S.globalTransactions)),revGlobalTransaction=(revGlobalTransactiont,Just(S.revGlobalTransactions)),globalPosting=(globalPostingt,Just(S.globalPostings)),revGlobalPosting=(revGlobalPostingt,Just(S.revGlobalPostings)),fileTransaction=(fileTransactiont,Just(S.fileTransactions)),revFileTransaction=(revFileTransactiont,Just(S.revFileTransactions)),filePosting=(filePostingt,Just(S.filePostings)),revFilePosting=(revFilePostingt,Just(S.revFilePostings)),filtered=(filteredt,Just(S.filtereds)),revFiltered=(revFilteredt,Just(S.revFiltereds)),sorted=(sortedt,Just(S.sorteds)),revSorted=(revSortedt,Just(S.revSorteds)),visible=(visiblet,Just(S.visibles)),revVisible=(revVisiblet,Just(S.revVisibles)),lineNum=(lineNumt,Just(S.lineNums)),date=(datet,Just(S.dates)),flag=(flagt,Just(S.flags)),number=(numbert,Just(S.numbers)),payee=(payeet,Just(S.payees)),account=(accountt,Just(S.accounts)),postingDrCr=(postingDrCrt,Just(S.postingDrCrs)),postingCmdty=(postingCmdtyt,Just(S.postingCmdtys)),postingQty=(postingQtyt,Just(S.postingQtys)),totalDrCr=(totalDrCrt,Just(S.totalDrCrs)),totalCmdty=(totalCmdtyt,Just(S.totalCmdtys)),totalQty=(totalQtyt,Nothing)}-- | Applied to a function that, when applied to the width of a cell,-- returns a cell filled with data, returns a Row with that cell.makeSpecificWidth::E.Changers->Int->(Box->Int->(a,R.ColumnSpec))->Box->[Rb.Chunk]makeSpecificWidthchwfi=R.rowch[c]where(_,c)=fiwtypeMaker=E.Changers->Box->Int->((E.Label,E.EvenOdd),R.ColumnSpec)makers::FieldsMakermakers=FieldstagsCellmemoCellfilenameCell-- | Applied to an Options, indicating which reports the user wants,-- returns a Fields (Maybe Maker) with a Maker in each respective-- field that the user wants to see.requestedMakers::E.Changers->F.FieldsBool->Fields(Maybe(Box->Int->((E.Label,E.EvenOdd),R.ColumnSpec)))requestedMakerschallFlds=letflds=bottomRowsFieldsallFldsfillerbmkr=ifbthenJust$mkrchelseNothinginfiller<$>flds<*>makerstagsCell::E.Changers->Box->Int->((E.Label,E.EvenOdd),R.ColumnSpec)tagsCellchinfow=(ts,cell)wherevn=M.visibleNum.L.boxMeta$infocell=R.ColumnSpecR.LeftJustify(R.Widthw)tscseo=E.fromVisibleNumvnts=(E.Other,eo)cs=Fdbl.toList.fmaptoBit.TF.unLines.TF.wordWrapw.TF.Words.Seq.fromList.map(X.cons'*').HT.textList.Q.tags.L.boxPostFam$infomd=E.getEvenOddLabelValueE.OthereochtoBit(TF.Wordsws)=md.Rb.plain$twheret=X.concat.intersperse(X.singleton' ').Fdbl.toList$wsmemoBits::E.Changers->(E.Label,E.EvenOdd)->L.Memo->R.Width->[Rb.Chunk]memoBitsch(lbl,eo)m(R.Widthw)=cswherecs=Fdbl.toList.fmaptoBit.TF.unLines.TF.wordWrapw.TF.Words.Seq.fromList.X.words.X.intercalate(X.singleton' ').L.unMemo$mmd=E.getEvenOddLabelValuelbleochtoBit(TF.Wordsws)=md.Rb.plain$(X.unwords.Fdbl.toList$ws)memoCell::E.Changers->Box->Int->((E.Label,E.EvenOdd),R.ColumnSpec)memoCellchinfowidth=(ts,cell)wherew=R.Widthwidthvn=M.visibleNum.L.boxMeta$infoeo=E.fromVisibleNumvnts=(E.Other,eo)cell=R.ColumnSpecR.LeftJustifywtscsmayPm=Q.postingMemo.L.boxPostFam$infomayTm=Q.transactionMemo.L.boxPostFam$infocs=case(mayPm,mayTm)of(Nothing,Nothing)->mempty(Nothing,Justtm)->memoBitschtstmw(Justpm,Nothing)->memoBitschtspmw(Justpm,Justtm)->memoBitschtspmw`mappend`memoBitschtstmwfilenameCell::E.Changers->Box->Int->((E.Label,E.EvenOdd),R.ColumnSpec)filenameCellchinfowidth=(ts,cell)wherew=R.Widthwidthvn=M.visibleNum.L.boxMeta$infoeo=E.fromVisibleNumvnts=(E.Other,eo)cell=R.ColumnSpecR.LeftJustifywtscsmd=E.getEvenOddLabelValueE.OthereochtoBitn=md.Rb.plain.X.drop(max0(X.lengthn-width))$ncs=caseQ.filename.L.boxPostFam$infoofNothing->[]Justfn->[toBit.L.unFilename$fn]dataTopRowCellsa=TopRowCells{globalTransaction::a,revGlobalTransaction::a,globalPosting::a,revGlobalPosting::a,fileTransaction::a,revFileTransaction::a,filePosting::a,revFilePosting::a,filtered::a,revFiltered::a,sorted::a,revSorted::a,visible::a,revVisible::a,lineNum::a-- ^ The line number from the posting's metadata,date::a,flag::a,number::a,payee::a,account::a,postingDrCr::a,postingCmdty::a,postingQty::a,totalDrCr::a,totalCmdty::a,totalQty::a}deriving(Show,Eq)topRowCells::G.Fieldsa->A.Fieldsa->TopRowCellsatopRowCellsga=TopRowCells{globalTransaction=G.globalTransactiong,revGlobalTransaction=G.revGlobalTransactiong,globalPosting=G.globalPostingg,revGlobalPosting=G.revGlobalPostingg,fileTransaction=G.fileTransactiong,revFileTransaction=G.revFileTransactiong,filePosting=G.filePostingg,revFilePosting=G.revFilePostingg,filtered=G.filteredg,revFiltered=G.revFilteredg,sorted=G.sortedg,revSorted=G.revSortedg,visible=G.visibleg,revVisible=G.revVisibleg,lineNum=G.lineNumg,date=G.dateg,flag=G.flagg,number=G.numberg,payee=A.payeea,account=A.accounta,postingDrCr=G.postingDrCrg,postingCmdty=G.postingCmdtyg,postingQty=G.postingQtyg,totalDrCr=G.totalDrCrg,totalCmdty=G.totalCmdtyg,totalQty=G.totalQtyg}dataETopRowCells=EGlobalTransaction|ERevGlobalTransaction|EGlobalPosting|ERevGlobalPosting|EFileTransaction|ERevFileTransaction|EFilePosting|ERevFilePosting|EFiltered|ERevFiltered|ESorted|ERevSorted|EVisible|ERevVisible|ELineNum|EDate|EFlag|ENumber|EPayee|EAccount|EPostingDrCr|EPostingCmdty|EPostingQty|ETotalDrCr|ETotalCmdty|ETotalQtyderiving(Show,Eq,Enum)eTopRowCells::TopRowCellsETopRowCellseTopRowCells=TopRowCells{globalTransaction=EGlobalTransaction,revGlobalTransaction=ERevGlobalTransaction,globalPosting=EGlobalPosting,revGlobalPosting=ERevGlobalPosting,fileTransaction=EFileTransaction,revFileTransaction=ERevFileTransaction,filePosting=EFilePosting,revFilePosting=ERevFilePosting,filtered=EFiltered,revFiltered=ERevFiltered,sorted=ESorted,revSorted=ERevSorted,visible=EVisible,revVisible=ERevVisible,lineNum=ELineNum,date=EDate,flag=EFlag,number=ENumber,payee=EPayee,account=EAccount,postingDrCr=EPostingDrCr,postingCmdty=EPostingCmdty,postingQty=EPostingQty,totalDrCr=ETotalDrCr,totalCmdty=ETotalCmdty,totalQty=ETotalQty}instanceFunctorTopRowCellswherefmapft=TopRowCells{globalTransaction=f(globalTransactiont),revGlobalTransaction=f(revGlobalTransactiont),globalPosting=f(globalPostingt),revGlobalPosting=f(revGlobalPostingt),fileTransaction=f(fileTransactiont),revFileTransaction=f(revFileTransactiont),filePosting=f(filePostingt),revFilePosting=f(revFilePostingt),filtered=f(filteredt),revFiltered=f(revFilteredt),sorted=f(sortedt),revSorted=f(revSortedt),visible=f(visiblet),revVisible=f(revVisiblet),lineNum=f(lineNumt),date=f(datet),flag=f(flagt),number=f(numbert),payee=f(payeet),account=f(accountt),postingDrCr=f(postingDrCrt),postingCmdty=f(postingCmdtyt),postingQty=f(postingQtyt),totalDrCr=f(totalDrCrt),totalCmdty=f(totalCmdtyt),totalQty=f(totalQtyt)}instanceApplicativeTopRowCellswherepurea=TopRowCells{globalTransaction=a,revGlobalTransaction=a,globalPosting=a,revGlobalPosting=a,fileTransaction=a,revFileTransaction=a,filePosting=a,revFilePosting=a,filtered=a,revFiltered=a,sorted=a,revSorted=a,visible=a,revVisible=a,lineNum=a,date=a,flag=a,number=a,payee=a,account=a,postingDrCr=a,postingCmdty=a,postingQty=a,totalDrCr=a,totalCmdty=a,totalQty=a}ff<*>fa=TopRowCells{globalTransaction=globalTransactionff(globalTransactionfa),revGlobalTransaction=revGlobalTransactionff(revGlobalTransactionfa),globalPosting=globalPostingff(globalPostingfa),revGlobalPosting=revGlobalPostingff(revGlobalPostingfa),fileTransaction=fileTransactionff(fileTransactionfa),revFileTransaction=revFileTransactionff(revFileTransactionfa),filePosting=filePostingff(filePostingfa),revFilePosting=revFilePostingff(revFilePostingfa),filtered=filteredff(filteredfa),revFiltered=revFilteredff(revFilteredfa),sorted=sortedff(sortedfa),revSorted=revSortedff(revSortedfa),visible=visibleff(visiblefa),revVisible=revVisibleff(revVisiblefa),lineNum=lineNumff(lineNumfa),date=dateff(datefa),flag=flagff(flagfa),number=numberff(numberfa),payee=payeeff(payeefa),account=accountff(accountfa),postingDrCr=postingDrCrff(postingDrCrfa),postingCmdty=postingCmdtyff(postingCmdtyfa),postingQty=postingQtyff(postingQtyfa),totalDrCr=totalDrCrff(totalDrCrfa),totalCmdty=totalCmdtyff(totalCmdtyfa),totalQty=totalQtyff(totalQtyfa)}instanceFdbl.FoldableTopRowCellswherefoldrfzo=f(globalTransactiono)(f(revGlobalTransactiono)(f(globalPostingo)(f(revGlobalPostingo)(f(fileTransactiono)(f(revFileTransactiono)(f(filePostingo)(f(revFilePostingo)(f(filteredo)(f(revFilteredo)(f(sortedo)(f(revSortedo)(f(visibleo)(f(revVisibleo)(f(lineNumo)(f(dateo)(f(flago)(f(numbero)(f(payeeo)(f(accounto)(f(postingDrCro)(f(postingCmdtyo)(f(postingQtyo)(f(totalDrCro)(f(totalCmdtyo)(f(totalQtyo)z)))))))))))))))))))))))))instanceT.TraversableTopRowCellswheretraverseft=TopRowCells<$>f(globalTransactiont)<*>f(revGlobalTransactiont)<*>f(globalPostingt)<*>f(revGlobalPostingt)<*>f(fileTransactiont)<*>f(revFileTransactiont)<*>f(filePostingt)<*>f(revFilePostingt)<*>f(filteredt)<*>f(revFilteredt)<*>f(sortedt)<*>f(revSortedt)<*>f(visiblet)<*>f(revVisiblet)<*>f(lineNumt)<*>f(datet)<*>f(flagt)<*>f(numbert)<*>f(payeet)<*>f(accountt)<*>f(postingDrCrt)<*>f(postingCmdtyt)<*>f(postingQtyt)<*>f(totalDrCrt)<*>f(totalCmdtyt)<*>f(totalQtyt)