package co.smartreceipts.android.workers.reports.pdf.renderer.impl;
import android.support.annotation.NonNull;
import com.google.common.base.Preconditions;
import com.tom_roush.pdfbox.pdmodel.PDDocument;
import com.tom_roush.pdfbox.util.awt.AWTColor;
import java.util.ArrayList;
import java.util.List;
import co.smartreceipts.android.filters.Filter;
import co.smartreceipts.android.model.Receipt;
import co.smartreceipts.android.settings.UserPreferenceManager;
import co.smartreceipts.android.utils.log.Logger;
import co.smartreceipts.android.workers.reports.TableGenerator;
import co.smartreceipts.android.workers.reports.pdf.colors.PdfColorStyle;
import co.smartreceipts.android.workers.reports.pdf.fonts.PdfFontSpec;
import co.smartreceipts.android.workers.reports.pdf.fonts.PdfFontStyle;
import co.smartreceipts.android.workers.reports.pdf.pdfbox.PdfBoxContext;
import co.smartreceipts.android.workers.reports.pdf.pdfbox.PdfBoxPageDecorations;
import co.smartreceipts.android.workers.reports.pdf.renderer.Renderer;
import co.smartreceipts.android.workers.reports.pdf.renderer.formatting.Padding;
import co.smartreceipts.android.workers.reports.pdf.renderer.grid.GridRowRenderer;
import co.smartreceipts.android.workers.reports.pdf.renderer.grid.PdfGridRenderer;
import co.smartreceipts.android.workers.reports.pdf.renderer.imagex.LollipopPdfPDImageXFactory;
import co.smartreceipts.android.workers.reports.pdf.renderer.imagex.PDImageXRenderer;
import co.smartreceipts.android.workers.reports.pdf.renderer.imagex.PdfPDImageXFactory;
import co.smartreceipts.android.workers.reports.pdf.renderer.imagex.PdfPDImageXFactoryFactory;
/**
* Generates a table of images. Every image has a legend that is displayed above the image.
*/
public class PdfGridGenerator implements TableGenerator<List<Renderer>, Receipt> {
private static final Padding DEFAULT_PADDING = new Padding(4f);
private static final int FULL_PAGE_ROWS_COLS = 1;
private final PdfBoxContext pdfBoxContext;
private final PDDocument pdDocument;
private final UserPreferenceManager userPreferenceManager;
private final PdfBoxPageDecorations decorations;
private final Filter<Receipt> filter;
private final AWTColor color;
private final PdfFontSpec fontSpec;
private final Padding padding;
private final float availableWidth;
private final float availableHeight;
public PdfGridGenerator(@NonNull PdfBoxContext pdfBoxContext, @NonNull PDDocument pdDocument, @NonNull Filter<Receipt> filter,
@NonNull PdfBoxPageDecorations decorations, float availableWidth, float availableHeight) {
this(pdfBoxContext, pdDocument, filter, decorations, pdfBoxContext.getColorManager().getColor(PdfColorStyle.Default),
pdfBoxContext.getFontManager().getFont(PdfFontStyle.Small), DEFAULT_PADDING, availableWidth, availableHeight);
}
public PdfGridGenerator(@NonNull PdfBoxContext pdfBoxContext, @NonNull PDDocument pdDocument, @NonNull Filter<Receipt> filter,
@NonNull PdfBoxPageDecorations decorations, @NonNull AWTColor color, @NonNull PdfFontSpec fontSpec,
@NonNull Padding padding, float availableWidth, float availableHeight) {
this.pdfBoxContext = Preconditions.checkNotNull(pdfBoxContext);
this.pdDocument = Preconditions.checkNotNull(pdDocument);
this.filter = Preconditions.checkNotNull(filter);
this.decorations = Preconditions.checkNotNull(decorations);
this.userPreferenceManager = Preconditions.checkNotNull(pdfBoxContext.getPreferences());
this.color = Preconditions.checkNotNull(color);
this.fontSpec = Preconditions.checkNotNull(fontSpec);
this.padding = Preconditions.checkNotNull(padding);
this.availableWidth = availableWidth;
this.availableHeight = availableHeight;
}
@NonNull
@Override
public List<Renderer> generate(@NonNull List<Receipt> receipts) {
final List<Renderer> renderers = new ArrayList<>();
GridReceiptsRendererFactory rendererFactory = null;
for (final Receipt receipt : receipts) {
if (!filter.accept(receipt) || receipt.getFile() == null || !receipt.hasFile()) {
Logger.debug(this, "Filtering out {} from receipt table", receipt);
continue;
}
if (!receipt.hasFile()) {
Logger.debug(this, "Missing file for {}. Omitting from receipt table", receipt);
continue;
}
if (receipt.isFullPage() || receipt.hasPDF()) {
if (rendererFactory != null && !rendererFactory.isEmpty()) {
Logger.debug(this, "Completing possible partial page as we have a full page entry");
constructRendererAndAddToList(rendererFactory, renderers);
rendererFactory = null;
}
if (receipt.hasPDF()) {
Logger.debug(this, "Adding existing pdf using the native renderer");
final PdfPDImageXFactory pdfFactory = new PdfPDImageXFactoryFactory(pdfBoxContext.getAndroidContext(), pdDocument, receipt.getFile()).get();
final ReceiptLabelTextRenderer textRenderer = new ReceiptLabelTextRenderer(receipt, pdfBoxContext.getAndroidContext(), pdDocument, userPreferenceManager, color, fontSpec);
final PDImageXRenderer imageRenderer = new PDImageXRenderer(pdfFactory);
final PdfGridRenderer pdfGridRenderer = new PdfGridRenderer(pdfFactory, availableWidth, availableHeight);
pdfGridRenderer.addRow(new GridRowRenderer(textRenderer));
pdfGridRenderer.addRow(new GridRowRenderer(imageRenderer));
pdfGridRenderer.getRenderingFormatting().addFormatting(DEFAULT_PADDING);
renderers.add(pdfGridRenderer);
} else {
Logger.debug(this, "Creating page for full page receipt.");
final GridReceiptsRendererFactory fullPageFactory = new GridReceiptsRendererFactory(pdfBoxContext.getAndroidContext(),
pdfBoxContext.getPreferences(), pdDocument, decorations, FULL_PAGE_ROWS_COLS, FULL_PAGE_ROWS_COLS);
fullPageFactory.addReceipt(receipt);
constructRendererAndAddToList(fullPageFactory, renderers);
}
} else {
if (rendererFactory == null) {
Logger.debug(this, "Creating new receipt grid for this pdf");
rendererFactory = new GridReceiptsRendererFactory(pdfBoxContext.getAndroidContext(),
pdfBoxContext.getPreferences(), pdDocument, decorations);
}
rendererFactory.addReceipt(receipt);
if (rendererFactory.isComplete()) {
Logger.debug(this, "NxN grid complete -- completing page");
constructRendererAndAddToList(rendererFactory, renderers);
rendererFactory = null;
}
}
}
// Add remaining cells (incomplete row)
if (rendererFactory != null) {
Logger.debug(this, "Writing final, incomplete page");
constructRendererAndAddToList(rendererFactory, renderers);
}
return renderers;
}
private void constructRendererAndAddToList(@NonNull GridReceiptsRendererFactory rendererFactory, @NonNull List<Renderer> list) {
Preconditions.checkNotNull(rendererFactory);
Preconditions.checkNotNull(list);
list.add(
rendererFactory.buildSinglePageGrid(availableWidth, availableHeight, color, fontSpec, padding)
);
}
}