public static CategoryComparison getCategoryComparison(File file, boolean encrypted)
      throws IOException, FileException {
    final List<String> categoryColumns = new ArrayList<String>();
    categoryColumns.addAll(Settings.getInstance().getCategories());

    final List<String> defaultColumns = new ArrayList<String>();
    defaultColumns.add("Date");
    defaultColumns.add("Last Name");
    defaultColumns.add("First Name");
    defaultColumns.add("Fund Type");
    defaultColumns.add("Check Number");
    defaultColumns.add("Total");

    final FileInputStream fstream = new FileInputStream(file);
    final DataInputStream in = new DataInputStream(fstream);
    final BufferedReader br = new BufferedReader(new InputStreamReader(in));
    try {
      final String firstLine = br.readLine();
      if (firstLine == null || firstLine.isEmpty()) {
        throw new RuntimeException(
            String.format("The file: %f is missing header.", file.getName()));
      }

      String schemaLine = firstLine;
      if (encrypted) {
        schemaLine = FileEncryption.decrypt(firstLine);
      }

      String[] tokens = schemaLine.split(",");
      if (tokens.length == 0) {
        throw new RuntimeException(String.format("The file: %f is corrupt.", file.getName()));
      }

      if (tokens[0].equals(SchemaSettings.SCHEMA_VERSION_KEY)) {
        String headerLine = br.readLine();
        if (encrypted) {
          headerLine = FileEncryption.decrypt(headerLine);
        }
        tokens = headerLine.split(",");
      }

      final List<String> missingColumns = new ArrayList<String>(categoryColumns);
      missingColumns.removeAll(Arrays.asList(tokens));
      final List<String> extraColumns = new ArrayList<String>(Arrays.asList(tokens));
      extraColumns.removeAll(defaultColumns);
      extraColumns.removeAll(categoryColumns);
      final List<String> allColumns = new ArrayList<String>(Arrays.asList(tokens));
      allColumns.removeAll(defaultColumns);

      return new CategoryComparison(allColumns, extraColumns, missingColumns);
    } catch (GeneralSecurityException e) {
      throw new FileException("Could not decrypt file: " + file.getName(), e);
    } finally {
      in.close();
      br.close();
    }
  }
 public static GivingRecord fromSchemaVersion10Csv(String csv, String[] headers)
     throws ParseException {
   try {
     final String[] tokens = csv.split(",");
     int tokenIndex = 0;
     final String dateString = tokens[tokenIndex++].trim();
     final String lastName = tokens[tokenIndex++].trim();
     final String firstName = tokens[tokenIndex++].trim();
     final GivingRecord record = new GivingRecord(dateString, lastName, firstName, "", "");
     final String[] categories = Arrays.copyOfRange(headers, tokenIndex, headers.length - 1);
     final List<String> definedCategories = Settings.getInstance().getCategories();
     for (String category : categories) {
       if (definedCategories.contains(category)) {
         record.setAmountForCategory(category, Double.parseDouble(tokens[tokenIndex++]));
       }
     }
     return record;
   } catch (Exception e) {
     throw new ParseException(csv, 0);
   }
 }
 private static ComponentBuilder<?, ?> createChurchAddressComponent() {
   final HorizontalListBuilder list =
       cmp.horizontalList()
           .setBaseStyle(stl.style().setTopBorder(stl.pen1Point()).setLeftPadding(10));
   addAddressAttribute(
       list, "Address", Settings.getInstance().getStringValue(Settings.ADDRESS1), false);
   addAddressAttribute(list, "", Settings.getInstance().getStringValue(Settings.ADDRESS2), false);
   final String city = Settings.getInstance().getStringValue(Settings.CITY);
   final String state = Settings.getInstance().getStringValue(Settings.STATE);
   final String zip = Settings.getInstance().getStringValue(Settings.ZIP);
   final String cityStateZip = String.format("%s, %s %s", city, state, zip);
   addAddressAttribute(list, "", cityStateZip, false);
   addAddressAttribute(
       list, "Phone", Settings.getInstance().getStringValue(Settings.PHONE), false);
   final HorizontalListBuilder title = cmp.horizontalFlowList();
   title
       .add(
           cmp.text(Settings.getInstance().getStringValue(Settings.CHURCH_NAME_KEY))
               .setStyle(Templates.boldStyle))
       .newRow();
   return cmp.verticalList(title, list);
 }
  private static JRDataSource createDataSource(String lastName, String firstName) {
    final List<GivingRecord> records =
        RecordManager.getInstance().getRecordsForName(lastName, firstName);

    final List<String> columnList = new ArrayList<String>();
    columnList.add("date");
    columnList.add("fundType");
    columnList.add("checkNumber");
    final List<String> categories = Settings.getInstance().getCategories();
    columnList.addAll(categories);
    columnList.add("total");

    final String[] columns = new String[columnList.size()];
    columnList.toArray(columns);

    final DRDataSource dataSource = new DRDataSource(columns);

    for (GivingRecord record : records) {
      final List<Object> data = new ArrayList<Object>();
      data.add(record.getDateString());
      data.add(record.getFundType());
      if (record.getCheckNumber().isEmpty()) {
        data.add(null);
      } else {
        data.add(Short.parseShort(record.getCheckNumber()));
      }
      for (String category : categories) {
        final BigDecimal amount = new BigDecimal(record.getAmountForCategory(category));
        data.add(amount);
      }
      data.add(new BigDecimal(record.getTotal()));
      dataSource.add(data.toArray());
    }

    return dataSource;
  }
  public static JasperReportBuilder createGivingStatement(String lastName, String firstName) {
    final StyleBuilder boldStyle = stl.style().bold();
    final StyleBuilder boldStyleSmall = stl.style().bold().setFontSize(8);
    final StyleBuilder boldCenteredStyle =
        stl.style(boldStyle).setHorizontalAlignment(HorizontalAlignment.CENTER);
    final StyleBuilder columnTitleStyle =
        stl.style(boldCenteredStyle)
            .setBorder(stl.pen1Point())
            .setBackgroundColor(Color.LIGHT_GRAY);

    final TextColumnBuilder<String> dateColumn = col.column("Date", "date", type.stringType());
    final TextColumnBuilder<String> fundTypeColumn =
        col.column("Fund Type", "fundType", type.stringType());
    final TextColumnBuilder<Short> checkNumberColumn =
        col.column("Check #", "checkNumber", type.shortType());

    final List<TextColumnBuilder<?>> columnList = new ArrayList<TextColumnBuilder<?>>();
    columnList.add(dateColumn);
    columnList.add(fundTypeColumn);
    columnList.add(checkNumberColumn);

    final List<AggregationSubtotalBuilder<BigDecimal>> subtotalBuilders =
        new ArrayList<AggregationSubtotalBuilder<BigDecimal>>();
    final List<String> categories = Settings.getInstance().getCategories();
    for (String category : categories) {
      final TextColumnBuilder<BigDecimal> categoryColumn =
          col.column(category, category, type.bigDecimalType());
      columnList.add(categoryColumn);
      subtotalBuilders.add(sbt.sum(categoryColumn));
    }
    final TextColumnBuilder<BigDecimal> totalsColumn =
        col.column("Total", "total", type.bigDecimalType());
    columnList.add(totalsColumn);
    subtotalBuilders.add(sbt.sum(totalsColumn));

    final AggregationSubtotalBuilder<?>[] sbtBuilders =
        new AggregationSubtotalBuilder<?>[subtotalBuilders.size()];
    subtotalBuilders.toArray(sbtBuilders);

    final TextColumnBuilder<?>[] columns = new TextColumnBuilder<?>[columnList.size()];
    columnList.toArray(columns);

    final VerticalListBuilder summary = cmp.verticalList();
    summary.add(cmp.verticalGap(5));
    summary.add(
        cmp.text(
                "Donor did not receive any goods or services in connection with the donations listed.")
            .setStyle(boldStyleSmall));
    summary.add(cmp.verticalGap(15));
    summary.add(cmp.text("Authorized Signature: ").setStyle(boldStyle));
    summary.add(cmp.verticalGap(10));
    summary.add(
        cmp.text("                                            ").setStyle(stl.style().underline()));

    return report() // create new report design
        .setTemplate(Templates.reportTemplate)
        .setColumnTitleStyle(columnTitleStyle)
        .highlightDetailEvenRows()
        .columns(columns)
        .title(createTitle(lastName, firstName))
        .pageFooter(cmp.pageXofY().setStyle(boldCenteredStyle))
        .setDataSource(createDataSource(lastName, firstName))
        .subtotalsAtSummary(sbtBuilders)
        .setPageMargin(DynamicReports.margin(40))
        .summary(summary);
  }