edu.jhuapl.graphs.controller.GraphController.java Source code

Java tutorial

Introduction

Here is the source code for edu.jhuapl.graphs.controller.GraphController.java

Source

/*
 * Copyright (c) 2013 The Johns Hopkins University/Applied Physics Laboratory
 *                             All rights reserved.
 *
 * This material may be used, modified, or reproduced by or for the U.S.
 * Government pursuant to the rights granted under the clauses at
 * DFARS 252.227-7013/7014 or FAR 52.227-14.
 *
 * 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
 *
 * NO WARRANTY.   THIS MATERIAL IS PROVIDED "AS IS."  JHU/APL DISCLAIMS ALL
 * WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING (BUT NOT
 * LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
 * INTELLECTUAL PROPERTY RIGHTS. ANY USER OF THE MATERIAL ASSUMES THE ENTIRE
 * RISK AND LIABILITY FOR USING THE MATERIAL.  IN NO EVENT SHALL JHU/APL BE
 * LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
 * CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR
 * INABILITY TO USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES
 * FOR LOST PROFITS.
 */

package edu.jhuapl.graphs.controller;

import edu.jhuapl.graphs.DataPoint;
import edu.jhuapl.graphs.DataSeries;
import edu.jhuapl.graphs.Encoding;
import edu.jhuapl.graphs.GraphException;
import edu.jhuapl.graphs.GraphSource;
import edu.jhuapl.graphs.PointInterface;
import edu.jhuapl.graphs.RenderedGraph;
import edu.jhuapl.graphs.jfreechart.JFreeChartBarGraphSource;
import edu.jhuapl.graphs.jfreechart.JFreeChartCategoryGraphSource;
import edu.jhuapl.graphs.jfreechart.JFreeChartGraphSource;
import edu.jhuapl.graphs.jfreechart.utils.CustomLabelNumberAxis;
import edu.jhuapl.graphs.jfreechart.utils.SparselyLabeledCategoryAxis;

import org.jfree.chart.JFreeChart;
import org.jfree.chart.LegendItem;
import org.jfree.chart.LegendItemCollection;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.PlotOrientation;

