/*
 * Copyright 2000-2004 The Apache Software Foundation.
 *
 * 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
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jp.sf.pal.myfaces.portlet.headerresource.jetspeed;

import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;

import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import jp.sf.pal.myfaces.portlet.headerresource.AbstractHeaderResource;
import jp.sf.pal.myfaces.portlet.headerresource.HeaderResource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jetspeed.CommonPortletServices;
import org.apache.jetspeed.headerresource.HeaderResourceFactory;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 * HeaderResource implementation for Jetspeed2.
 * 
 * @author <a href="mailto:shinsuke@yahoo.co.jp">Shinsuke Sugaya</a>
 */
public class HeaderResourceImpl extends AbstractHeaderResource implements HeaderResource
{
    private static final Log log = LogFactory.getLog(HeaderResourceImpl.class);

    private HeaderResourceFactory headerResourceFactory;

    public HeaderResourceImpl()
    {
    }

    public void init()
    {
        headerResourceFactory = (HeaderResourceFactory) getPortletContext().getAttribute(
                CommonPortletServices.CPS_HEADER_RESOURCE_FACTORY);
        if (headerResourceFactory == null)
        {
            log.error("cannot create headerResourceFactory for Jetspeed.");
        }
    }

    public void addHeaderResources(PortletRequest request, PortletResponse response, String elements)
    {
        if (log.isDebugEnabled())
        {
            log.debug("addHeaderResources(PortletRequest, PortletResponse, String) -  : elements=" + elements);
        }

        if (elements == null || elements.equals(""))
        {
            return;
        }

        org.apache.jetspeed.headerresource.HeaderResource headerResource = headerResourceFactory
                .getHeaderResouce(request);

        DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
        try
        {
            DocumentBuilder builder = dbfactory.newDocumentBuilder();
            Document doc = builder.parse(new InputSource(new StringReader(elements)));

            // root node is head
            Element root = doc.getDocumentElement();

            NodeList list = root.getChildNodes();
            for (int i = 0; i < list.getLength(); i++)
            {
                if (list.item(i).getNodeType() == Node.ELEMENT_NODE)
                {
                    Element element = (Element) list.item(i);

                    HashMap map = new HashMap();
                    NamedNodeMap nnMap = element.getAttributes();
                    for (int j = 0; j < nnMap.getLength(); j++)
                    {
                        Node attr = nnMap.item(j);
                        map.put(attr.getNodeName(), attr.getNodeValue());
                    }

                    String tagName = element.getTagName();
                    NodeList children = element.getChildNodes();
                    StringBuffer text = null;
                    for (int j = 0; j < children.getLength(); j++)
                    {
                        if (text == null)
                        {
                            text = new StringBuffer();
                        }
                        text.append(parseChildNode(children.item(j)));
                    }
                    if (log.isDebugEnabled())
                    {
                        log.debug("addHeaderResources(PortletRequest, PortletResponse, String) -  :" + " tagName="
                                + tagName);
                        log.debug("addHeaderResources(PortletRequest, PortletResponse, String) -  :" + " text=" + text);
                    }

                    // script tag needs </script> element
                    if (tagName.equalsIgnoreCase("script") && text == null)
                    {
                        text = new StringBuffer("");
                    }

                    headerResource.addHeaderInfo(tagName, map, text != null ? text.toString() : null);
                }
            }
        }
        catch (DOMException e)
        {
            log.error("cannot add header resources.", e);
        }
        catch (ParserConfigurationException e)
        {
            log.error("cannot add header resources.", e);
        }
        catch (SAXException e)
        {
            log.error("cannot add header resources.", e);
        }
        catch (IOException e)
        {
            log.error("cannot add header resources.", e);
        }

    }

    private String parseChildNode(Node e)
    {
        StringBuffer buf = new StringBuffer();
        if (e.getNodeType() == Node.ELEMENT_NODE)
        {
            String tagName = ((Element) e).getTagName();
            buf.append("<");
            buf.append(tagName);
            buf.append(" ");
            if (e.hasAttributes())
            {
                NamedNodeMap nnMap = e.getAttributes();
                for (int i = 0; i < nnMap.getLength(); i++)
                {
                    Node attr = nnMap.item(i);
                    buf.append(attr.getNodeName());
                    buf.append("=\"");
                    buf.append(attr.getNodeValue());
                    buf.append("\" ");
                }
            }
            if (e.hasChildNodes())
            {
                NodeList list = e.getChildNodes();
                buf.append(">");
                for (int i = 0; i < list.getLength(); i++)
                {
                    Node child = list.item(i);
                    buf.append(parseChildNode(child));
                }
                buf.append("</");
                buf.append(tagName);
                buf.append(">");
            }
            else
            {
                buf.append("/>");
            }
        }
        else if (e.getNodeType() == Node.TEXT_NODE)
        {
            buf.append(e.getNodeValue());
        }
        else if (e.getNodeType() == Node.COMMENT_NODE)
        {
            buf.append("<!--");
            buf.append(e.getNodeValue());
            buf.append("-->");
        }
        return buf.toString();
    }
}
