/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2005 Bull S.A.
 * Contact: jonas-team@ow2.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.webapp.jonasadmin.monitoring;

// servlet imports
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;

import javax.imageio.IIOException;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.ow2.jonas.lib.management.extensions.base.JonasManagementRepr;
import org.ow2.jonas.lib.management.javaee.J2eeObjectName;
import org.ow2.jonas.lib.util.Log;
import org.ow2.jonas.webapp.jonasadmin.WhereAreYou;

import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;

/**
 * @author Adriana Danes
 * <br>Contributor Michel-Ange Anton
 */
public class MemoryGraphServlet extends HttpServlet {

    /**
     * Logger.
     */
    private static Logger logger = Log.getLogger(Log.JONAS_ADMIN_PREFIX);


    private static final int HEIGHT = 180;
    private static final int TOP_MARGIN = 35;
    private static final int RIGHT_MARGIN = 80;
    private static final int BOTTOM_MARGIN = 10;
    private static final int LEFT_MARGIN = 70;
    private static final int HORIZONTAL_SPACE = 30;

    private static final int Y_LENGTH = HEIGHT - TOP_MARGIN - BOTTOM_MARGIN; // the graph height
    private static final int GAUGE_WIDTH = 10;

    private static final Color BG_COLOR = new Color(0x006699);
    private static final Color FG_COLOR = Color.white;
    private static final Color GRAPHICS_BG_COLOR = Color.lightGray;
    private static final Color GRAPHICS_FG_COLOR = Color.darkGray;
    private static final Color AXIS_COLOR = Color.white;
    private static final Color TEXT_COLOR = Color.white;

