/*
 * The contents of this file are subject to the terms 
 * of the Common Development and Distribution License 
 * (the "License").  You may not use this file except 
 * in compliance with the License.
 * 
 * You can obtain a copy of the license at 
 * glassfish/bootstrap/legal/CDDLv1.0.txt or 
 * https://glassfish.dev.java.net/public/CDDLv1.0.html. 
 * See the License for the specific language governing 
 * permissions and limitations under the License.
 * 
 * When distributing Covered Code, include this CDDL 
 * HEADER in each file and include the License file at 
 * glassfish/bootstrap/legal/CDDLv1.0.txt.  If applicable, 
 * add the following below this CDDL HEADER, with the 
 * fields enclosed by brackets "[]" replaced with your 
 * own identifying information: Portions Copyright [yyyy] 
 * [name of copyright owner]
 */

package com.sun.enterprise.tools.guiframework.view;

import com.iplanet.jato.RequestManager;

import com.sun.enterprise.tools.guiframework.exception.FrameworkException;
import com.sun.enterprise.tools.guiframework.view.descriptors.ViewDescriptor;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.URL;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletContext;

import org.xml.sax.EntityResolver;

/**
 *  For now we're limiting this class to 1 instance per JVM.  The
 *  ViewDescriptorURL and the cache are stored staticly.
 */
public class ViewDescriptorManager implements ViewDescriptorManagerInterface {

    /**
     *
     */
    private ViewDescriptorManager() {
    }


    /**
     *
     */
    public static ViewDescriptorManager getInstance() {
	return _instance;
    }


    /**
     *	<P>This sets the base URL that relative DTD documents can be resolved
     *	against (namely the view.dtd).</P>
     *
     *	<P>An example might be: "file://something/something/blah/blah"</P>
     */
    public void setDTDURLBase(String base) {
	_dtdBase = base;
    }


    /**
     *	This returns the base URL that relative DTD documents can be resolved
     *	against (namely the view.dtd).
     */
    public String getDTDURLBase() {
    	// Provide a best guess...
	if (_dtdBase == null) {
	    ServletContext servletContext =
		RequestManager.getRequestContext().getServletContext();
	    String path = "file:///"+servletContext.getRealPath("/")+"xml/";
	    setDTDURLBase(path);
	}
	return _dtdBase;
    }


    /**
     *
     */
    public void setViewDescriptorURL(String url) {
	try {
	    setViewDescriptorURL(new URL(url));
	} catch (MalformedURLException ex) {
	    throw new FrameworkException(ex);
	}
    }


    /**
     *
     */
    public void setViewDescriptorURL(URL url) {
	_descURL = url;
    }


    /**
     *
     */
    public URL getViewDescriptorURL() {
	return _descURL;
    }


    public void setViewXMLEntityResolver(EntityResolver entityResolver) {
        _viewXMLEntityResolver = entityResolver;
    }
    
    public EntityResolver getViewXMLEntityResolver() {
        return _viewXMLEntityResolver;
    }
    
    /**
     *	This method sets a flag to indicate that the cache should be dumped and
     *	the XML file should be re-read.
     */
    public void clearCache() {
	_clearCache = true;
    }


    public ViewDescriptor getViewDescriptor(String name) {
	ViewDescriptor viewDesc = null;
	if (_clearCache) {
	    // This enable re-reading after flushing
	    synchronized (this) {
		if (_clearCache) {
		    _descriptors = new HashMap();
		    _clearCache = false;
                    _processAllDescriptors = true;
		}
	    }
	} else {
	    // Try getting from the ViewDescriptor cache
	    viewDesc = (ViewDescriptor) _descriptors.get(name);
	    if (viewDesc != null) {
		return viewDesc;
	    }
	}

	// We have not yet found the ViewDescriptor, look in the XML file
        try {
                        
	    // Get the view xml url
	    URL url = getViewDescriptorURL();
	    if (url == null) {
		throw new FrameworkException(
		    "View Descriptor XML file not specified!!!");
	    }

	    // Get a ViewXMLReader
	    ViewXMLReader reader = null;
	    try {
                //System.out.println("reading: "+url.toString()+
                //    "\n   base: "+getDTDURLBase());
		reader = new ViewXMLReader(
		    url.openStream(), getDTDURLBase(), getJSPRoot(), 
                    getViewXMLEntityResolver());
	    } catch (IOException ex) {
		throw new FrameworkException("Unable to open URL: '"+
		    url+"'.", ex);
	    } catch (Exception ex) {
		throw new FrameworkException(ex);
	    }

            if (_processAllDescriptors == true) {
                synchronized(this) {
                    if (_descriptors.size() == 0) {
                        _descriptors = reader.getAllViewDescriptors();
                    }
                    _processAllDescriptors = false;
                }
                viewDesc = (ViewDescriptor)_descriptors.get(name);
            }
            
            if (viewDesc == null) {
                // Read the ViewDescriptor
                viewDesc = reader.getViewDescriptor(name);
                // Save the ViewDescriptor for later
                synchronized (this) {
                    _descriptors.put(name, viewDesc);
                }
            }

	    // Return the ViewDescriptor
	    return viewDesc;
        } catch (Exception ex) {
	    throw new FrameworkException("Unable to locate ViewDescriptor '"+
	    	name+"'.", ex);
        }
    }

    /**
     *
     */
    public void deserialize(ObjectInputStream stream) throws IOException, ClassNotFoundException {
	_descriptors = (Map) stream.readObject();
    }

    /**
     *
     */
    public void serialize(ObjectOutputStream stream) throws IOException {
	stream.writeObject(_descriptors);
    }


    /**
     *	This method is not part of the Interface, consider removing.
     */
    public void setJSPRoot(String root) {
	_jspRoot = root;
    }


    /**
     *	This method is not part of the Interface, consider removing.
     */
    public String getJSPRoot() {
	return _jspRoot;
    }


    /**
     *	The 1 shared instance of ViewDescriptorManager
     */
    private static ViewDescriptorManager _instance =
	new ViewDescriptorManager();


    /**
     *
     */
    protected String _jspRoot = "";


    /**
     *	Cache of ViewDescriptors
     */
    protected boolean _clearCache = false;

    /**
     *	Cache of ViewDescriptors
     */
    protected Map _descriptors = new HashMap();


    /**
     *	Location of the View Descriptor
     */
    protected URL _descURL = null;


    /**
     *	Base URL used to resolve relative paths to DTD's
     */
    protected String _dtdBase = null;
    
    protected EntityResolver _viewXMLEntityResolver = null;
    
    /**
     * whether all descriptors should be processed together
     **/
    protected boolean _processAllDescriptors = true;
    
}