import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class GraphController {

    private static final int defaultMaxLegendItems = 50;

    private static final int maxCategoryLabelWidthRatio = 15;
    private static final Color noDataColor = Color.GRAY;
    private static final Color warningDataColor = Color.YELLOW;
    private static final Color alertDataColor = Color.RED;
    private static final Color severeDataColor = Color.MAGENTA;

    private static final Font graphFont = new Font("Arial", Font.BOLD, 14);
    private static final Font rangeAxisFont = new Font("Arial", Font.BOLD, 12);
    private static final Font rangeAxisLabelFont = new Font("Arial", Font.BOLD, 12);
    private static final Font domainAxisFont = new Font("Arial", Font.PLAIN, 11);
    private static final Font domainAxisLabelFont = new Font("Arial", Font.BOLD, 12);
    private static final Font legendFont = new Font("Arial", Font.PLAIN, 11);

    private String graphDataId = null;
    private GraphDataHandlerInterface graphDataHandler = null;
    private int maxLegendItems = defaultMaxLegendItems;
    private Map<String, String> translationMap = new HashMap<String, String>(0);

    public GraphController(String graphDataId, GraphDataHandlerInterface graphDataHandler, String userId) {
        if (graphDataId != null && graphDataId.length() > 0) {
            this.graphDataId = graphDataId;
        } else {
            this.graphDataId = getUniqueId(userId);
        }

        this.graphDataHandler = graphDataHandler;
    }

    public Map<String, String> getTranslationMap() {
        if (translationMap == null) {
            translationMap = new HashMap<String, String>(0);
        }
        return translationMap;
    }

    /**
     * Set a key value map to be used for translations.
     */
    public void setTranslationMap(Map<String, String> translationMap) {
        this.translationMap = translationMap;
    }

    /**
     * Returns a translation of <code>word</code> if available.  Note: matches case.
     *
     * @return a translation from translationMap or <code>word</code>
     */
    protected String getTranslation(String word) {
        if (getTranslationMap() != null && getTranslationMap().containsKey(word)) {
            return getTranslationMap().get(word);
        }
        return word;
    }

    public String getGraphDataId() {
        return graphDataId;
    }

    /**
     * @param maxLegendItems Maximum number of items to display in the legend
     */
    public void setMaxLegendItems(int maxLegendItems) {
        this.maxLegendItems = maxLegendItems;
    }

    public GraphObject writeTimeSeriesGraph(PrintWriter out, GraphDataInterface graphData, boolean useImageMap,
            boolean includeFooter, String callBackURL) {
        StringBuffer sb = new StringBuffer();
        GraphObject graph = writeTimeSeriesGraph(sb, graphData, useImageMap, includeFooter, callBackURL);
        out.println(sb);
        return graph;
    }

    public GraphObject writeSimpleTimeSeriesGraph(StringBuffer sb, GraphDataInterface graphData, String linkUrl,
            String callbackUrl) {
        GraphObject graph = createTimeSeriesGraph(graphData);

        writeSimpleLinkTSGraph(sb, graphData, callbackUrl, linkUrl, graph);
        return graph;
    }

    public GraphObject writeTimeSeriesGraph(StringBuffer sb, GraphDataInterface graphData, boolean useImageMap,
            boolean includeFooter, String callBackURL) {
        return writeTimeSeriesGraph(sb, graphData, useImageMap, includeFooter, true, callBackURL);
    }

    public GraphObject writeTimeSeriesGraph(StringBuffer sb, GraphDataInterface graphData, boolean useImageMap,
            boolean includeFooter, boolean includeButtons, String callBackURL) {
        GraphObject graph = createTimeSeriesGraph(graphData);
        writeGraph(sb, graphData, useImageMap, includeFooter, includeButtons, callBackURL, null, null, graph);
        return graph;
    }

    public GraphObject writeTimeSeriesGraphWithHelpLinks(StringBuffer sb, GraphDataInterface graphData,
            boolean useImageMap, boolean includeFooter, String graphOptionsHelpLink, String downloadHelpLink,
            String callBackURL) {
        GraphObject graph = createTimeSeriesGraph(graphData);
        writeGraph(sb, graphData, useImageMap, includeFooter, callBackURL, graphOptionsHelpLink, downloadHelpLink,
                graph);
        return graph;
    }

    public void dumpWriteTsGraph(PrintWriter out, GraphDataInterface graphData, boolean includeFooter,
            String callBackURL) {
        StringBuffer sb = new StringBuffer();
        dumpWriteTsGraph(sb, graphData, includeFooter, callBackURL);
        out.println(sb);
        return;
    }

    public void dumpWriteTsGraph(StringBuffer sb, GraphDataInterface graphData, boolean includeFooter,
            String callBackURL) {
        Map<String, Object> graphMetaData = dumpGraph(graphData);
        writeGraph(sb, graphData, includeFooter, callBackURL, "imageMap" + graphDataId, null, null, graphMetaData);
    }

    public void dumpWriteTsGraph(PrintWriter out, GraphDataInterface graphData, boolean includeFooter,
            String callBackURL, String graphURL) {
        StringBuffer sb = new StringBuffer();
        dumpWriteTsGraph(sb, graphData, includeFooter, callBackURL, graphURL);
        out.println(sb);
        return;
    }

    public void dumpWriteTsGraph(StringBuffer sb, GraphDataInterface graphData, boolean includeFooter,
            String callBackURL, String graphURL) {
        Map<String, Object> graphMetaData = dumpGraph(graphData);
        writeGraph(sb, graphData, includeFooter, graphURL, callBackURL, "imageMap" + graphDataId, null, null,
                graphMetaData);
    }

    public GraphObject writePieGraph(PrintWriter out, GraphDataInterface graphData, boolean useImageMap,
            String callBackURL) {
        StringBuffer sb = new StringBuffer();
        GraphObject graph = writePieGraph(sb, graphData, useImageMap, callBackURL);
        out.println(sb);
        return graph;
    }

    public GraphObject writePieGraph(StringBuffer sb, GraphDataInterface graphData, boolean useImageMap,
            String callBackURL) {
        GraphObject graph = createPieGraph(graphData);
        writeGraph(sb, graphData, useImageMap, false, false, callBackURL, null, null, graph);
        return graph;
    }

    public GraphObject writeBarGraph(PrintWriter out, GraphDataInterface graphData, boolean stackGraph,
            boolean useImageMap, String callBackURL) {
        StringBuffer sb = new StringBuffer();
        GraphObject graph = writeBarGraph(sb, graphData, stackGraph, useImageMap, callBackURL);
        out.println(sb);
        return graph;
    }

    public GraphObject writeBarGraph(StringBuffer sb, GraphDataInterface graphData, boolean stackGraph,
            boolean useImageMap, String callBackURL) {
        GraphObject graph = createBarGraph(graphData, stackGraph);
        writeGraph(sb, graphData, useImageMap, false, false, callBackURL, null, null, graph);
        return graph;
    }

    public GraphObject writeSeverityGraph(PrintWriter out, GraphDataInterface graphData, boolean useImageMap,
            String callBackURL) {
        StringBuffer sb = new StringBuffer();
        GraphObject graph = writeSeverityGraph(sb, graphData, useImageMap, callBackURL);
        out.println(sb);
        return graph;
    }

    public GraphObject writeSeverityGraph(StringBuffer sb, GraphDataInterface graphData, boolean useImageMap,
            String callBackURL) {
        GraphObject graph = createSeverityGraph(graphData);
        writeGraph(sb, graphData, useImageMap, false, false, callBackURL, null, null, graph);
        return graph;
    }

    public GraphObject writeDualAxisGraph(PrintWriter out, GraphDataInterface graphData, boolean useImageMap,
            String callBackURL) {
        StringBuffer sb = new StringBuffer();
        GraphObject graph = writeDualAxisGraph(sb, graphData, useImageMap, callBackURL);
        out.println(sb);
        return graph;
    }

    public GraphObject writeDualAxisGraph(StringBuffer sb, GraphDataInterface graphData, boolean useImageMap,
            String callBackURL) {
        GraphObject graph = createDualAxisGraph(graphData);
        writeGraph(sb, graphData, useImageMap, false, false, callBackURL, null, null, graph);
        return graph;
    }

    public GraphObject createTimeSeriesGraph(GraphDataInterface graphData) {
        return createTimeSeriesGraph(graphData, null, null, null);
    }

    public GraphObject createTimeSeriesGraph(GraphDataInterface graphData, Double yAxisMin, Double yAxisMax,
            String displayKey) {
        List<DataSeries> dataSeries = new ArrayList<DataSeries>();
        LegendItemCollection legendItems = new LegendItemCollection();
        Map<String, Object> graphMetaData = new HashMap<String, Object>();
        double maxCount = setDataSeries(graphData, displayKey, false, dataSeries, legendItems);

        setTimeSeriesGraphMetaData(graphData, yAxisMin, yAxisMax, maxCount, graphMetaData);

        return getGraph(graphData, dataSeries, graphMetaData, legendItems, "tsgraph");
    }

    public GraphObject createBarGraph(GraphDataInterface graphData, boolean stackGraph) {
        return createBarGraph(graphData, stackGraph, false);
    }

    /**
     * The useItemColor is still under development to allow each bar to be a different color.
     */
    public GraphObject createBarGraph(GraphDataInterface graphData, boolean stackGraph, boolean useItemColor) {
        List<DataSeries> dataSeries = new ArrayList<DataSeries>();
        LegendItemCollection legendItems = new LegendItemCollection();
        Map<String, Object> graphMetaData = new HashMap<String, Object>();

        setDataSeries(graphData, null, false, dataSeries, legendItems, useItemColor);
        setBarGraphMetaData(graphData, stackGraph, graphMetaData);

        return getGraph(graphData, dataSeries, graphMetaData, legendItems, "bargraph");
    }

    public GraphObject createPieGraph(GraphDataInterface graphData) {
        return createPieGraph(graphData, Encoding.PNG);
    }

    public GraphObject createPieGraph(GraphDataInterface graphData, Encoding encoding) {
        GraphObject graph = null;

        Map<String, Object> graphMetaData = new HashMap<String, Object>();
        List<PointInterface> points = new ArrayList<PointInterface>();
        setPieGraphMetaData(graphData, graphMetaData, points); // I'm ashamed of this code in so many ways
        String graphTitle = (String) graphMetaData.get(GraphSource.GRAPH_TITLE);

        try {
            // add the created chart properties
            JFreeChartGraphSource graphSource = new JFreeChartGraphSource();
            graphSource.setData(Arrays.asList(new DataSeries(points, new HashMap<String, Object>())));
            graphSource.setParams(graphMetaData);
            graphSource.initialize();

            if (graphData.showLegend()) {
                PiePlot plot = (PiePlot) graphSource.getChart().getPlot();
                // use rectangles as the legend shapes
                plot.setLegendItemShape(new Rectangle(7, 8));
                // generate tooltip for the legend items in the following format: "lineSetLabels - count"
                if (graphData.percentBased()) {
                    plot.setLegendLabelToolTipGenerator(new StandardPieSectionLabelGenerator("{0} - {1} ({2})",
                            new DecimalFormat("#.##"), new DecimalFormat("#.##%")));
                } else {
                    plot.setLegendLabelToolTipGenerator(new StandardPieSectionLabelGenerator("{0} - {1} ({2})",
                            new DecimalFormat("#"), new DecimalFormat("#.##%")));
                }
            }

            // render the graph to get the image map
            RenderedGraph renderedGraph = graphSource.renderGraph(graphData.getGraphWidth(),
                    graphData.getGraphHeight(), encoding);
            String extension = ".dat";
            switch (encoding) {
            case JPEG:
                extension = ".jpg";
                break;
            case PNG:
            case PNG_WITH_TRANSPARENCY:
                extension = ".png";
                break;
            }

            String imageFileName = getCleanValue(graphTitle) + "_piegraph" + extension;
            // get the image map
            String imageMapName = "imageMap" + graphDataId;
            String imageMap = appendImageMapTarget(renderedGraph.getImageMap(imageMapName),
                    graphData.getLineSetURLTarget());

            try {
                // store away the graph data file
                graphDataHandler.putGraphData(graphData, graphDataId);
                graph = new GraphObject(graphSource, renderedGraph, imageFileName, imageMapName, imageMap,
                        graphDataId);
            } catch (GraphException e) {
                System.out.println(e.getMessage());
                e.printStackTrace();
            }
        } catch (GraphException e) {
            System.out.println("Could not create pie graph " + graphTitle);
            e.printStackTrace();
        }

        return graph;
    }

    public GraphObject createSeverityGraph(GraphDataInterface graphData) {
        List<DataSeries> dataSeries = new ArrayList<DataSeries>();
        Map<String, Object> graphMetaData = new HashMap<String, Object>();
        LegendItemCollection legendItems = new LegendItemCollection();
        Color[] graphBaseColors = graphData.getGraphBaseColors();
        Map<Double, String> tickValueToLabelMapping = new HashMap<Double, String>();

        setDataSeries(graphData, null, true, dataSeries, null);
        setBarGraphMetaData(graphData, true, graphMetaData);

        // create a custom legend
        legendItems.add(new LegendItem(getTranslation("Severe"), severeDataColor));
        legendItems.add(new LegendItem(getTranslation("Not Severe"), graphBaseColors[0]));
        legendItems.add(new LegendItem(getTranslation("No Data Available"), noDataColor));

        // create custom value axis labels
        String[] lineSetLabels = graphData.getLineSetLabels();
        double lowestTickValue = 0.5;
        int tickCount = lineSetLabels.length;

        for (int i = 0; i < tickCount; i++) {
            tickValueToLabelMapping.put(lowestTickValue + i, lineSetLabels[i]);
        }

        CustomLabelNumberAxis rangeAxis = new CustomLabelNumberAxis(tickValueToLabelMapping);
        rangeAxis.setLowestTickValue(lowestTickValue);
        rangeAxis.setTickCount(tickCount);
        graphMetaData.put(JFreeChartCategoryGraphSource.RANGE_AXIS, rangeAxis);

        return getGraph(graphData, dataSeries, graphMetaData, legendItems, "tsgraph");
    }

    public GraphObject createDualAxisGraph(GraphDataInterface graphData) {
        List<DataSeries> dataSeries = new ArrayList<DataSeries>();
        LegendItemCollection legendItems = new LegendItemCollection();
        Map<String, Object> graphMetaData = new HashMap<String, Object>();
        double maxCount = setDataSeries(graphData, null, false, dataSeries, legendItems);

        setTimeSeriesGraphMetaData(graphData, null, null, maxCount, graphMetaData);
        setBarGraphMetaData(graphData, false, graphMetaData);
        graphMetaData.put(GraphSource.GRAPH_TYPE, GraphSource.GRAPH_TYPE_DUAL_AXIS);

        return getGraph(graphData, dataSeries, graphMetaData, legendItems, "dualAxisGraph");
    }

    public static String zipGraphs(List<GraphObject> graphs, String tempDir, String userId) throws GraphException {
        if (graphs != null && graphs.size() > 0) {
            byte[] byteBuffer = new byte[1024];
            String zipFileName = getUniqueId(userId) + ".zip";

            try {
                File zipFile = new File(tempDir, zipFileName);
                ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile));
                boolean hasGraphs = false;

                for (GraphObject graph : graphs) {
                    if (graph != null) {
                        byte[] renderedGraph = graph.getRenderedGraph().getData();
                        ByteArrayInputStream in = new ByteArrayInputStream(renderedGraph);
                        int len;

                        zos.putNextEntry(new ZipEntry(graph.getImageFileName()));

                        while ((len = in.read(byteBuffer)) > 0) {
                            zos.write(byteBuffer, 0, len);
                        }

                        in.close();
                        zos.closeEntry();
                        hasGraphs = true;
                    }
                }

                zos.close();

                if (hasGraphs) {
                    return zipFileName;
                } else {
                    return null;
                }
            } catch (IOException e) {
                throw new GraphException("Could not write zip", e);
            }
        }

        return null;
    }

    private void writeSimpleLinkTSGraph(StringBuffer sb, GraphDataInterface graphData, String callbackURL,
            String linkURL, GraphObject graph) {
        int graphWidth = graphData.getGraphWidth();
        int graphHeight = graphData.getGraphHeight();
        sb.append("<div style=\"background-color:white; width:" + graphWidth + "px; height:" + graphHeight
                + "px;\">\n");
        sb.append("<a href=\"").append(linkURL).append("\">");

        String graphURL = callbackURL + "?graphDataId=" + graphDataId;
        ;
        sb.append("<img src=\"").append(graphURL).append("\" title=\"").append(graphData.getGraphTitle())
                .append("\" border=\"0\"/></a>").append("</div>\n");

    }

    private void writeGraph(StringBuffer sb, GraphDataInterface graphData, boolean useImageMap,
            boolean includeFooter, String callBackURL, String graphOptionsHelpLink, String downloadHelpLink,
            GraphObject graph) {
        writeGraph(sb, graphData, useImageMap, includeFooter, true, callBackURL, graphOptionsHelpLink,
                downloadHelpLink, graph);
    }

    private void writeGraph(StringBuffer sb, GraphDataInterface graphData, boolean useImageMap,
            boolean includeFooter, boolean includeButtons, String callBackURL, String graphOptionsHelpLink,
            String downloadHelpLink, GraphObject graph) {
        int graphWidth = graphData.getGraphWidth();
        int graphHeight = graphData.getGraphHeight();
        String imageMapName = graph.getImageMapName();
        String graphURL = callBackURL + (callBackURL.indexOf('?') > -1 ? "&" : "?") + "graphDataId=" + graphDataId;

        sb.append("<div style=\"background-color:white; width:" + graphWidth + "px\">\n");
        sb.append("<div id=\"graphDiv" + imageMapName + "\" style=\"width:" + graphWidth + "px; height:"
                + graphHeight + "px;\">\n");

        if (useImageMap) {
            // write the graph with an image map
            sb.append(graph.getImageMap());
            sb.append("<img src=\"" + graphURL + "\" usemap=\"#" + imageMapName + "\" border=\"0\"/>\n");
        } else {
            // just write the graph with the option to turn it into an interactive graph
            sb.append("<img src=\"" + graphURL
                    + "\" title=\"Switch to Interactive View\" onclick=\"makeInteractiveGraph('" + callBackURL
                    + "', '" + imageMapName + "', '" + graphDataId + "');\" border=\"0\"/>\n");
        }

        sb.append("</div>\n");

        JFreeChart chart = graph.getGraphSource().getChart();
        String graphTitle = chart.getTitle().getText();

        String xAxisLabel = "";
        String yAxisLabel = "";
        double yAxisMin = 0;
        double yAxisMax = 0;

        if (chart.getPlot() instanceof CategoryPlot) {
            CategoryPlot plot = chart.getCategoryPlot();
            xAxisLabel = plot.getDomainAxis().getLabel();
            yAxisLabel = plot.getRangeAxis().getLabel();
            // get the y-axis minimum and maximum range
            yAxisMin = plot.getRangeAxis().getRange().getLowerBound();
            yAxisMax = plot.getRangeAxis().getRange().getUpperBound();
            // get the y-axis minimum and maximum range
            graph.setYAxisMin(yAxisMin);
            graph.setYAxisMax(yAxisMax);
            //set series information for configuration
            graph.setDataSeriesJSON(getDataSeriesJSON(graphData.getLineSetLabels(), graphData.displayAlerts(),
                    graphData.displaySeverityAlerts(), "\""));
        }

        //added option to not bring back the button area - cjh
        if (includeButtons) {
            // write the footer
            sb.append("<div style=\"padding:5px; text-align:center;\">\n");
            if (includeFooter) {
                //this keys it to be a timeseries graph so we can do getCategoryPlot
                String dataSeriesJSON = getDataSeriesJSON(graphData.getLineSetLabels(), graphData.displayAlerts(),
                        graphData.displaySeverityAlerts(), "&quot;");

                sb.append(
                        "<input type=\"button\" style=\"font-family:Arial; font-size:0.6em;\" value=\"Graph Options\" onclick=\"showTimeSeriesGraphOptions('"
                                + callBackURL + "', '" + imageMapName + "', '" + graphDataId + "', '" + graphTitle
                                + "', '" + xAxisLabel + "', '" + yAxisLabel + "', " + yAxisMin + ", " + yAxisMax
                                + ", '" + dataSeriesJSON + "');\"/>");
                if (graphOptionsHelpLink != null) {
                    sb.append(graphOptionsHelpLink);
                }
            }

            sb.append(
                    "<input type=\"button\" style=\"font-family:Arial; font-size:0.6em;\" value=\"Download\" onclick=\"showDownloadOptions('"
                            + callBackURL + "', '" + imageMapName + "', '" + graphDataId + "');\"/>");

            if (downloadHelpLink != null) {
                sb.append(downloadHelpLink);
            }
            sb.append("</div>\n");
        }
        sb.append("</div>\n");

        if (!useImageMap) {
            sb.append("<div id=\"linkDiv" + imageMapName
                    + "\" style=\"font-family: Arial; font-size: 0.7em; text-align: right\">\n");
            sb.append("*Click anywhere on the graph to <a href=\"#\" onclick=\"makeInteractiveGraph('" + callBackURL
                    + "', '" + imageMapName + "', '" + graphDataId
                    + "'); return false;\">switch to interactive view</a>\n");
            sb.append("</div>\n");
        }
    }

    private void writeGraph(StringBuffer sb, GraphDataInterface graphData, boolean includeFooter,
            String callBackURL, String imageMapName, String graphOptionsHelpLink, String downloadHelpLink,
            Map<String, Object> graphMetaData) {
        writeGraph(sb, graphData, includeFooter, callBackURL + "?graphDataId=" + graphDataId, callBackURL,
                imageMapName, graphOptionsHelpLink, downloadHelpLink, graphMetaData);
    }

    public void writeGraph(StringBuffer sb, GraphDataInterface graphData, boolean includeFooter, String graphURL,
            String callBackURL, String imageMapName, String graphOptionsHelpLink, String downloadHelpLink,
            Map<String, Object> graphMetaData) {

        int graphWidth = graphData.getGraphWidth();
        int graphHeight = graphData.getGraphHeight();

        sb.append("<div style=\"background-color:white; width:" + graphWidth + "px\">\n");
        sb.append("<div id=\"graphDiv" + imageMapName + "\" style=\"width:" + graphWidth + "px; height:"
                + graphHeight + "px;\">\n");

        // just write the graph with the option to turn it into an interactive graph
        sb.append("<img src=\"" + graphURL
                + "\" title=\"Switch to Interactive View\" onclick=\"makeInteractiveGraph('" + callBackURL + "', '"
                + imageMapName + "', '" + graphDataId + "');\" border=\"0\"/>\n");

        sb.append("</div>\n");
        // write the footer
        sb.append("<div style=\"padding:5px; text-align:center;\">\n");

        if (includeFooter) {
            String graphTitle = (String) graphMetaData.get(GraphSource.GRAPH_TITLE);
            String xAxisLabel = (String) graphMetaData.get(GraphSource.GRAPH_X_LABEL);
            String yAxisLabel = (String) graphMetaData.get(GraphSource.GRAPH_Y_LABEL);
            String dataSeriesJSON = getDataSeriesJSON(graphData.getLineSetLabels(), graphData.displayAlerts(),
                    graphData.displaySeverityAlerts(), "&quot;");
            // get the y-axis minimum and maximum range
            double yAxisMin = (Double) graphMetaData.get(GraphSource.GRAPH_RANGE_LOWER_BOUND);
            double yAxisMax = (Double) graphMetaData.get(GraphSource.GRAPH_RANGE_UPPER_BOUND);

            sb.append(
                    "<input type=\"button\" style=\"font-family:Arial; font-size:0.6em;\" value=\"Graph Options\" onclick=\"showTimeSeriesGraphOptions('"
                            + callBackURL + "', '" + imageMapName + "', '" + graphDataId + "', '" + graphTitle
                            + "', '" + xAxisLabel + "', '" + yAxisLabel + "', " + yAxisMin + ", " + yAxisMax + ", '"
                            + dataSeriesJSON + "');\"/>");

            if (graphOptionsHelpLink != null) {
                sb.append(graphOptionsHelpLink);
            }
        }

        sb.append(
                "<input type=\"button\" style=\"font-family:Arial; font-size:0.6em;\" value=\"Download\" onclick=\"showDownloadOptions('"
                        + callBackURL + "', '" + imageMapName + "', '" + graphDataId + "');\"/>");

        if (downloadHelpLink != null) {
            sb.append(downloadHelpLink);
        }

        sb.append("</div>\n");
        sb.append("</div>\n");

        sb.append("<div id=\"linkDiv" + imageMapName
                + "\" style=\"font-family: Arial; font-size: 0.7em; text-align: right\">\n");
        sb.append("*Click anywhere on the graph to <a href=\"#\" onclick=\"makeInteractiveGraph('" + callBackURL
                + "', '" + imageMapName + "', '" + graphDataId
                + "'); return false;\">switch to interactive view</a>\n");
        sb.append("</div>\n");
    }

    private double setDataSeries(GraphDataInterface graphData, String displayKey, boolean useNoDataColor,
            List<DataSeries> dataSeries, LegendItemCollection legendItems) {
        return setDataSeries(graphData, displayKey, useNoDataColor, dataSeries, legendItems, false);
    }

    /**
     * The useItemColor is still under development to allow each bar to be a different color.
     */
    private double setDataSeries(GraphDataInterface graphData, String displayKey, boolean useNoDataColor,
            List<DataSeries> dataSeries, LegendItemCollection legendItems, boolean useItemColor) {
        double[][] counts = graphData.getCounts();
        int[][] colors = graphData.getColors();
        String[][] altTexts = graphData.getAltTexts();
        String[][] lineSetURLs = graphData.getLineSetURLs();
        String[] xLabels = graphData.getXLabels();
        String[] lineSetLabels = graphData.getLineSetLabels();
        boolean[] displayAlerts = graphData.displayAlerts();
        boolean[] displaySeverityAlerts = graphData.displaySeverityAlerts();
        double[] lineSymbolSizes = graphData.getLineSymbolSizes();
        Color[] graphBaseColors = graphData.getGraphBaseColors();
        int displayKeyIndex = 0;
        double maxCount = 0;
        boolean singleAlertLegend = graphData.getShowSingleAlertLegend();
        boolean singleSeverityLegend = graphData.getShowSingleSeverityLegend();

        for (int i = 0; i < counts.length; i++) {
            String lineSetLabel = "series" + (i + 1);
            boolean displayAlert = false;
            boolean displaySeverityAlert = false;
            double lineSymbolSize = 7.0;
            try {
                lineSetLabel = lineSetLabels[i];
            } catch (Exception e) {
            }
            try {
                displayAlert = displayAlerts[i];
            } catch (Exception e) {
            }
            try {
                displaySeverityAlert = displaySeverityAlerts[i];
            } catch (Exception e) {
            }
            try {
                lineSymbolSize = lineSymbolSizes[i];
            } catch (Exception e) {
            }

            double xy = lineSymbolSize / 2.0 * -1;
            Color seriesColor = graphBaseColors[i % graphBaseColors.length];
            boolean displayNormalData = displaySeries(displayKey, displayKeyIndex++) ? true : false;
            boolean displayWarningData = displayAlert && displaySeries(displayKey, displayKeyIndex++) ? true
                    : false;
            boolean displayAlertData = displayAlert && displaySeries(displayKey, displayKeyIndex++) ? true : false;
            boolean displaySevereData = displaySeverityAlert && displaySeries(displayKey, displayKeyIndex++) ? true
                    : false;
            List<DataPoint> points = new ArrayList<DataPoint>();

            /** get graph data */

            for (int j = 0; j < counts[i].length; j++) {
                boolean alertDataExists = false;
                String altText = null;
                String lineSetURL = null;
                int color = 1;
                try {
                    altText = altTexts[i][j];
                } catch (Exception e) {
                }
                try {
                    lineSetURL = lineSetURLs[i][j];
                } catch (Exception e) {
                }
                try {
                    color = colors[i][j];
                } catch (Exception e) {
                }

                Map<String, Object> pointMetaData = new HashMap<String, Object>();
                pointMetaData.put(GraphSource.ITEM_TOOL_TIP, altText);
                pointMetaData.put(GraphSource.ITEM_URL, lineSetURL);
                pointMetaData.put(GraphSource.ITEM_SHAPE,
                        new Ellipse2D.Double(xy, xy, lineSymbolSize, lineSymbolSize));

                pointMetaData.put(GraphSource.ITEM_COLOR, seriesColor);

                // color 0 = GRAY (no data), color 2 = YELLOW (warning), 3 = RED (alert),
                // 4 = PURPLE (severe)
                if (useNoDataColor && color == 0) {
                    pointMetaData.put(GraphSource.ITEM_COLOR, noDataColor);
                } else if (displayWarningData && color == 2) {
                    alertDataExists = true;
                    pointMetaData.put(GraphSource.ITEM_COLOR, warningDataColor);
                } else if (displayAlertData && color == 3) {
                    alertDataExists = true;
                    pointMetaData.put(GraphSource.ITEM_COLOR, alertDataColor);
                } else if (displaySevereData && color == 4) {
                    alertDataExists = true;
                    pointMetaData.put(GraphSource.ITEM_COLOR, severeDataColor);
                }

                if (useItemColor) {
                    seriesColor = graphBaseColors[j % graphBaseColors.length];
                    pointMetaData.put(GraphSource.ITEM_COLOR, seriesColor);
                }

                if (displayNormalData || alertDataExists) {
                    // only update the maxCount if this data point is visible
                    if (counts[i][j] > maxCount) {
                        maxCount = counts[i][j];
                    }
                } else {
                    // if normal data is supposed to be hidden and no alert data exists, then hide this
                    // data point
                    pointMetaData.put(GraphSource.ITEM_VISIBLE, false);
                }

                // if the data is set to the Double.MIN_VALUE, then add it as a null.
                if (counts[i][j] != Double.MIN_VALUE) {
                    points.add(new DataPoint(counts[i][j], xLabels[j], pointMetaData));
                } else {
                    points.add(new DataPoint(null, xLabels[j], pointMetaData));
                }

            }

            /** add the series */

            // series properties
            Map<String, Object> dataSeriesMetaData = new HashMap<String, Object>();
            dataSeriesMetaData.put(GraphSource.SERIES_TITLE, lineSetLabel);
            dataSeriesMetaData.put(GraphSource.SERIES_COLOR, seriesColor);
            // if normal data is hidden for this series, hide the series connector line
            dataSeriesMetaData.put(GraphSource.SERIES_LINES_VISIBLE, displayNormalData);
            dataSeries.add(new DataSeries(points, dataSeriesMetaData));

            if (legendItems != null) {
                if (displayNormalData && legendItems.getItemCount() < maxLegendItems) {
                    if (displayAlert && !singleAlertLegend) {
                        legendItems
                                .add(new LegendItem(lineSetLabel + ": " + getTranslation("Normal"), seriesColor));
                    } else {
                        legendItems.add(new LegendItem(lineSetLabel, seriesColor));
                    }
                }
                if (!singleAlertLegend && displayWarningData && legendItems.getItemCount() < maxLegendItems) {
                    legendItems
                            .add(new LegendItem(lineSetLabel + ": " + getTranslation("Warning"), warningDataColor));
                }
                if (!singleAlertLegend && displayAlertData && legendItems.getItemCount() < maxLegendItems) {
                    legendItems.add(new LegendItem(lineSetLabel + ": " + getTranslation("Alert"), alertDataColor));
                }
                if (!singleSeverityLegend && displaySevereData && legendItems.getItemCount() < maxLegendItems) {
                    legendItems
                            .add(new LegendItem(lineSetLabel + ": " + getTranslation("Severe"), severeDataColor));
                }
            }
        }

        if (singleAlertLegend && legendItems.getItemCount() < maxLegendItems) {
            legendItems.add(new LegendItem(getTranslation("Warning"), warningDataColor));
            legendItems.add(new LegendItem(getTranslation("Alert"), alertDataColor));
        }
        if (singleSeverityLegend && legendItems.getItemCount() < maxLegendItems) {
            legendItems.add(new LegendItem(getTranslation("Severe"), severeDataColor));
        }
        return maxCount;
    }

    public void setTimeSeriesGraphMetaData(GraphDataInterface graphData, double maxCount,
            Map<String, Object> graphMetaData) {
        setTimeSeriesGraphMetaData(graphData, null, null, maxCount, graphMetaData);
    }

    public void setTimeSeriesGraphMetaData(GraphDataInterface graphData, Double yAxisMin, Double yAxisMax,
            double maxCount, Map<String, Object> graphMetaData) {
        String graphTitle = graphData.getGraphTitle() != null ? graphData.getGraphTitle() : "";
        String xAxisLabel = graphData.getXAxisLabel() != null ? graphData.getXAxisLabel() : "";
        String yAxisLabel = graphData.getYAxisLabel() != null ? graphData.getYAxisLabel() : "";
        int graphWidth = graphData.getGraphWidth();
        int graphHeight = graphData.getGraphHeight();
        boolean percentBased = graphData.percentBased();
        int maxLabeledCategoryTicks = graphData.getMaxLabeledCategoryTicks();

        graphMetaData.put(GraphSource.GRAPH_TYPE, GraphSource.GRAPH_TYPE_LINE);
        graphMetaData.put(GraphSource.BACKGROUND_COLOR, Color.WHITE);
        graphMetaData.put(GraphSource.GRAPH_TITLE, graphTitle);
        graphMetaData.put(GraphSource.GRAPH_FONT, graphFont);
        graphMetaData.put(GraphSource.GRAPH_MINOR_TICKS, 0);
        graphMetaData.put(GraphSource.GRAPH_LEGEND, graphData.showLegend());
        graphMetaData.put(GraphSource.LEGEND_FONT, legendFont);

        SparselyLabeledCategoryAxis domainAxis;

        if (graphWidth >= 500 && graphHeight >= 300) {
            // this is a larger graph so we can add some additional properties to pretty it up
            graphMetaData.put(GraphSource.GRAPH_BORDER, true);
            graphMetaData.put(GraphSource.AXIS_OFFSET, 5.0);
            graphMetaData.put(GraphSource.GRAPH_RANGE_GRIDLINE_PAINT, Color.lightGray);

            if (yAxisLabel == null && percentBased) {
                yAxisLabel = getTranslation("Percent");
            } else if (yAxisLabel == null) {
                yAxisLabel = getTranslation("Counts");
            }

            if (xAxisLabel == null) {
                xAxisLabel = getTranslation("Date");
            }

            domainAxis = new SparselyLabeledCategoryAxis(maxLabeledCategoryTicks, Color.lightGray);
        } else {
            yAxisLabel = "";
            xAxisLabel = "";
            domainAxis = new SparselyLabeledCategoryAxis(maxLabeledCategoryTicks);
        }

        domainAxis.setCategoryLabelPositions(CategoryLabelPositions.createDownRotationLabelPositions(45));
        domainAxis.setMaximumCategoryLabelWidthRatio(maxCategoryLabelWidthRatio);
        graphMetaData.put(JFreeChartCategoryGraphSource.DOMAIN_AXIS, domainAxis);

        graphMetaData.put(GraphSource.GRAPH_RANGE_INTEGER_TICK, !percentBased);
        graphMetaData.put(GraphSource.GRAPH_RANGE_MINOR_TICK_VISIBLE, false);

        if (yAxisMin != null && yAxisMax != null) {
            graphMetaData.put(GraphSource.GRAPH_RANGE_LOWER_BOUND, yAxisMin);
            graphMetaData.put(GraphSource.GRAPH_RANGE_UPPER_BOUND, yAxisMax);
        } else {
            graphMetaData.put(GraphSource.GRAPH_RANGE_LOWER_BOUND, 0.0);

            if (maxCount == 0) {
                // if there is no data, set the upper bound to 1.0, otherwise we
                // get a weird looking y-axis
                graphMetaData.put(GraphSource.GRAPH_RANGE_UPPER_BOUND, 1.0);
            }
            // if the maxCount is less than 1, Y-Axis labels are not displayed.
            // Found during testing % data that may be 1%
            else if (maxCount < 1) {
                graphMetaData.put(GraphSource.GRAPH_RANGE_INTEGER_TICK, false);
                graphMetaData.put(GraphSource.GRAPH_RANGE_UPPER_BOUND, maxCount * 1.05);
            } else {
                graphMetaData.put(GraphSource.GRAPH_RANGE_UPPER_BOUND, maxCount * 1.05);
            }
        }

        graphMetaData.put(GraphSource.GRAPH_Y_LABEL, yAxisLabel);
        graphMetaData.put(GraphSource.GRAPH_Y_AXIS_FONT, rangeAxisFont);
        graphMetaData.put(GraphSource.GRAPH_Y_AXIS_LABEL_FONT, rangeAxisLabelFont);
        graphMetaData.put(GraphSource.GRAPH_X_LABEL, xAxisLabel);
        graphMetaData.put(GraphSource.GRAPH_X_AXIS_FONT, domainAxisFont);
        graphMetaData.put(GraphSource.GRAPH_X_AXIS_LABEL_FONT, domainAxisLabelFont);
    }

    public void setBarGraphMetaData(GraphDataInterface graphData, boolean stackGraph,
            Map<String, Object> graphMetaData) {
        String graphTitle = graphData.getGraphTitle() != null ? graphData.getGraphTitle() : "";
        String xAxisLabel = graphData.getXAxisLabel() != null ? graphData.getXAxisLabel() : "";
        String yAxisLabel = graphData.getYAxisLabel() != null ? graphData.getYAxisLabel() : "";
        int graphWidth = graphData.getGraphWidth();
        int graphHeight = graphData.getGraphHeight();
        boolean percentBased = graphData.percentBased();
        boolean plotHorizontal = graphData.plotHorizontal();
        int maxLabeledCategoryTicks = graphData.getMaxLabeledCategoryTicks();

        if (stackGraph) {
            graphMetaData.put(GraphSource.GRAPH_TYPE, GraphSource.GRAPH_TYPE_STACKED_BAR);
        } else {
            graphMetaData.put(GraphSource.GRAPH_TYPE, GraphSource.GRAPH_TYPE_BAR);
        }

        if (plotHorizontal) {
            graphMetaData.put(JFreeChartBarGraphSource.PLOT_ORIENTATION, PlotOrientation.HORIZONTAL);
        }

        graphMetaData.put(GraphSource.GRAPH_LABEL_BACKGROUND_COLOR, Color.WHITE);
        graphMetaData.put(GraphSource.BACKGROUND_COLOR, Color.WHITE);
        graphMetaData.put(GraphSource.GRAPH_TITLE, graphTitle);
        graphMetaData.put(GraphSource.GRAPH_FONT, graphFont);
        graphMetaData.put(GraphSource.GRAPH_BORDER, false);
        graphMetaData.put(GraphSource.GRAPH_LEGEND, graphData.showLegend());
        graphMetaData.put(GraphSource.LEGEND_FONT, legendFont);

        SparselyLabeledCategoryAxis domainAxis;

        if (graphWidth >= 500 && graphHeight >= 300) {
            // this is a larger graph so we can add some additional properties to pretty it up
            graphMetaData.put(GraphSource.GRAPH_BORDER, true);
            graphMetaData.put(GraphSource.AXIS_OFFSET, 5.0);
            graphMetaData.put(GraphSource.GRAPH_RANGE_GRIDLINE_PAINT, Color.lightGray);

            domainAxis = new SparselyLabeledCategoryAxis(maxLabeledCategoryTicks, Color.lightGray);
        } else {
            domainAxis = new SparselyLabeledCategoryAxis(maxLabeledCategoryTicks);
        }

        if (!plotHorizontal) {
            // don't rotate labels if this is a horizontal graph
            domainAxis.setCategoryLabelPositions(CategoryLabelPositions.createDownRotationLabelPositions(45));
        }

        domainAxis.setMaximumCategoryLabelWidthRatio(maxCategoryLabelWidthRatio);
        graphMetaData.put(JFreeChartCategoryGraphSource.DOMAIN_AXIS, domainAxis);

        graphMetaData.put(GraphSource.GRAPH_RANGE_AXIS_LOCATION, AxisLocation.BOTTOM_OR_LEFT);
        graphMetaData.put(GraphSource.GRAPH_RANGE_INTEGER_TICK, !percentBased);
        graphMetaData.put(GraphSource.GRAPH_RANGE_MINOR_TICK_VISIBLE, false);
        graphMetaData.put(GraphSource.GRAPH_Y_LABEL, yAxisLabel);
        graphMetaData.put(GraphSource.GRAPH_Y_AXIS_FONT, rangeAxisFont);
        graphMetaData.put(GraphSource.GRAPH_Y_AXIS_LABEL_FONT, rangeAxisLabelFont);
        graphMetaData.put(GraphSource.GRAPH_X_LABEL, xAxisLabel);
        graphMetaData.put(GraphSource.GRAPH_X_AXIS_FONT, domainAxisFont);
        graphMetaData.put(GraphSource.GRAPH_X_AXIS_LABEL_FONT, domainAxisLabelFont);
    }

    public void setPieGraphMetaData(GraphDataInterface graphData, Map<String, Object> graphMetaData,
            List<PointInterface> points) {
        double[][] counts = graphData.getCounts();
        String[][] altTexts = graphData.getAltTexts();
        String[][] lineSetURLs = graphData.getLineSetURLs();
        String[] lineSetLabels = graphData.getLineSetLabels();
        String graphTitle = graphData.getGraphTitle() != null ? graphData.getGraphTitle() : "";
        String graphNoDataMessage = graphData.getNoDataMessage();
        Color[] graphBaseColors = graphData.getGraphBaseColors();
        boolean graphDisplayLabel = graphData.getShowGraphLabels();

        for (int i = 0; i < counts.length; i++) {
            String lineSetLabel = "series" + (i + 1);
            String altText = null;
            String lineSetURL = null;
            try {
                lineSetLabel = lineSetLabels[i];
            } catch (Exception e) {
            }
            try {
                altText = altTexts[i][0];
            } catch (Exception e) {
            }
            try {
                lineSetURL = lineSetURLs[i][0];
            } catch (Exception e) {
            }

            Map<String, Object> pointMetaData = new HashMap<String, Object>();
            pointMetaData.put(GraphSource.ITEM_TOOL_TIP, altText);
            pointMetaData.put(GraphSource.ITEM_URL, lineSetURL);
            pointMetaData.put(GraphSource.ITEM_COLOR, graphBaseColors[i % graphBaseColors.length]);
            points.add(new DataPoint(counts[i][0], lineSetLabel, pointMetaData));
        }

        Font font = graphFont;
        if (graphData.getTitleFont() != null) {
            font = graphData.getTitleFont();
        }

        graphMetaData.put(GraphSource.GRAPH_TYPE, GraphSource.GRAPH_TYPE_PIE);
        graphMetaData.put(GraphSource.BACKGROUND_COLOR, graphData.getBackgroundColor()); //edit to get graph data background color, defaults to white
        graphMetaData.put(GraphSource.GRAPH_LABEL_BACKGROUND_COLOR, graphData.getLabelBackgroundColor());
        graphMetaData.put(GraphSource.GRAPH_TITLE, graphTitle);
        graphMetaData.put(GraphSource.GRAPH_FONT, font);
        graphMetaData.put(GraphSource.GRAPH_BORDER, false);
        graphMetaData.put(GraphSource.GRAPH_DISPLAY_LABEL, graphDisplayLabel);
        graphMetaData.put(GraphSource.GRAPH_NO_DATA_MESSAGE, graphNoDataMessage);
        graphMetaData.put(GraphSource.GRAPH_LEGEND, graphData.showLegend());
        graphMetaData.put(GraphSource.LEGEND_FONT, legendFont);
    }

    private GraphObject getGraph(GraphDataInterface graphData, List<DataSeries> series,
            Map<String, Object> graphMetaData, LegendItemCollection legendItems, String graphType) {

        GraphObject graph = null;
        String graphTitle = graphData.getGraphTitle();

        try {
            // add the created chart properties
            JFreeChartGraphSource graphSource = new JFreeChartGraphSource();
            graphSource.setData(series);
            graphSource.setParams(graphMetaData);
            graphSource.initialize();

            // add the custom legend
            graphSource.getChart().getCategoryPlot().setFixedLegendItems(legendItems);

            // render the graph to get the image map
            RenderedGraph renderedGraph = graphSource.renderGraph(graphData.getGraphWidth(),
                    graphData.getGraphHeight(), Encoding.PNG);
            String imageFileName = getCleanValue(graphTitle) + "_" + graphType + ".png";
            // get the image map
            String imageMapName = "imageMap" + graphDataId;
            String imageMap = appendImageMapTarget(renderedGraph.getImageMap(imageMapName),
                    graphData.getLineSetURLTarget());

            try {
                // store away the graph data file
                graphDataHandler.putGraphData(graphData, graphDataId);

                graph = new GraphObject(graphSource, renderedGraph, imageFileName, imageMapName, imageMap,
                        graphDataId);
            } catch (GraphException e) {
                System.out.println(e.getMessage());
                e.printStackTrace();
            }
        } catch (GraphException e) {
            System.out.println("Could not create graph " + graphTitle);
            e.printStackTrace();
        }

        return graph;
    }

    private Map<String, Object> dumpGraph(GraphDataInterface graphData) {
        // setup the default metadata
        List<DataSeries> dataSeries = new ArrayList<DataSeries>();
        LegendItemCollection legendItems = new LegendItemCollection();
        Map<String, Object> graphMetaData = new HashMap<String, Object>();
        double maxCount = setDataSeries(graphData, null, false, dataSeries, legendItems);

        setTimeSeriesGraphMetaData(graphData, null, null, maxCount, graphMetaData);

        // store away the graph data file
        try {
            graphDataHandler.putGraphData(graphData, graphDataId);
        } catch (GraphException e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }

        return graphMetaData;
    }

    private static String getUniqueId(String userId) {
        Date currentTime = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMMdd_hh_mm_ss_SSS");

        if (userId != null && userId.length() > 0) {
            return userId + "_" + sdf.format(currentTime) + "_" + (int) (Math.random() * 10000);
        } else {
            return sdf.format(currentTime) + "_" + (int) (Math.random() * 10000);
        }
    }

    private String appendImageMapTarget(String imageMap, String target) {
        if (target != null && target.length() > 0) {
            return imageMap.replace("<area ", "<area target=\"" + target + "\" ");
        }

        return imageMap;
    }

    private String getCleanValue(String value) {
        if (value == null) {
            return "";
        }

        // illegal characters for file names on windows are \/:*?"<>|
        String cleanValue = value.replaceAll("\\\\", "-");
        cleanValue = cleanValue.replaceAll("/", "-");
        cleanValue = cleanValue.replaceAll(":", "-");
        cleanValue = cleanValue.replaceAll("\\*", "-");
        cleanValue = cleanValue.replaceAll("\\?", "-");
        cleanValue = cleanValue.replaceAll("\"", "-");
        cleanValue = cleanValue.replaceAll("<", "-");
        cleanValue = cleanValue.replaceAll(">", "-");
        cleanValue = cleanValue.replaceAll("\\|", "-");

        cleanValue = cleanValue.replaceAll(";", "-");
        cleanValue = cleanValue.replaceAll("\\+", "-");

        return cleanValue;
    }

    private boolean displaySeries(String displayKey, int seriesIndex) {
        if (displayKey != null && displayKey.length() > seriesIndex && displayKey.charAt(seriesIndex) == '0') {
            return false;
        } else {
            return true;
        }
    }

    private String getDataSeriesJSON(String[] lineSetLabels, boolean[] displayAlerts,
            boolean[] displaySeverityAlerts, String quoteStr) {
        String json = "";

        if (lineSetLabels != null) {
            for (int i = 0; i < lineSetLabels.length; i++) {
                boolean displayAlert = false;
                boolean displaySeverityAlert = false;
                try {
                    displayAlert = displayAlerts[i];
                } catch (Exception e) {
                }
                try {
                    displaySeverityAlert = displaySeverityAlerts[i];
                } catch (Exception e) {
                }

                if (displayAlert) {
                    json += getDataSeriesJSONHelper(lineSetLabels[i],
                            lineSetLabels[i] + ": " + getTranslation("Normal"), true, quoteStr);
                    json += ", ";
                    json += getDataSeriesJSONHelper(lineSetLabels[i],
                            lineSetLabels[i] + ": " + getTranslation("Warning"), true, quoteStr);
                    json += ", ";
                    json += getDataSeriesJSONHelper(lineSetLabels[i],
                            lineSetLabels[i] + ": " + getTranslation("Alert"), true, quoteStr);
                    json += ", ";

                    if (displaySeverityAlert) {
                        json += getDataSeriesJSONHelper(lineSetLabels[i],
                                lineSetLabels[i] + ": " + getTranslation("Severe"), true, quoteStr);
                        json += ", ";
                    }
                } else {
                    json += getDataSeriesJSONHelper(lineSetLabels[i], lineSetLabels[i], false, quoteStr);
                    json += ", ";
                }
            }

            if (json.length() > 0) {
                json = json.substring(0, json.length() - 2);
            }
        }

        return "{ [ " + json + " ] }";
    }

    private String getDataSeriesJSONHelper(String seriesName, String displayName, boolean displayAlerts,
            String quoteStr) {
        String json = "";
        json += "{ ";
        json += "seriesName:";
        json += quoteStr + seriesName + quoteStr;
        json += ", displayName:";
        json += quoteStr + displayName + quoteStr;
        json += ", displayAlerts:" + displayAlerts + " ";
        json += "}";
        return json;
    }
}