
// Copyright (c) 1999, 2000 Oracle Corporation
package oracle.jbo.html.jsp.graph;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

import java.util.Enumeration;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;

import oracle.dss.graph.Graph;
import oracle.dss.util.DefaultErrorHandler;


public class GraphTagBase extends TagSupport
    implements GraphConstants
{

   protected String graphType = "PIE";
   
   protected int graphTypeAsInt = 55;

   GraphTagSessionBindingListener sessionListener;

   Graph graph = null;

   String commonScriptName = "GraphHelper.jsp";

   /* image dimensions */
   int width = 500;
   int height = 500;

   /**
   * register listener to clean up
   */
   protected static boolean cleanupRegistered = false;

   /**
   * unique prefix., used while generating key  for image objects stored
   * in the session. Later used in cleanup when the session expires
   */
   protected static String prefixString = "oragraph111";


   public GraphTagBase()
   {
	   super();

       graph = new Graph();

	   init(graph);
   }

   public Graph getGraph()
   {
	   return graph;
   }
   
   public static int s2i(String s)
   {
       return GraphConstantsHelper.s2i(s);
   }

   public void setGraphType(String s)
   {
	   graphType = s;
       
       int i = s2i(s);
       
       if ( i == -1)
       {
           System.out.println("Error : invalid graph type");
       }
       else
       {
           setGraphTypeAsInt(i);
       }
   }

   public String getGraphType()
   {
	   return graphType;
   }
   
   protected void setGraphTypeAsInt(int i)
   {
       graphTypeAsInt = i;
   }
   
   protected int getGraphTypeAsInt()
   {
       return graphTypeAsInt;
   }

   public void setImageWidth(int width)
   {
	   this.width = width;
   }

   public int getImageWidth()
   {
	   return width;
   }

   public void setImageHeight(int height)
   {
	   this.height = height;
   }

   public int getImageHeight()
   {
	   return height;
   }

   public void setCommonScriptName(String commonScriptName)
   {
	this.commonScriptName = commonScriptName;
   }

   public String getCommonScriptName()
   {
	return this.commonScriptName;
   }

   public static String getIDParamName()
   {
	return "id";
   }
   
   
    private void init(Graph control)
    {
         Object errHandler = control.getErrorHandler();

	     if ( (errHandler != null) && (errHandler instanceof DefaultErrorHandler))
         {
	       DefaultErrorHandler defErrHandler = (DefaultErrorHandler) errHandler;

	       defErrHandler.setDebugMode(DefaultErrorHandler.SHOW_ERROR);
	     }
    }

   /**
   * Process the start tag for this instance.
   *
   * The doStartTag() method assumes that all setter methods have been
   * invoked before.
   *
   * When this method is invoked, the body has not yet been invoked.
   *
   * @returns EVAL_BODY_INCLUDE if the tag wants to process body, SKIP_BODY if it
   * does ont want to process it.
   */
   public int doStartTag() throws JspException
   {
      registerCleanup();

      // Set the attribute on the pageContext for the scriptable variable (PAGE_SCOPE because of Orion)
      pageContext.setAttribute("graph", graph);

      graph.setGraphType(getGraphTypeAsInt());
     
      return Tag.EVAL_BODY_INCLUDE;
   }

   /**
   *  Graph tag body will include SingleTableGraph/MasterDetailGraph, which 
   *  will supply the required data
   */
   public int doEndTag()
		throws JspException
   {
      JspWriter out = pageContext.getOut();

      String id = generateUniqueId();
       
      String idParam = getIDParamName() + "=" + id;
      
      String url = getCommonScriptName() + "?" +  idParam  ;
      
      String link = "<IMG SRC=\"" + url + "\" WIDTH= " +
                  getImageWidth() + " HEIGHT=" + getImageHeight() + ">";

      try
      {
        storeImageInSession(id);
    
        out.println(link);
      }
      catch(Exception exc)
      {
	   exc.printStackTrace(); // TODO

	   throw new JspException(exc.getMessage());
      }

      return EVAL_PAGE;
   }

   void storeImageInSession(String id)
   {
	   ByteArrayOutputStream bos = new  ByteArrayOutputStream( getImageWidth() 
						* getImageHeight());

	   graph.exportToJPEG(bos, 100 /* quality */);

       pageContext.getSession().setAttribute(id, bos);
   }

   /**
   * release() called after doEndTag() to reset state
   */
   public void release()
   {
      super.release();
   }

   // impl methods

   /**
   * register HTTP Session binding listner to cleanup the
   * chart objects generated in this session
   */
   protected void registerCleanup( )
   {
        synchronized(this)
        {
            if ( cleanupRegistered )
               return;

	        HttpSession session = pageContext.getSession();

            if ( session != null )
            {
               sessionListener = new GraphTagSessionBindingListener();

               session.setAttribute("bindings.listener", sessionListener);

               cleanupRegistered = true;
            }
        }
   }

   /**
   * unregister HTTP Session binding listner used to cleanup the
   * chart objects generated in this session
   */
   protected void unregisterCleanup()
   {
        synchronized(this)
        {
            if ( !cleanupRegistered )
               return;

	        HttpSession session = pageContext.getSession();

            if ( session != null )
            {

              session.removeValue("bindings.listener");

              cleanupRegistered = false;
            }
        }
   }

   /**
   *  generated an unique id to identify chart., used in the url parameter
   */
   protected static String generateUniqueId()
   {
        String uid = new java.rmi.server.UID().toString();

        return prefixString + uid;
   }


   public static void generateImage(HttpSession session, 
					HttpServletRequest request, 
					HttpServletResponse response)
	throws JspException
   {

        try
        {
            String id = request.getParameter(getIDParamName());
        
            if ( id == null )
            {
                StringBuffer str = new StringBuffer();
                
                str.append("HTTP request should include 'ID' parameter.");
        
                throw new JspException(str.toString());
                }
            else
            {
                Object val = session.getAttribute(id);
    
                if ( val instanceof ByteArrayOutputStream)
                {
                            generateImage(response, (ByteArrayOutputStream)val);
                }
                else
                {
                    throw new JspException("GraphTag :invalid object type in session ");
                }
             }
        }
        catch(Exception exc)
        {
            throw new JspException(exc.getMessage());
        }
    }


    public static void generateImage(HttpServletResponse response, 
					ByteArrayOutputStream bos)
		throws JspException
    {
        try
        {
            response.setContentType("image/gif");

            response.getOutputStream().write( bos.toByteArray());
        }
        catch(IOException exc)
        {
            throw new JspException(exc.getMessage());
        }
    }
}



class GraphTagSessionBindingListener
	implements HttpSessionBindingListener
{

    public GraphTagSessionBindingListener()
    {
	   super();
    }

    // HttpSessionBindingListener interface
    public void valueBound(HttpSessionBindingEvent event)
    {
    }

    public void valueUnbound(HttpSessionBindingEvent event)
    {
        System.out.println(getClass().toString() + "  valueUnBound"); 

        HttpSession session = event.getSession();

        try
        {
	    Enumeration enum = session.getAttributeNames();

	    for (Enumeration e = session.getAttributeNames(); e.hasMoreElements() ;) 
            {
		Object o  = e.nextElement();

		if ( o != null )
		{
		    String name = o.toString();
		    if (name.startsWith(GraphTagBase.prefixString))
	                   session.removeAttribute(name);	
		}
            }
        }
        catch(Exception e)
        {
		System.out.println("error occured in Graph session listener " 
 					+ e.getMessage());
        }
    }
}


