/**
   * Create a dial image.
   *
   * <ul>
   *   <li>Load the specified XML document describing the dial definition
   *   <li>Create a dial definition object from the XML definition
   *   <li>Use the JFreeChartEngine to create a dial image
   *   <li>Create an XML document describing the dial
   *   <li>Return the XML document
   * </ul>
   *
   * @return The XML document describing this dial
   */
  @Override
  public Document getXmlContent() {

    WidgetDefinition widget = null;
    if (type == DashboardWidgetComponent.TYPE_DIAL) {

      // load the XML document that defines the dial
      IActionSequenceResource resource =
          new ActionSequenceResource(
              title,
              IActionSequenceResource.SOLUTION_FILE_RESOURCE,
              "text/xml", //$NON-NLS-1$
              definitionPath);
      Document dialDefinition = null;
      try {
        org.dom4j.io.SAXReader reader = new org.dom4j.io.SAXReader();
        reader.setEntityResolver(new SolutionURIResolver());
        dialDefinition =
            reader.read(
                resource.getInputStream(RepositoryFilePermission.READ, LocaleHelper.getLocale()));
      } catch (Throwable t) {
        // XML document can't be read. We'll just return a null document.
      }

      if (dialDefinition == null) {
        error(
            Messages.getInstance()
                .getErrorString(
                    "Widget.ERROR_0002_INVALID_RESOURCE", definitionPath)); // $NON-NLS-1$
        return null;
      }
      // create a dial definition from the XML definition
      widget = new DialWidgetDefinition(dialDefinition, 0, width, height, getSession());

      if (widget != null) {
        // set the value to be displayed on the dial
        widget.setValue(new Double(value));
      }
    }
    /*
     * else if( type == TYPE_THERMOMETER ) { // load the XML document that
     * defines the thermometer
     *
     * ActionResource resource = new ActionResource( title,
     * IActionResource.SOLUTION_FILE_RESOURCE, "text/xml", //$NON-NLS-1$
     * PentahoSystem.getApplicationContext().getSolutionPath( definitionPath ) );
     * //$NON-NLS-1$ Document thermometerDefinition = null; try {
     * thermometerDefinition = PentahoSystem.getResourceAsDocument( resource ); }
     * catch (IOException e) {} // create a dial definition from the XML
     * definition widget = createThermometer( thermometerDefinition );
     *
     * if( widget != null ) { // set the value to be displayed on the dial
     * widget.setValue( new Double(value) ); // Set the XSL file to be used
     * to generate the HTML setXsl( "text/html", "DialWidget.xsl" );
     * //$NON-NLS-1$ //$NON-NLS-2$ } else { error(
     * Messages.getInstance().getString("Widget.ERROR_0001_COULD_NOT_CREATE") );
     * //$NON-NLS-1$ return null; } }
     */
    if (widget == null) {
      error(Messages.getInstance().getString("Widget.ERROR_0001_COULD_NOT_CREATE")); // $NON-NLS-1$
      return null;
    }
    // create an image for the dial using the JFreeChart engine
    StringWriter stringWriter = new StringWriter();
    PrintWriter printWriter = new PrintWriter(stringWriter);
    // create temporary file names
    String solutionDir = "system/tmp/"; // $NON-NLS-1$
    String fileNamePrefix = "tmp_pie_"; // $NON-NLS-1$
    String extension = ".png"; // $NON-NLS-1$
    String fileName = null;
    String filePathWithoutExtension = null;
    try {
      File file =
          PentahoSystem.getApplicationContext()
              .createTempFile(getSession(), fileNamePrefix, extension, true);
      fileName = file.getName();
      filePathWithoutExtension = solutionDir + fileName.substring(0, fileName.indexOf('.'));
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    String dialTitle = ""; // $NON-NLS-1$
    JFreeChartEngine.saveChart(
        widget,
        dialTitle,
        units,
        filePathWithoutExtension,
        width,
        height,
        JFreeChartEngine.OUTPUT_PNG,
        printWriter,
        this);

    // Create a document that describes the result
    Document result = DocumentHelper.createDocument();
    IPentahoRequestContext requestContext = PentahoRequestContextHolder.getRequestContext();
    setXslProperty(
        "baseUrl", requestContext.getContextPath()); // $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    setXslProperty(
        "fullyQualifiedServerUrl",
        PentahoSystem.getApplicationContext()
            .getFullyQualifiedServerURL()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    Element root = result.addElement("widget"); // $NON-NLS-1$
    root.addElement("title").setText(title); // $NON-NLS-1$
    root.addElement("units").setText(units); // $NON-NLS-1$
    root.addElement("width").setText(Integer.toString(width)); // $NON-NLS-1$
    root.addElement("height").setText(Integer.toString(height)); // $NON-NLS-1$
    Element valueNode = root.addElement("value"); // $NON-NLS-1$
    valueNode.setText(Double.toString(value));
    valueNode.addAttribute(
        "in-image", Boolean.toString(widget.getValueFont() != null)); // $NON-NLS-1$
    root.addElement("image").setText(fileName); // $NON-NLS-1$
    return result;
  }
  protected Document createDials(
      final IPentahoResultSet resultSet, final WidgetDefinition widgetDefinition) {

    if (resultSet == null) {
      error(
          Messages.getInstance()
              .getErrorString("WidgetGrid.ERROR_0001_NO_RESULTS_FROM_ACTION")); // $NON-NLS-1$
      return null;
    }

    if (valueItem == null) {
      error(
          Messages.getInstance()
              .getErrorString("WidgetGrid.ERROR_0002_NO_VALUE_ITEM")); // $NON-NLS-1$
    }

    // Create a document that describes the result
    Document result = DocumentHelper.createDocument();
    IPentahoRequestContext requestContext = PentahoRequestContextHolder.getRequestContext();
    setXslProperty(
        "baseUrl", requestContext.getContextPath()); // $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    setXslProperty(
        "fullyQualifiedServerUrl",
        PentahoSystem.getApplicationContext()
            .getFullyQualifiedServerURL()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

    Element root = result.addElement("widgets"); // $NON-NLS-1$

    IPentahoMetaData metaData = resultSet.getMetaData();
    // TODO support multiple column headers / row headers
    // TODO support an iteration across columns for a given row

    // find the column that we have been told to you
    Object[][] columnHeaders = metaData.getColumnHeaders();
    int nameColumnNo = -1;
    int valueColumnNo = -1;
    for (int idx = 0; idx < columnHeaders[0].length; idx++) {
      if (columnHeaders[0][idx].toString().equalsIgnoreCase(nameItem)) {
        nameColumnNo = idx;
      }
      if (columnHeaders[0][idx].toString().equalsIgnoreCase(valueItem)) {
        valueColumnNo = idx;
      }
    }

    if (nameColumnNo == -1) {
      // we did not find the specified name column
      error(
          Messages.getInstance()
              .getErrorString(
                  "WidgetGrid.ERROR_0004_NAME_COLUMN_MISSING", nameItem)); // $NON-NLS-1$
      return null;
    }

    if (valueColumnNo == -1) {
      // we did not find the specified name column
      error(
          Messages.getInstance()
              .getErrorString(
                  "WidgetGrid.ERROR_0005_VALUE_COLUMN_MISSING", valueItem)); // $NON-NLS-1$
      return null;
    }

    double value;
    String name;
    Object[] row = resultSet.next();
    while (row != null) {
      name = row[nameColumnNo].toString();
      try {
        value = Double.parseDouble(row[valueColumnNo].toString());
        createDial(value, name, root, widgetDefinition);
      } catch (Exception e) {
      }

      row = resultSet.next();
    }
    setXslProperty("urlTarget", "pentaho_popup"); // $NON-NLS-1$ //$NON-NLS-2$
    setXslProperty("columns", Integer.toString(columns)); // $NON-NLS-1$
    if (style != null) {
      setXslProperty("style", style); // $NON-NLS-1$
    }
    return result;
  }
  @Override
  public Document getXmlContent() {

    // Create a document that describes the result
    Document result = DocumentHelper.createDocument();
    IPentahoRequestContext requestContext = PentahoRequestContextHolder.getRequestContext();
    setXslProperty(
        "baseUrl", requestContext.getContextPath()); // $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    setXslProperty(
        "fullyQualifiedServerUrl",
        PentahoSystem.getApplicationContext()
            .getFullyQualifiedServerURL()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    String mapName = "chart" + AbstractChartComponent.chartCount++; // $NON-NLS-1$
    Document chartDefinition =
        jcrHelper.getSolutionDocument(definitionPath, RepositoryFilePermission.READ);

    if (chartDefinition == null) {
      Element errorElement = result.addElement("error"); // $NON-NLS-1$
      errorElement
          .addElement("title")
          .setText(
              Messages.getInstance()
                  .getString(
                      "ABSTRACTCHARTEXPRESSION.ERROR_0001_ERROR_GENERATING_CHART")); //$NON-NLS-1$
                                                                                     // //$NON-NLS-2$
      String message =
          Messages.getInstance()
              .getString(
                  "CHARTS.ERROR_0001_CHART_DEFINIION_MISSING", definitionPath); // $NON-NLS-1$
      errorElement.addElement("message").setText(message); // $NON-NLS-1$
      error(message);
      return result;
    }
    // create a pie definition from the XML definition
    dataDefinition = createChart(chartDefinition);

    if (dataDefinition == null) {
      Element errorElement = result.addElement("error"); // $NON-NLS-1$
      errorElement
          .addElement("title")
          .setText(
              Messages.getInstance()
                  .getString(
                      "ABSTRACTCHARTEXPRESSION.ERROR_0001_ERROR_GENERATING_CHART")); //$NON-NLS-1$
                                                                                     // //$NON-NLS-2$
      String message =
          Messages.getInstance()
              .getString(
                  "CHARTS.ERROR_0002_CHART_DATA_MISSING",
                  actionPath); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
      errorElement.addElement("message").setText(message); // $NON-NLS-1$
      // System .out.println( result.asXML() );
      return result;
    }

    // create an image for the dial using the JFreeChart engine
    PrintWriter printWriter = new PrintWriter(new StringWriter());
    // we'll dispay the title in HTML so that the dial image does not have
    // to
    // accommodate it
    String chartTitle = ""; // $NON-NLS-1$
    try {
      if (width == -1) {
        width =
            Integer.parseInt(
                chartDefinition.selectSingleNode("/chart/width").getText()); // $NON-NLS-1$
      }
      if (height == -1) {
        height =
            Integer.parseInt(
                chartDefinition.selectSingleNode("/chart/height").getText()); // $NON-NLS-1$
      }
    } catch (Exception e) {
      // go with the default
    }
    if (chartDefinition.selectSingleNode("/chart/" + AbstractChartComponent.URLTEMPLATE_NODE_NAME)
        != null) { //$NON-NLS-1$
      urlTemplate =
          chartDefinition
              .selectSingleNode("/chart/" + AbstractChartComponent.URLTEMPLATE_NODE_NAME)
              .getText(); //$NON-NLS-1$
    }

    if (chartDefinition.selectSingleNode("/chart/paramName") != null) { // $NON-NLS-1$
      paramName = chartDefinition.selectSingleNode("/chart/paramName").getText(); // $NON-NLS-1$
    }

    Element root = result.addElement("charts"); // $NON-NLS-1$
    TimeSeriesCollection chartDataDefinition = (TimeSeriesCollection) dataDefinition;
    if (chartDataDefinition.getSeriesCount() > 0) {
      // create temporary file names
      String[] tempFileInfo = createTempFile();
      String fileName = tempFileInfo[AbstractChartComponent.FILENAME_INDEX];
      String filePathWithoutExtension =
          tempFileInfo[AbstractChartComponent.FILENAME_WITHOUT_EXTENSION_INDEX];

      ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());
      JFreeChartEngine.saveChart(
          chartDataDefinition,
          chartTitle,
          "",
          filePathWithoutExtension,
          width,
          height,
          JFreeChartEngine.OUTPUT_PNG,
          printWriter,
          info,
          this); //$NON-NLS-1$
      applyOuterURLTemplateParam();
      populateInfo(info);
      Element chartElement = root.addElement("chart"); // $NON-NLS-1$
      chartElement.addElement("mapName").setText(mapName); // $NON-NLS-1$
      chartElement.addElement("width").setText(Integer.toString(width)); // $NON-NLS-1$
      chartElement.addElement("height").setText(Integer.toString(height)); // $NON-NLS-1$
      for (int row = 0; row < chartDataDefinition.getSeriesCount(); row++) {
        for (int column = 0; column < chartDataDefinition.getItemCount(row); column++) {
          Number value = chartDataDefinition.getY(row, column);
          Comparable rowKey = chartDataDefinition.getSeriesKey(row);
          RegularTimePeriod columnKey = chartDataDefinition.getSeries(row).getTimePeriod(column);
          Element valueElement = chartElement.addElement("value2D"); // $NON-NLS-1$
          valueElement.addElement("value").setText(value.toString()); // $NON-NLS-1$
          valueElement.addElement("row-key").setText(rowKey.toString()); // $NON-NLS-1$
          valueElement.addElement("column-key").setText(columnKey.toString()); // $NON-NLS-1$
        }
      }
      String mapString = ImageMapUtilities.getImageMap(mapName, info);
      chartElement.addElement("imageMap").setText(mapString); // $NON-NLS-1$
      chartElement.addElement("image").setText(fileName); // $NON-NLS-1$
    }
    return result;
  }