/*******************************************************************************
* Copyright 2013
* Ubiquitous Knowledge Processing (UKP) Lab
* Technische Universität Darmstadt
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package de.tudarmstadt.ukp.csniper.webapp.statistics.page.export;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import de.tudarmstadt.ukp.csniper.webapp.evaluation.EvaluationRepository;
import de.tudarmstadt.ukp.csniper.webapp.evaluation.model.AdditionalColumn;
import de.tudarmstadt.ukp.csniper.webapp.evaluation.model.ItemContext;
import de.tudarmstadt.ukp.csniper.webapp.project.model.AnnotationType;
import de.tudarmstadt.ukp.csniper.webapp.search.ContextProvider;
import de.tudarmstadt.ukp.csniper.webapp.statistics.SortableAggregatedEvaluationResultDataProvider.ResultFilter;
import de.tudarmstadt.ukp.csniper.webapp.statistics.model.AggregatedEvaluationResult;
import de.tudarmstadt.ukp.csniper.webapp.statistics.page.StatisticsPage.ExportModel;
import de.tudarmstadt.ukp.csniper.webapp.statistics.page.StatisticsPage.StatisticsFormModel;
import de.tudarmstadt.ukp.csniper.webapp.support.task.Task;
public class ExportHtmlTask
extends Task
implements ExportTask
{
private static final int COLUMN_COUNT = 12;
private EvaluationRepository repository;
private ContextProvider contextProvider;
private StatisticsFormModel formModel;
private ExportModel exportModel;
private File outputFile;
public ExportHtmlTask(StatisticsFormModel aFormModel, ExportModel aExportModel,
EvaluationRepository aRepository, ContextProvider aContextProvider)
{
formModel = aFormModel;
exportModel = aExportModel;
contextProvider = aContextProvider;
repository = aRepository;
}
@Override
public File getOutputFile()
{
return outputFile;
}
@Override
public String getFilename()
{
String innerSeparator = "-";
String outerSeparator = "_";
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
StringBuilder sb = new StringBuilder();
sb.append("csniper");
sb.append(outerSeparator);
sb.append(dateFormat.format(new Date()));
sb.append(outerSeparator);
sb.append(StringUtils.join(formModel.getCollections(), innerSeparator));
sb.append(outerSeparator);
for (Iterator<AnnotationType> it = formModel.getTypes().iterator(); it.hasNext();) {
sb.append(it.next().getName());
if (it.hasNext()) {
sb.append(innerSeparator);
}
}
sb.append(outerSeparator);
sb.append(StringUtils.join(formModel.getUsers(), innerSeparator));
sb.append(".html");
return sb.toString();
}
@Override
public void clean()
{
if (outputFile != null) {
FileUtils.deleteQuietly(outputFile);
outputFile = null;
}
}
@Override
protected void run()
{
HtmlWriter writer = null;
contextProvider.setOutputPos(exportModel.includePos);
outputFile = null;
try {
outputFile = File.createTempFile("date", ".html");
writer = new HtmlWriter(new OutputStreamWriter(new FileOutputStream(outputFile),
"UTF-8"));
List<AdditionalColumn> ac = exportModel.additionalColumns;
String[] row = new String[COLUMN_COUNT];
List<AggregatedEvaluationResult> results = repository.listAggregatedResults(
formModel.getCollections(), formModel.getTypes(), formModel.getUsers(),
formModel.getUserThreshold(), formModel.getConfidenceThreshold());
Collections.sort(results, new Comparator<AggregatedEvaluationResult>()
{
@Override
public int compare(AggregatedEvaluationResult aO1, AggregatedEvaluationResult aO2)
{
String id1 = aO1.getItem().getCollectionId() + "|"
+ aO1.getItem().getDocumentId();
String id2 = aO2.getItem().getCollectionId() + "|"
+ aO2.getItem().getDocumentId();
return id1.compareTo(id2);
}
});
// Write rest
setTotal(results.size());
for (AggregatedEvaluationResult aer : results) {
ResultFilter classification = aer.getClassification();
if (formModel.getFilters().contains(classification)) {
ItemContext context = contextProvider.getContext(aer.getItem(),
exportModel.contextSize, exportModel.contextSize);
row[0] = aer.getItem().getCollectionId();
row[1] = aer.getItem().getDocumentId();
row[2] = Long.toString(aer.getItem().getBeginOffset());
row[3] = Long.toString(aer.getItem().getEndOffset());
row[4] = context.getLeft();
row[5] = context.getUnit();
row[6] = context.getRight();
row[7] = aer.getItem().getType();
row[8] = classification.toString();
row[9] = Double.toString(aer.getConfidence());
row[10] = Integer.toString(aer.getCorrect());
row[11] = Integer.toString(aer.getWrong());
writer.writeHtml(row, aer.getItem().getId(), ac, aer.getUsers(false));
}
// Make sure we do not get to 100% before we did the classification, because
// otherwise ProgressBar.onFinish() will trigger!!!
increment();
if (isCancelled()) {
break;
}
}
}
catch (IOException e) {
e.printStackTrace();
error("Export failed: " + ExceptionUtils.getRootCauseMessage(e));
cancel();
}
finally {
writer.close();
if (isCancelled()) {
clean();
}
}
}
private class HtmlWriter
{
private OutputStreamWriter out;
public HtmlWriter(OutputStreamWriter aOutputStreamWriter)
throws IOException
{
out = aOutputStreamWriter;
write("<html><head>");
write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />");
write("<style type=\"text/css\">");
write("div div { border:solid 1px #777; padding:5px; display:block; color:#777; }");
write("p, div div { margin:5 0px; }");
write("p.context { color:#333; }");
write("p.item { margin: 13px 0px 13px 30px; }");
write("table { color:#777; border-collapse: collapse; }");
write("td, th { padding: 3px 6px 3px 6px; }");
write("th { font-weight:bold; border-bottom: 1px solid #000; }");
write("</style>");
write("</head><body>");
write("<h1>" + getFilename() + "</h1>");
}
public void writeHtml(String[] row, long aItemId,
List<AdditionalColumn> aAdditionalColumns, Collection<String> aUsers)
throws IOException
{
write("<div>");
write("<div><strong>" + row[0] + "</strong>, textid[" + row[1] + "], offsets[" + row[2]
+ "," + row[3] + "], type[<strong>" + row[7]
+ "</strong>], classification[<strong>" + row[8] + "</strong> (" + row[9]
+ ")], correct|wrong[" + row[10] + "|" + row[11] + "]");
if (!aUsers.isEmpty()) {
StringBuilder sb = new StringBuilder();
boolean columnsHaveEntries = false;
sb.append("<table>");
sb.append("<tr>");
sb.append("<th>User</th>");
for (AdditionalColumn ac : aAdditionalColumns) {
sb.append("<th>" + ac.getName() + "</th>");
}
sb.append("</tr>");
for (String user : aUsers) {
boolean userHasEntries = false;
StringBuilder userRow = new StringBuilder();
userRow.append("<tr>");
userRow.append("<td>" + user + "</td>");
for (AdditionalColumn ac : aAdditionalColumns) {
String value = repository.getEvaluationResult(aItemId, user)
.getAdditionalColumns().get(ac);
if (value == null) {
value = "";
}
else {
userHasEntries = true;
columnsHaveEntries = true;
}
userRow.append("<td>" + value + "</td>");
}
userRow.append("</tr>");
if (userHasEntries) {
sb.append(userRow);
}
}
sb.append("</table>");
if (columnsHaveEntries) {
write(sb.toString());
}
}
write("</div>");
write("<p class=\"context\">[...] " + nl2br(row[4].trim()) + "</p>");
write("<p class=\"item\">" + nl2br(row[5].trim()) + "</p>");
write("<p class=\"context\">" + nl2br(row[6].trim()) + " [...]</p>");
write("</div>");
write("<hr /><br />");
}
public void close()
{
try {
write("</body></html>");
}
catch (IOException e) {
e.printStackTrace();
}
finally {
IOUtils.closeQuietly(out);
}
}
private void write(String aStr)
throws IOException
{
out.write(aStr + "\n");
}
private String nl2br(String aStr)
{
return StringUtils.replace(aStr, "\n", "<br />\n");
}
}
}