/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/util/org/apache/slide/util/jinx/lib/Codeguide.java,v 1.1 2004/03/25 16:18:11 juergen Exp $
 * $Revision: 1.1 $
 * $Date: 2004/03/25 16:18:11 $
 *
 * ====================================================================
 *
 * Copyright 1999-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 org.apache.slide.util.jinx.lib;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.slide.util.Files;
import org.apache.slide.util.JDom;
import org.apache.slide.util.XAssertionFailed;
import org.apache.slide.util.XException;
import org.apache.slide.util.cli.Abort;
import org.apache.slide.util.nodeset.NodeSet;
import org.apache.slide.util.os.Catalina;
import org.apache.slide.util.os.Platform;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.xpath.XPath;

public class Codeguide {
    public static void removeUnless(Object ssx, List lst, File dir, String relative) throws IOException {
        File file;
        
        if (ssx == null) {
            file = new File(dir, relative.replace('/', File.separatorChar));
            if (!lst.remove(file)) {
                throw new IOException("file not in list: " + file);
            }
        }
    }
    
    public static List pathCreate() {
        return new ArrayList();
    }

    public static void pathAdd(List lst, File file) {
        lst.add(file);
    }

    public static void pathAdd2(List lst, File file, String relative) {
        lst.add(new File(file, relative.replace('/', File.separatorChar)));
    }
    
    public static void pathAddGlob(List result, File base, String c) throws IOException, Abort {
        NodeSet set;
        int initial;
        
        initial = result.size();
        set = new NodeSet();
        set.include(c);
        set.exclude("**/CVS");
        set.list(base, result);
        if (result.size() == initial) {
            throw new Abort("constraint didn't yield any files: " + base + ": " + c);
        }
    }

    public static void remove(List cp, File file) throws IOException {
        if (!cp.remove(file)) {
            throw new IOException("not in classpath: " + file);
        }
    }
    
    public static String pathToString(List lst) {
        StringBuffer buffer;
        Iterator iter;

        buffer = new StringBuffer();
        iter = lst.iterator();
        while (iter.hasNext()) {
            buffer.append("         <Directory absolutePath=\"");
            buffer.append(((File) iter.next()).getAbsolutePath());
            buffer.append("\"/>\n");
        }
        return buffer.toString();
        
    }
        
    //--

    public static Codeguide create(File tws, File catalina, String catalinaOpts, String webappContext)
        throws IOException, XException, Abort
    {
        String dirName;
        File file;
        
        dirName = "codeguide-6.0";
        if (!Platform.isWindows()) {
            dirName = "." + dirName;
        }
        file = Files.join(Platform.USER_HOME, dirName, "configuration.xml");
        Files.checkFile(file);
        return new Codeguide(file, JDom.forFile(file), tws, catalina, catalinaOpts, webappContext);
    }

    private final File file;
    private final Document doc;
    private final Element tools;
    private final File tws;
    private final Catalina catalina;
    
    public Codeguide(File file, Document doc, File tws, File catalinaHome, String catalinaOpts, String webappContext)
        throws Abort
    {
        this.file = file;
        this.doc = doc;
        this.tools = element(doc, xpath("/cg:Configuration/cg:Tools"));
        this.tws = tws;
        this.catalina = Catalina.create(catalinaHome.getPath(), catalinaOpts, webappContext);
    }
    
    public void configure() throws IOException, XException {
        checkSettings();
        twsMenu();
        write();
    }

    private void write() throws IOException, XException {
        File bak;
        Writer writer;
        
        bak = new File(file.getPath() + ".bak");
        if (bak.exists()) {
            Files.delete(bak);
        }
        if (!file.renameTo(bak)) {
            throw new IOException("rename failed");
        }
        writer = new FileWriter(file);
        JDom.outputter().output(doc, writer);
        writer.close();
    }

    private void checkSettings() throws XException {
        property("CONVERT_TABS_TO_SPACES_ON_SAVE", "TRUE");
        property("EDITOR_TAB_SIZE", "4");
    }
    
