package org.openlca.app.editors.reports;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import org.apache.commons.io.IOUtils;
import org.openlca.app.M;
import org.openlca.app.db.DatabaseDir;
import org.openlca.app.editors.reports.model.Report;
import org.openlca.app.editors.reports.model.ReportComponent;
import org.openlca.app.editors.reports.model.ReportIndicator;
import org.openlca.app.editors.reports.model.ReportParameter;
import org.openlca.app.editors.reports.model.ReportSection;
import org.openlca.app.editors.reports.model.ReportVariant;
import org.openlca.core.database.IDatabase;
import org.openlca.core.database.ImpactMethodDao;
import org.openlca.core.model.ParameterRedef;
import org.openlca.core.model.Project;
import org.openlca.core.model.ProjectVariant;
import org.openlca.core.model.descriptors.ImpactCategoryDescriptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
public final class Reports {
private Reports() {
}
public static Report createOrOpen(Project project, IDatabase database) {
Report report = openReport(project, database);
return report != null ? report : createNew(project, database);
}
private static Report createNew(Project project, IDatabase database) {
Report report = new Report();
createDefaultSections(report);
if (project == null) {
report.title = "No project";
return report;
}
createReportVariants(project, report);
createReportIndicators(project, report, database);
report.title = M.ResultsOfProject + " " + project.getName();
return report;
}
private static void createReportVariants(Project project, Report report) {
if (project == null || report == null)
return;
int id = 0;
for (ProjectVariant projectVar : project.getVariants()) {
ReportVariant reportVar = new ReportVariant(id++);
reportVar.name = projectVar.getName();
report.variants.add(reportVar);
for (ParameterRedef redef : projectVar.getParameterRedefs()) {
ReportParameter param = findOrCreateParameter(redef, report);
param.putValue(reportVar.id, redef.getValue());
}
}
}
private static ReportParameter findOrCreateParameter(ParameterRedef redef,
Report report) {
for (ReportParameter parameter : report.parameters) {
ParameterRedef reportRedef = parameter.redef;
if (reportRedef == null)
continue;
if (Objects.equals(redef.getName(), reportRedef.getName())
&& Objects.equals(redef.getContextId(),
reportRedef.getContextId()))
return parameter;
}
ReportParameter parameter = new ReportParameter();
report.parameters.add(parameter);
parameter.name = redef.getName();
parameter.redef = redef;
return parameter;
}
private static void createReportIndicators(Project project, Report report,
IDatabase database) {
if (project.getImpactMethodId() == null)
return;
ImpactMethodDao dao = new ImpactMethodDao(database);
List<ImpactCategoryDescriptor> descriptors = dao
.getCategoryDescriptors(project.getImpactMethodId());
int id = 0;
for (ImpactCategoryDescriptor descriptor : descriptors) {
ReportIndicator indicator = new ReportIndicator(id++);
report.indicators.add(indicator);
indicator.descriptor = descriptor;
indicator.reportName = descriptor.getName();
indicator.displayed = true;
}
}
private static Report openReport(Project project, IDatabase database) {
if (project == null)
return null;
File file = getReportFile(project, database);
if (file == null || !file.exists())
return null;
try (FileInputStream fis = new FileInputStream(file);
Reader reader = new InputStreamReader(fis, "utf-8")) {
Gson gson = new Gson();
return gson.fromJson(reader, Report.class);
} catch (Exception e) {
Logger log = LoggerFactory.getLogger(Reports.class);
log.error("failed to open report file " + file, e);
return null;
}
}
public static void save(Project project, Report report, IDatabase database) {
if (report == null || project == null)
return;
Logger log = LoggerFactory.getLogger(Reports.class);
File file = getReportFile(project, database);
if (file == null) {
log.error("failed to get report file {} for {}" + file, report);
return;
}
if (!file.getParentFile().exists())
file.getParentFile().mkdirs();
log.trace("write report {} to file {}", report, file);
try (FileOutputStream fos = new FileOutputStream(file)) {
Gson gson = new Gson();
String json = gson.toJson(report);
IOUtils.write(json, fos, "utf-8");
} catch (Exception e) {
log.error("failed to write report file", e);
}
}
private static File getReportFile(Project project, IDatabase database) {
if (project == null)
return null;
File dir = DatabaseDir.getDir(project);
if (dir == null)
return null;
return new File(dir, "report.json");
}
private static void createDefaultSections(Report report) {
report.sections.add(createIntroSection(0));
ReportComponent[] components = {
ReportComponent.VARIANT_DESCRIPTION_TABLE,
ReportComponent.INDICATOR_DESCRIPTION_TABLE,
ReportComponent.IMPACT_RESULT_TABLE,
ReportComponent.INDICATOR_BAR_CHART,
ReportComponent.PROCESS_CONTRIBUTION_CHART,
ReportComponent.RELATIVE_INDICATOR_BAR_CHART
};
try {
Properties props = new Properties();
props.load(Reports.class
.getResourceAsStream("default_sections.properties"));
int idx = 1;
for (ReportComponent component : components) {
report.sections.add(createSection(idx, props, component));
idx++;
}
} catch (Exception e) {
Logger log = LoggerFactory.getLogger(Reports.class);
log.error("failed to create default report sections", e);
}
}
private static ReportSection createIntroSection(int idx) {
ReportSection section = new ReportSection();
section.index = idx;
section.title = "Introduction";
String text = "In the following the results of the project are shown. "
+ "This is a default template for the report of the project results. "
+ "You can configure this template via the project editor by \n"
+ "\n"
+ "<p><ul>\n"
+ "<li>changing the text of the sections, \n"
+ "<li>adding or removing sections, \n"
+ "<li>moving sections around, \n"
+ "<li>and selecting visual components that should be shown. \n"
+ "</ul></p>\n"
+ "\n"
+ "Note that you can also use HTML elements to format the section texts. "
+ "Additionally, you can export this report as an HTML page using "
+ "the export button in the toolbar of the report view.";
section.text = text;
return section;
}
private static ReportSection createSection(int idx, Properties props,
ReportComponent component) {
ReportSection section = new ReportSection();
section.index = idx;
section.title = props.getProperty(component.name() + ".title");
section.text = props.getProperty(component.name() + ".text");
section.componentId = component.getId();
return section;
}
}