package org.apache.maven.plugin;

/*
 * ====================================================================
 * Copyright 2001-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.
 * ====================================================================
 */

import org.apache.commons.lang.StringUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.xpath.XPath;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class PluginToTags
{
    /** plugin script */
    private String pluginScript;

    /** output file */
    private String xdoc;

    /**
     * @return Returns the outputFile.
     */
    public String getXdoc()
    {
        return xdoc;
    }

    /**
     * @param outputFile
     *            The outputFile to set.
     */
    public void setXdoc(String outputFile)
    {
        this.xdoc = outputFile;
    }

    /**
     * @return Returns the pluginScript.
     */
    public String getPluginScript()
    {
        return pluginScript;
    }

    /**
     * @param pluginScript
     *            The plugin script to generate the docs from.
     */
    public void setPluginScript(String pluginScript)
    {
        this.pluginScript = pluginScript;
    }

    /**
     * Transform the plugin script to the output file. The output file will be
     * in xdoc format.
     * 
     * @throws IOException reading files
     * @throws JDOMException on xml
     */
    public void transform() throws JDOMException, IOException
    {
        File output = new File(getXdoc());
        BufferedWriter bw = new BufferedWriter(new FileWriter((output)));
        bw.write("<document>\n");
        bw.write("  <properties>\n");
        bw.write("    <title>Plugin tags</title>\n");
        bw.write("  </properties>\n");
        bw.write("  <body>\n");
        List taglibs = getTaglibs();
        writeOverview(bw, taglibs);
        writeTaglibs(bw, taglibs);
        bw.write("  </body>\n");
        bw.write("</document>\n");
        bw.close();
    }
    
    /**
     * Write xdoc sections to the given writer for each taglib
     * @param bw the writer
     * @param taglibs a list of taglibs to output
     * @throws IOException when there are errors writing
     */
    private void writeTaglibs(BufferedWriter bw, List taglibs) throws IOException
    {
        for (Iterator taglibIter = taglibs.iterator(); taglibIter.hasNext();)
        {
            Map taglib = (Map) taglibIter.next();
            bw.write("    <section name='" + taglib.get("uri") + " Tag Library'>\n");
            List tagNames = (List)taglib.get("tagNames");
            // write out subsection with name, description, attr, desc etc....
            for (Iterator tagIter = tagNames.iterator(); tagIter.hasNext();)
            {
                String name = (String) tagIter.next();
                bw.write("      <subsection name='" + name + " Tag'>\n");
                bw.write("        <p>No description</p>\n");
                bw.write("        <table>\n");
                bw.write("          <tr><th>Attribute</th><th>Optional?</th><th>Description</th></tr>\n");
                bw.write("        </table>\n");
                bw.write("      </subsection>\n");
            }
            bw.write("    </section>\n");
        }
    }

    /**
     * Write an xdoc overview section for all taglibs
     * @param bw the writer for output
     * @param taglibs the taglibs to output
     * @throws IOException when writing fails
     */
    private void writeOverview(BufferedWriter bw, List taglibs) throws IOException
    {
        bw.write("    <section name='Overview'>\n");
        bw.write("      <p>The following tag libraries and tags are provided by this plugin.</p>\n");
        bw.write("      <ol>\n");
        for (Iterator taglibIter = taglibs.iterator(); taglibIter.hasNext();)
        {
            Map taglib = (Map) taglibIter.next();
            String title = taglib.get("uri") + " Tag Library";
            String linkStart = "<a href='#" + StringUtils.replace(title, " ", "_")
            	+ "'>";
            bw.write("        <li>" + linkStart + taglib.get("uri") + "</a>\n");
            bw.write("          <ol>\n");
            List tagNames = (List)taglib.get("tagNames");
            for (Iterator tagIter = tagNames.iterator(); tagIter.hasNext();)
            {
                String name = (String) tagIter.next();
                bw.write("            <li><a href='#" + name + "_Tag'>" + name + "</a></li>\n");
            }
            bw.write("          </ol>\n");
            bw.write("        </li>\n");
        }    
        bw.write("      </ol>\n");
        bw.write("    </section>\n");
    }

    /**
     * @return a list of tag libraries. Each element in the list 
     * is a {@link Map}. Each map contains an entry for "uri" (as a String)
     * and one for tagNames (as a List).
     * 
     * @throws IOException reading files
     * @throws JDOMException on xml
     */
    public List getTaglibs() throws JDOMException, IOException
    {
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(new File(getPluginScript()));
        XPath xpath = XPath.newInstance("/project/define:taglib");
        List taglibElements = xpath.selectNodes(doc);
        List taglibs = new LinkedList();
        for (Iterator iter = taglibElements.iterator(); iter.hasNext();)
        {
            Element element = (Element) iter.next();
            Map taglib = new HashMap();
            taglib.put("uri", element.getAttributeValue("uri"));
            taglib.put("tagNames", new LinkedList());
            XPath tagsXp = XPath.newInstance("define:tag|define:jellybean");
            List tagsElements = tagsXp.selectNodes(element);
            for (Iterator tagsIter = tagsElements.iterator(); tagsIter.hasNext();)
            {
                Element tagsElement = (Element) tagsIter.next();
                ((List) taglib.get("tagNames")).add(tagsElement.getAttributeValue("name"));
            }
            taglibs.add(taglib);
        }
        return taglibs;
    }

}