    private void property(String name, String expected) throws XException {
        XPath path;
        Element prop;
        String found;
        
        path = xpath("/cg:Configuration/cg:Properties/cg:Property[@name=\"" + name +"\"]");
        prop = element(doc, path);
        found = prop.getAttributeValue("value");
        if (!expected.equals(found)) {
            throw new XException("invalid value for propertry '" + name + "': expected " + expected + ", found: " + found);
        } else {
            System.out.println("ok: " + name + "=" + found);
        }
    }
    
    private void twsMenu() {
        platformItem("console", null, null, true,
                     "cmd.exe", "/c start \"Tamino WebDAVServer\" /D" + tws + "\\build\\tree\\bin set JAVA_HOME=$JDK_HOME_DIRECTORY_PATH$&& set ANT_HOME=r:\\XToolsBuild\\XToolsBuild_2_0_1_0",
                     "gnome-terminal", "--working-directory=" + tws + "/build/tree/bin");
        platformItem("run ...", null, new File(tws, "bin"), false,
                     "cmd.exe", "/k echo TODO",
                     "/bin/sh", " ./inodav.sh $USER_ARGUMENTS$");
        junitItem("SwingRunner", "junit.swingui.TestRunner", "");
        junitItem("TextRunner", "junit.textui.TestRunner", "");
        junitItem("Debug", "junit.textui.TestRunner",
                  "-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,address=20500,server=y,suspend=y -Djava.compiler=NONE");
    }
    
    private static final String CATEGORY = "tws";

    private void platformItem(String name, String filePattern, File workingdir, boolean detach,
                              String execWin, String parmsWin,
                              String execUnix, String parmsUnix) {
        if (Platform.isWindows()) {
            item(name, filePattern, workingdir, detach, execWin, parmsWin);
        } else {
            item(name, filePattern, workingdir, detach, execUnix, parmsUnix);
        }
    }
    private void junitItem(String name, String runner, String jvmOpts) {
        item(name, "*.java", tws, false, Files.join("$JDK_HOME_DIRECTORY_PATH$", "bin", "java"), jvmOpts
                 + " -Dtest.dir=" + new File(tws, "testsuite").getPath()
                 + " -Dcatalina.home=" + catalina.home
                 + " -Dwebapp.context=" + catalina.getContext()
                 + " -classpath \"$CLASSPATH$\" " + runner +" $FILE_CLASSNAME$");
    }
    private void item(String name, String filePattern, File workingdir, boolean detach, String exec, String parms) {
        Element tool;
        String txt;
        Element pattern;
        
        tool = elementOpt(tools, xpath("cg:Tool[@category=\"" + CATEGORY + "\"][@name=\"" + name + "\"]"));
        if (tool == null) {
            txt = "adding";
        } else {
            txt = "updating";
            tool.detach();
        }
        System.out.println(txt + " tws tool: " + name);
        tool = new Element("Tool", tools.getNamespace());
        tool.setAttribute("name", name);
        tool.setAttribute("executable", exec);
        tool.setAttribute("parameters", parms);
        tool.setAttribute("workingdir", (workingdir == null)? "" : workingdir.getAbsolutePath());
        tool.setAttribute("kind", (filePattern == null)? "Menu" : "File");
        tool.setAttribute("behavior", detach? "detach" : "default");
        tool.setAttribute("console", "tws");
        tool.setAttribute("category", CATEGORY);
        if (filePattern != null) {
            pattern = new Element("FilePattern");
            pattern.addContent(filePattern);
            tool.addContent(pattern);
        }
        tools.addContent(tool);
    }
    
    //-- xpath primitives
    
    private static final Namespace NS = Namespace.getNamespace("cg", "http://www.omnicore.com/namespaces/codeguide/6.0/configuration");

    private static Element element(Object obj, XPath xpath) {
        Element result;
        
        result = elementOpt(obj, xpath);
        if (result == null) {
            throw new XAssertionFailed("not found: " + xpath);
        }
        return result;
    }

    private static Element elementOpt(Object root, XPath xpath) {
        try  {
            return (Element) xpath.selectSingleNode(root);
        } catch (JDOMException e) {
            throw new XAssertionFailed(xpath.toString(), e);
        }
    }
    
    private static XPath xpath(String select) {
        XPath path;
        
        try {
            path = XPath.newInstance(select);
        } catch (JDOMException e) {
            throw new XAssertionFailed(select, e);
        }
        path.addNamespace(NS);
        return path;
    }
}
