// Copyright (C) 2003-2009 by Object Mentor, Inc. All rights reserved.
// Released under the terms of the CPL Common Public License version 1.0.
package fitnesse.reporting;

import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;

import fitnesse.html.template.PageFactory;
import fitnesse.testsystems.ExecutionLog;
import fitnesse.wiki.*;
import org.apache.velocity.VelocityContext;
import util.Clock;

public class CompositeExecutionLog {

  private final WikiPage testPage;
  private final String testPagePath;
  private WikiPagePath errorLogPagePath;

  public CompositeExecutionLog(WikiPage testPage) {
    this.testPage = testPage;
    PageCrawler crawler = testPage.getPageCrawler();
    testPagePath = "." + crawler.getFullPath();
    errorLogPagePath = crawler.getFullPath().addNameToFront(PageData.ErrorLogName);
  }

  private Map<String, ExecutionLog> logs = new HashMap<String, ExecutionLog>();

  public void add(String testSystemName, ExecutionLog executionLog) {
    logs.put(testSystemName, executionLog);
  }

  public void publish(PageFactory pageFactory) {
    String content = buildLogContent(pageFactory);
    PageCrawler crawler = testPage.getPageCrawler();
    WikiPage root = crawler.getRoot();

    WikiPage errorLogPage = WikiPageUtil.addPage(root, errorLogPagePath);
    PageData data = errorLogPage.getData();

    if(root != null) {
      WikiPagePath wpp = new WikiPagePath(errorLogPagePath.getRest());
      WikiPage wikiPage = root.getPageCrawler().getPage(wpp);
      if(wikiPage != null) {
        PageData pageData = wikiPage.getData();
        String tags = pageData.getAttribute(PageData.PropertySUITES);
        if(tags != null && !"".equals(tags)){
          data.setAttribute(PageData.PropertySUITES,tags);
        }
      }
    }

    data.setContent(content);
    errorLogPage.commit(data);
  }

  String buildLogContent(PageFactory pageFactory) {
    VelocityContext context = new VelocityContext();

    context.put("currentDate", makeDateFormat().format(Clock.currentDate()));
    context.put("testPage", testPagePath);
    context.put("logs", logs);

    return pageFactory.render(context, "executionLog.vm");
  }

  public String getErrorLogPageName() {
    return PathParser.render(errorLogPagePath);
  }

  public int exceptionCount() {
    int count = 0;
    for (ExecutionLog log : logs.values())
      count += log.getExceptions().size();
    return count;
  }

  public boolean hasCapturedOutput() {
    for (ExecutionLog log : logs.values())
      if (log.hasCapturedOutput())
        return true;
    return false;
  }

  private SimpleDateFormat makeDateFormat() {
    //SimpleDateFormat is not thread safe, so we need to create each instance independently.
    return new SimpleDateFormat("h:mm:ss a (z) 'on' EEEE, MMMM d, yyyy");
  }
}

@@ -251,16 +251,50 @@
 l.Map;%0A%0A
+import fitnesse.html.HtmlElement;%0A
 import f
@@ -458,16 +458,63 @@
 Clock;%0A%0A
+import static fitnesse.html.HtmlElement.endl;%0A%0A
 public c
@@ -540,16 +540,48 @@
 tionLog 
+implements ExecutionLogListener 
 %7B%0A%0A  pri
@@ -2925,11 +2925,1591 @@
 y%22);%0A  %7D
+%0A%0A  @Override%0A  public void commandStarted(ExecutionContext context) %7B%0A    executionLog = new ExecutionLog();%0A    executionLog.command = context.getCommand();%0A    startTime = Clock.currentTimeInMillis();%0A    logs.put(context.getTestSystemName() + logs.size(), executionLog);%0A  %7D%0A%0A  @Override%0A  public void stdOut(String output) %7B%0A    executionLog.capturedOutput.append(output).append(%22%5Cn%22);%0A  %7D%0A%0A  @Override%0A  public void stdErr(String output) %7B%0A    executionLog.capturedError.append(output).append(%22%5Cn%22);%0A  %7D%0A%0A  @Override%0A  public void exitCode(int exitCode) %7B%0A    long endTime = Clock.currentTimeInMillis();%0A    executionLog.executionTime = endTime - startTime;%0A    executionLog.exitCode = exitCode;%0A  %7D%0A%0A  @Override%0A  public void exceptionOccurred(Throwable e) %7B%0A    executionLog.exceptions.add(e);%0A  %7D%0A%0A  public static class ExecutionLog %7B%0A    private String command = %22%22;%0A    private long executionTime;%0A    private int exitCode;%0A    private StringBuilder capturedOutput = new StringBuilder();%0A    private StringBuilder capturedError = new StringBuilder();%0A    private List%3CThrowable%3E exceptions = new LinkedList%3CThrowable%3E();%0A%0A    public String getCommand() %7B%0A      return command;%0A    %7D%0A%0A    public long getExecutionTime() %7B%0A      return executionTime;%0A    %7D%0A%0A    public int getExitCode() %7B%0A      return exitCode;%0A    %7D%0A%0A    public String getCapturedOutput() %7B%0A      return capturedOutput.toString();%0A    %7D%0A%0A    public String getCapturedError() %7B%0A      return capturedError.toString();%0A    %7D%0A%0A    public List%3CThrowable%3E getExceptions() %7B%0A      return exceptions;%0A    %7D%0A%0A  %7D
 %0A%7D%0A

Add line endings to log.