    /**
     * Respond to a GET request for the content produced by
     * this servlet.
     *
     * @param req The servlet request we are processing
     * @param res The servlet response we are producing
     *
     * @exception IOException if an input/output error occurs
     * @exception ServletException if a servlet error occurs
     */
    public void doGet(HttpServletRequest req, HttpServletResponse res)
        throws IOException, ServletException {

        HttpSession oSession = req.getSession();
        WhereAreYou oWhere = (WhereAreYou) oSession.getAttribute(WhereAreYou.SESSION_NAME);
        String serverName = oWhere.getCurrentJonasServerName();
        String domainName = oWhere.getCurrentDomainName();

        res.setContentType("image/png");
        OutputStream out = res.getOutputStream();

        // get the data to draw:
        Long[] data = (Long[]) JonasManagementRepr.getAttribute(J2eeObjectName.J2EEServer(domainName, serverName), "tableMeasures", serverName);
        int xLength = 2 * data.length;
        int width = LEFT_MARGIN + xLength + HORIZONTAL_SPACE + GAUGE_WIDTH + RIGHT_MARGIN;

        BufferedImage img = new BufferedImage(width, HEIGHT, BufferedImage.TYPE_INT_RGB);
        Graphics g = img.getGraphics();

        // fill the image background:
        g.setColor(BG_COLOR);
        g.fillRect(0, 0, width, HEIGHT);

        // firstly, the memory used history:

        // draw the chart area:
        g.setColor(GRAPHICS_BG_COLOR);
        g.fillRect(cartesianXToGraphicsX(0), cartesianYToGraphicsY(Y_LENGTH), xLength - 1, Y_LENGTH);

        // search the max value in the data array:
        long yMax = data[0].longValue();
        for (int i = 1; i < data.length; i++) {
            yMax = Math.max(yMax, data[i].longValue());

            // looking for k and n where: k.10^n <= yMax < (k+1).10^n
        }
        long tmp = yMax;
        int n = 0;
        while ((tmp / 10) >= 1) {
            tmp = tmp / 10;
            n++;
        }
        long k = tmp % 10;

        // pow = 10^n
        int pow = 1;
        for (int i = 0; i < n; i++) {
            pow = pow * 10;

            // draw the range on the y axis:
        }
        for (int i = 1; i <= k; i++) {
            int y = (new Long(i * Y_LENGTH / (k + 1))).intValue();
            g.setColor(FG_COLOR);
            g.drawLine(cartesianXToGraphicsX( -3), cartesianYToGraphicsY(y)
                , cartesianXToGraphicsX(xLength), cartesianYToGraphicsY(y));
            g.setColor(TEXT_COLOR);
            g.drawString("" + (i * pow), cartesianXToGraphicsX( -18 - n * 6)
                , cartesianYToGraphicsY(y - 5));
        }

        // draw the values:
        g.setColor(GRAPHICS_FG_COLOR);
        for (int i = 0; i < data.length; i++) {
            int y = (new Long(data[i].longValue() * Y_LENGTH / ((k + 1) * pow))).intValue();
            g.drawLine(cartesianXToGraphicsX(2 * i), cartesianYToGraphicsY(0)
                , cartesianXToGraphicsX(2 * i), cartesianYToGraphicsY(y));
        }

        g.setColor(TEXT_COLOR);
        g.drawString("History of memory used", cartesianXToGraphicsX(0)
            , cartesianYToGraphicsY(Y_LENGTH + 20));
        g.drawString("(Kbytes)", cartesianXToGraphicsX(0), cartesianYToGraphicsY(Y_LENGTH + 10));
        g.drawString("0", cartesianXToGraphicsX( -12), cartesianYToGraphicsY( -5));
        g.setColor(AXIS_COLOR);
        g.drawLine(cartesianXToGraphicsX( -3), cartesianYToGraphicsY(0)
            , cartesianXToGraphicsX(xLength), cartesianYToGraphicsY(0));
        g.drawLine(cartesianXToGraphicsX( -1), cartesianYToGraphicsY(0), cartesianXToGraphicsX( -1)
            , cartesianYToGraphicsY(Y_LENGTH));
        g.drawLine(cartesianXToGraphicsX(xLength - 2), cartesianYToGraphicsY(0)
            , cartesianXToGraphicsX(xLength - 2), cartesianYToGraphicsY(Y_LENGTH));

        // secondly, the current memory used:

        int xGauge = LEFT_MARGIN + xLength + HORIZONTAL_SPACE;

        g.setColor(GRAPHICS_BG_COLOR);
        g.fillRect(xGauge, cartesianYToGraphicsY(Y_LENGTH), GAUGE_WIDTH, Y_LENGTH);

        long usedMemory = ((Long) JonasManagementRepr.getAttribute(J2eeObjectName.J2EEServer(domainName, serverName)
            , "currentUsedMemory", serverName)).longValue();
        long totalMemory = ((Long) JonasManagementRepr.getAttribute(J2eeObjectName.J2EEServer(domainName, serverName)
            , "currentTotalMemory", serverName)).longValue();

        g.setColor(GRAPHICS_FG_COLOR);
        int y = (new Long(usedMemory * Y_LENGTH / totalMemory)).intValue();
        g.fillRect(xGauge, cartesianYToGraphicsY(y), GAUGE_WIDTH, y);

        g.setColor(AXIS_COLOR);
        g.drawRect(xGauge, cartesianYToGraphicsY(Y_LENGTH), GAUGE_WIDTH, Y_LENGTH);

        g.setColor(TEXT_COLOR);
        g.drawString("0", xGauge + GAUGE_WIDTH + 3, cartesianYToGraphicsY( -5));
        g.drawString("" + usedMemory, xGauge + GAUGE_WIDTH + 3
            , cartesianYToGraphicsY(Math.min(y - 5, Y_LENGTH - 25)));
        g.drawString("(current)", xGauge + GAUGE_WIDTH + 3, cartesianYToGraphicsY(Math.min(y - 15
            , Y_LENGTH - 35)));
        g.drawString("" + totalMemory, xGauge + GAUGE_WIDTH + 3, cartesianYToGraphicsY(Y_LENGTH - 5));
        g.drawString("(total)", xGauge + GAUGE_WIDTH + 3, cartesianYToGraphicsY(Y_LENGTH - 15));
        g.drawString("Memory used", xGauge, cartesianYToGraphicsY(Y_LENGTH + 20));
        g.drawString("(Kbytes)", xGauge, cartesianYToGraphicsY(Y_LENGTH + 10));

        try {
            ImageIO.write(img, "png", out);
        } catch (IIOException iioe) {
            logger.log(BasicLevel.DEBUG, "Flushing problem", iioe);
        }
        out.close();
    }

    /**
     * @param length the data array size (data.length)
     * @return the picture width when displaying an array of the specified size
     */
    public static int getWidth(int length) {
        return LEFT_MARGIN + 2 * length + HORIZONTAL_SPACE + GAUGE_WIDTH + RIGHT_MARGIN;
    }

    /**
     * @return the picture height
     */
    public static int getHeight() {
        return HEIGHT;
    }

    private int cartesianXToGraphicsX(int x) {
        return x + LEFT_MARGIN;
    }

    private int cartesianYToGraphicsY(int y) {
        return HEIGHT - 1 - y - BOTTOM_MARGIN;
    }
}
