/**
 * Logback: the reliable, generic, fast and flexible logging framework.
 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
 *
 * This program and the accompanying materials are dual-licensed under
 * either the terms of the Eclipse Public License v1.0 as published by
 * the Eclipse Foundation
 *
 *   or (per the licensee's choosing)
 *
 * under the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation.
 */
package ch.qos.logback.core.status;

import static ch.qos.logback.core.CoreConstants.LINE_SEPARATOR;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import ch.qos.logback.core.CoreConstants;
import ch.qos.logback.core.helpers.Transform;
import ch.qos.logback.core.util.CachingDateFormatter;

abstract public class ViewStatusMessagesServletBase extends HttpServlet {

  private static final long serialVersionUID = -3551928133801157219L;
  private static CachingDateFormatter SDF = new CachingDateFormatter(
      "yyyy-MM-dd HH:mm:ss");

  static String SUBMIT = "submit";
  static String CLEAR = "Clear";

  protected abstract StatusManager getStatusManager(HttpServletRequest req, HttpServletResponse resp);

  protected abstract String getPageTitle(HttpServletRequest req, HttpServletResponse resp);

  int count;

  protected void service(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {

    count = 0;
    StatusManager sm = getStatusManager(req, resp);

    resp.setContentType("text/html");
    PrintWriter output = resp.getWriter();

    output.append("<html>\r\n");
    output.append("<head>\r\n");
    printCSS(req.getContextPath(), output);
    output.append("</head>\r\n");
    output.append("<body>\r\n");
    output.append(getPageTitle(req, resp));


    output.append("<form method=\"POST\">\r\n");
    output.append("<input type=\"submit\" name=\""+SUBMIT+"\" value=\""+CLEAR+"\">");
    output.append("</form>\r\n");


    if(CLEAR.equalsIgnoreCase(req.getParameter(SUBMIT))) {
      sm.clear();
      sm.add(new InfoStatus("Cleared all status messages", this));
    }
    
    output.append("<table>");
    StringBuilder buf = new StringBuilder();
    if(sm != null) {
      printList(buf, sm);
    } else {
      output.append("Could not find status manager");
    }
    output.append(buf);
    output.append("</table>");
    output.append("</body>\r\n");
    output.append("</html>\r\n");
    output.flush();
    output.close();
  }

  public void printCSS(String localRef, PrintWriter output) {
    output.append("  <STYLE TYPE=\"text/css\">\r\n");
    output.append("    .warn  { font-weight: bold; color: #FF6600;} \r\n"); // orange
    output.append("    .error { font-weight: bold; color: #CC0000;} \r\n");
    output
        .append("    table { margin-left: 2em; margin-right: 2em; border-left: 2px solid #AAA; }\r\n");
    output.append("    tr.even { background: #FFFFFF; }\r\n");
    output.append("    tr.odd  { background: #EAEAEA; }\r\n");
    output
        .append("    td { padding-right: 1ex; padding-left: 1ex; border-right: 2px solid #AAA; }\r\n");
    output
        .append("    td.date { text-align: right; font-family: courier, monospace; font-size: smaller; }");
    output.append(LINE_SEPARATOR);

    output.append("  td.level { text-align: right; }");
    output.append(LINE_SEPARATOR);
    output
        .append("    tr.header { background: #596ED5; color: #FFF; font-weight: bold; font-size: larger; }");
    output.append(CoreConstants.LINE_SEPARATOR);

    output
        .append("  td.exception { background: #A2AEE8; white-space: pre; font-family: courier, monospace;}");
    output.append(LINE_SEPARATOR);

    output.append("  </STYLE>\r\n");

  }

  public void printList(StringBuilder buf, StatusManager sm) {
    buf.append("<table>\r\n");
    printHeader(buf);
    List<Status> statusList = sm.getCopyOfStatusList();
    for (Status s : statusList) {
      count++;
      printStatus(buf, s);
    }
    buf.append("</table>\r\n");
  }

  public void printHeader(StringBuilder buf) {
    buf.append("  <tr class=\"header\">\r\n");
    buf.append("    <th>Date </th>\r\n");
    buf.append("    <th>Level</th>\r\n");
    buf.append("    <th>Origin</th>\r\n");
    buf.append("    <th>Message</th>\r\n");
    buf.append("  </tr>\r\n");

  }

  String statusLevelAsString(Status s) {
    switch (s.getEffectiveLevel()) {
    case Status.INFO:
      return "INFO";
    case Status.WARN:
      return "<span class=\"warn\">WARN</span>";
    case Status.ERROR:
      return "<span class=\"error\">ERROR</span>";
    }
    return null;
  }

  String abbreviatedOrigin(Status s) {
    Object o = s.getOrigin();
    if (o == null) {
      return null;
    }
    String fqClassName = o.getClass().getName();
    int lastIndex = fqClassName.lastIndexOf(CoreConstants.DOT);
    if (lastIndex != -1) {
      return fqClassName.substring(lastIndex + 1, fqClassName.length());
    } else {
      return fqClassName;
    }
  }

  private void printStatus(StringBuilder buf, Status s) {
    String trClass;
    if (count % 2 == 0) {
      trClass = "even";
    } else {
      trClass = "odd";
    }
    buf.append("  <tr class=\"").append(trClass).append("\">\r\n");
    String dateStr = SDF.format(s.getDate());
    buf.append("    <td class=\"date\">").append(dateStr).append("</td>\r\n");
    buf.append("    <td class=\"level\">").append(statusLevelAsString(s))
        .append("</td>\r\n");
    buf.append("    <td>").append(abbreviatedOrigin(s)).append("</td>\r\n");
    buf.append("    <td>").append(s.getMessage()).append("</td>\r\n");
    buf.append("  </tr>\r\n");
    if (s.getThrowable() != null) {
      printThrowable(buf, s.getThrowable());
    }
  }

  private void printThrowable(StringBuilder buf, Throwable t) {
    buf.append("  <tr>\r\n");
    buf.append("    <td colspan=\"4\" class=\"exception\"><pre>");
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw);
    t.printStackTrace(pw);
    buf.append(Transform.escapeTags(sw.getBuffer()));
    buf.append("    </pre></td>\r\n");
    buf.append("  </tr>\r\n");

  }
}
