/*
 * Copyright 2015 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 *      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.
*/

/*******************************************************************************

 * Copyright (c) 2010 Red Hat, Inc.
 * Distributed under license by Red Hat, Inc. All rights reserved.
 * This program is made available under the terms of the
 * Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Red Hat, Inc. - initial API and implementation
 ******************************************************************************/

package org.jboss.tools.runtime.handlers;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.Attributes;
import java.util.jar.JarFile;

import org.drools.eclipse.util.DroolsRuntime;
import org.drools.eclipse.util.DroolsRuntimeManager;
import org.eclipse.core.runtime.IProgressMonitor;
import org.jboss.tools.runtime.core.model.AbstractRuntimeDetectorDelegate;
import org.jboss.tools.runtime.core.model.RuntimeDefinition;
import org.kie.eclipse.runtime.IRuntime;

public class DroolsHandler extends AbstractRuntimeDetectorDelegate {

	private static final String DROOLS_PREFIX = "Drools "; // NON-NLS-1$
	private static final String DROOLS_PREFIX_HYPHEN = DROOLS_PREFIX + " - "; // NON-NLS-1$

    private static final String DROOLS = "DROOLS"; // NON-NLS-1$
    private static final String SOA_P = "SOA-P"; //$NON-NLS-1$

    @Override
    public void initializeRuntimes(List<RuntimeDefinition> serverDefinitions) {
        IRuntime[] existingRuntimes = DroolsRuntimeManager.getDefault().getConfiguredRuntimes();
        List<DroolsRuntime> droolsRuntimes = new ArrayList<DroolsRuntime>();
        if (existingRuntimes != null) {
            for (IRuntime runtime : existingRuntimes) {
            	if (runtime instanceof DroolsRuntime)
            		droolsRuntimes.add((DroolsRuntime) runtime);
            }
        }
        initializeInternal(serverDefinitions, droolsRuntimes);
        if (droolsRuntimes.size() > 0) {
            DroolsRuntime[] dra = droolsRuntimes.toArray(new DroolsRuntime[0]);
            DroolsRuntimeManager.getDefault().setRuntimes(dra);
        }

    }

    private void initializeInternal(List<RuntimeDefinition> serverDefinitions,
            List<DroolsRuntime> droolsRuntimes) {
        for (RuntimeDefinition serverDefinition : serverDefinitions) {
            String type = serverDefinition.getType();
            if (serverDefinition.isEnabled() && !droolsExists(serverDefinition)) {
                if (DROOLS.equals(type)) {
                    File droolsRoot = serverDefinition.getLocation();
                    if (droolsRoot.isDirectory()) {
                        DroolsRuntime runtime = new DroolsRuntime();
                        boolean startsWithDrools = serverDefinition.getName().startsWith(DROOLS_PREFIX);
                        String newName =   startsWithDrools ?  serverDefinition.getName() :
                        	DROOLS_PREFIX + serverDefinition.getName();
                        runtime.setName(newName);

                        runtime.setPath(droolsRoot.getAbsolutePath());
                        DroolsRuntimeManager.getDefault().recognizeJars(runtime);
                        runtime.setDefault(true);
                        droolsRuntimes.add(runtime);
                    }
                }
            }
            initializeInternal(serverDefinition.getIncludedRuntimeDefinitions(),
                    droolsRuntimes);
        }
    }

    /**
     * @param serverDefinition
     * @return
     */
    private static boolean droolsExists(RuntimeDefinition serverDefinition) {
    	return getRuntimeForLocation(serverDefinition.getLocation().getAbsolutePath()) != null;
    }

    private static DroolsRuntime getRuntimeForLocation(String loc) {
        IRuntime[] droolsRuntimes = DroolsRuntimeManager.getDefault().getConfiguredRuntimes();
        for (IRuntime dr : droolsRuntimes) {
            String location = dr.getPath();
            if (location != null && location.equals(loc) && dr instanceof DroolsRuntime) {
                return (DroolsRuntime) dr;
            }
        }
        return null;
    }

    private boolean droolsRuntimeNameExists(String name) {
        IRuntime[] droolsRuntimes = DroolsRuntimeManager.getDefault().getConfiguredRuntimes();
        for (IRuntime dr : droolsRuntimes) {
    		if( dr.getName().equals(name))
    			return true;
    	}
    	return false;
    }

    private String getDroolsRuntimeName(String prefix) {
    	if( !droolsRuntimeNameExists(prefix))
    		return prefix;
    	int count = 1;
    	while(droolsRuntimeNameExists(prefix + " (" + count + ")"))
    		count++;
    	return prefix + " (" + count + ")";
    }

    @Override
    public RuntimeDefinition getRuntimeDefinition(File root,
            IProgressMonitor monitor) {
        if (monitor.isCanceled() || root == null) {
            return null;
        }
        String[] files = root.list(new FilenameFilter() {

            public boolean accept(File dir, String name) {
                if (name.startsWith("drools-api") && name.endsWith(".jar")) {
                    return true;
                }
                return false;
            }
        });
        if (files != null && files.length > 0) {
            String version = getImplementationVersion(root, files[0]);
            if (version != null) {
                version = version.substring(0, 3);
                String name = getDroolsRuntimeName(DROOLS_PREFIX + version);
                DroolsRuntime found = getRuntimeForLocation(root.getAbsolutePath());
                if( found != null) {
                	name = found.getName();
                }
                return new RuntimeDefinition(name, version, DROOLS,
                        root.getAbsoluteFile());
            }
        }
        return null;
    }

    public String getImplementationVersion(File dir, String file) {
        File jarFile = new File(dir, file);
        if(!jarFile.isFile()) {
            return null;
        }
        try {
            JarFile jar = new JarFile(jarFile);
            Attributes attributes = jar.getManifest().getMainAttributes();
            String version = attributes.getValue("Implementation-Version");
            return version;
        } catch (IOException e) {
            return null;
        }
    }

    @Override
    public boolean exists(RuntimeDefinition serverDefinition) {
        if (serverDefinition == null || serverDefinition.getLocation() == null) {
            return false;
        }
        return droolsExists(serverDefinition);
    }

    public void computeIncludedRuntimeDefinition(
            RuntimeDefinition serverDefinition) {
        if (serverDefinition == null
                || !SOA_P.equals(serverDefinition.getType())) {
            return;
        }
        File droolsRoot = serverDefinition.getLocation(); //$NON-NLS-1$
        if (droolsRoot.isDirectory()) {
            String name = DROOLS_PREFIX_HYPHEN + serverDefinition.getName(); //$NON-NLS-1$
            RuntimeDefinition sd = new RuntimeDefinition(name,
                    serverDefinition.getVersion(), DROOLS, droolsRoot);
            sd.setParent(serverDefinition);
            serverDefinition.getIncludedRuntimeDefinitions().add(sd);
        }
    }

    public String getVersion(RuntimeDefinition runtimeDefinition) {
        return runtimeDefinition.getVersion();
    }

}


/*
 * Copyright 2010 Red Hat, Inc. and/or its affiliates.
 *
 * 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.drools.eclipse.editors.completion;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.drools.compiler.lang.descr.GlobalDescr;
import org.drools.compiler.rule.builder.dialect.java.KnowledgeHelperFixer;
import org.drools.core.util.StringUtils;
import org.drools.eclipse.DroolsEclipsePlugin;
import org.drools.eclipse.DroolsPluginImages;
import org.drools.eclipse.editors.AbstractRuleEditor;
import org.drools.eclipse.editors.DRLRuleEditor;
import org.eclipse.core.resources.IProject;
import org.eclipse.jdt.core.CompletionContext;
import org.eclipse.jdt.core.CompletionProposal;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.ILocalVariable;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.eval.IEvaluationContext;
import org.eclipse.jdt.internal.ui.text.java.AbstractJavaCompletionProposal;
import org.eclipse.jdt.internal.ui.text.java.JavaMethodCompletionProposal;
import org.eclipse.jdt.internal.ui.text.java.LazyJavaTypeCompletionProposal;
import org.eclipse.jdt.ui.text.java.CompletionProposalCollector;
import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IFileEditorInput;

/**
 * This is the basic completion processor that is used when the editor is outside of a rule block
 * partition.
 * The provides the content assistance for basic rule assembly stuff.
 *
 * This processor will also read behind the current editing position, to provide some context to
 * help provide the pop up list.
 */
public class DefaultCompletionProcessor extends AbstractCompletionProcessor {

    private static final String    NEW_RULE_TEMPLATE           = "rule \"new rule\"" + System.getProperty( "line.separator" ) + "\twhen" + System.getProperty( "line.separator" ) + "\t\t" + System.getProperty( "line.separator" ) + "\tthen"
                                                                 + System.getProperty( "line.separator" ) + "\t\t" + System.getProperty( "line.separator" ) + "end";
    private static final String    NEW_QUERY_TEMPLATE          = "query \"query name\"" + System.getProperty( "line.separator" ) + "\t#conditions" + System.getProperty( "line.separator" ) + "end";
    private static final String    NEW_FUNCTION_TEMPLATE       = "function void yourFunction(Type arg) {" + System.getProperty( "line.separator" ) + "\t/* code goes here*/" + System.getProperty( "line.separator" ) + "}";
    private static final String    NEW_TEMPLATE_TEMPLATE       = "template Name" + System.getProperty( "line.separator" ) + "\t" + System.getProperty( "line.separator" ) + "end";
    protected static final Pattern IMPORT_PATTERN              = Pattern.compile( ".*\n\\W*import\\W[^;\\s]*",
                                                                                Pattern.DOTALL );
    // TODO: doesn't work for { inside functions
    private static final Pattern   FUNCTION_PATTERN            = Pattern.compile( ".*\n\\W*function\\s+(\\S+)\\s+(\\S+)\\s*\\(([^\\)]*)\\)\\s*\\{([^\\}]*)",
                                                                                Pattern.DOTALL );
    protected static final Image   VARIABLE_ICON               = DroolsPluginImages.getImage( DroolsPluginImages.VARIABLE );
    protected static final Image   METHOD_ICON                 = DroolsPluginImages.getImage( DroolsPluginImages.METHOD );
    protected static final Image   CLASS_ICON                  = DroolsPluginImages.getImage( DroolsPluginImages.CLASS );

    public DefaultCompletionProcessor(AbstractRuleEditor editor) {
        super( editor );
    }

    protected List<ICompletionProposal> getCompletionProposals(ITextViewer viewer,
                                          int documentOffset) {
        try {
            IDocument doc = viewer.getDocument();
            String backText = readBackwards( documentOffset,
                                             doc );

            String prefix = CompletionUtil.stripLastWord( backText );

            List<ICompletionProposal> props = null;
            Matcher matcher = IMPORT_PATTERN.matcher( backText );
            if ( matcher.matches() ) {
                String classNameStart = backText.substring( backText.lastIndexOf( "import" ) + 7 );
                props = getAllClassProposals( classNameStart,
                                              documentOffset,
                                              prefix );
            } else {
                matcher = FUNCTION_PATTERN.matcher( backText );
                if ( matcher.matches() ) {
                    // extract function parameters
                    Map<String, String> params = extractParams( matcher.group( 3 ) );
                    // add global parameters
//                    List globals = getGlobals();
//                    if ( globals != null ) {
//                        for ( Iterator iterator = globals.iterator(); iterator.hasNext(); ) {
//                            GlobalDescr global = (GlobalDescr) iterator.next();
//                            params.put( global.getIdentifier(),
//                                        global.getType() );
//                        }
//                    }
                    String functionText = matcher.group( 4 );
                    props = getJavaCompletionProposals( documentOffset,
                                                        functionText,
                                                        prefix,
                                                        params,
                                                        false,
                                                        false);
                    filterProposalsOnPrefix( prefix,
                                             props );
                } else {
                    props = getPossibleProposals( viewer,
                                                  documentOffset,
                                                  backText,
                                                  prefix );
                }
            }
            return props;
        } catch ( Throwable t ) {
            DroolsEclipsePlugin.log( t );
        }
        return null;
    }

    private Map<String, String> extractParams(String params) {
        Map<String, String> result = new HashMap<String, String>();
        String[] parameters = params.split( "," );
        for ( int i = 0; i < parameters.length; i++ ) {
            String[] typeAndName = parameters[i].split( " " );
            if ( typeAndName.length == 2 ) {
                result.put( typeAndName[1],
                            typeAndName[0] );
            }
        }
        return result;
    }

    /*
     * create and returns a java project based on the current editor input or returns null
     */
    private IJavaProject getCurrentJavaProject() {
        IEditorInput input = getEditor().getEditorInput();
        if ( !(input instanceof IFileEditorInput) ) {
            return null;
        }
        IProject project = ((IFileEditorInput) input).getFile().getProject();
        IJavaProject javaProject = JavaCore.create( project );
        return javaProject;
    }

    protected List<ICompletionProposal> getAllClassProposals(final String classNameStart,
                                        final int documentOffset,
                                        final String prefix) {
        List<ICompletionProposal> result = new ArrayList<ICompletionProposal>();
        IJavaProject javaProject = getCurrentJavaProject();
        if ( javaProject == null ) {
            return result;
        }
        CompletionProposalCollector collector = new CompletionProposalCollector( javaProject ) {
            public void accept(CompletionProposal proposal) {
                if ( proposal.getKind() == org.eclipse.jdt.core.CompletionProposal.PACKAGE_REF || proposal.getKind() == org.eclipse.jdt.core.CompletionProposal.TYPE_REF ) {
                    super.accept( proposal );
                }
            }
        };
        collector.acceptContext( new CompletionContext() );
        try {
            IEvaluationContext evalContext = javaProject.newEvaluationContext();
            evalContext.codeComplete( classNameStart,
                                      classNameStart.length(),
                                      collector );
            IJavaCompletionProposal[] proposals = collector.getJavaCompletionProposals();
            for ( int i = 0; i < proposals.length; i++ ) {
                if ( proposals[i] instanceof AbstractJavaCompletionProposal ) {
                    AbstractJavaCompletionProposal javaProposal = (AbstractJavaCompletionProposal) proposals[i];
                    int replacementOffset = documentOffset - (classNameStart.length() - javaProposal.getReplacementOffset());
                    javaProposal.setReplacementOffset( replacementOffset );
                    if ( javaProposal instanceof LazyJavaTypeCompletionProposal ) {
                        String completionPrefix = classNameStart.substring( classNameStart.length() - javaProposal.getReplacementLength() );
                        int dotIndex = completionPrefix.lastIndexOf( '.' );
                        // match up to the last dot in order to make higher level matching still work (camel case...)
                        if ( dotIndex != -1 ) {
                            javaProposal.setReplacementString( ((LazyJavaTypeCompletionProposal) javaProposal).getQualifiedTypeName() );
                        }
                    }
                    result.add( proposals[i] );
                }
            }
        } catch ( Throwable t ) {
            DroolsEclipsePlugin.log( t );
        }
        return result;
    }

    protected List<ICompletionProposal> getPossibleProposals(ITextViewer viewer,
                                        int documentOffset,
                                        String backText,
                                        final String prefix) {
        List<ICompletionProposal> list = new ArrayList<ICompletionProposal>();
        list.add( new RuleCompletionProposal( documentOffset - prefix.length(),
                                              prefix.length(),
                                              "rule",
                                              NEW_RULE_TEMPLATE,
                                              6 ) );
        list.add( new RuleCompletionProposal( documentOffset - prefix.length(),
                                              prefix.length(),
                                              "import",
                                              "import " ) );
        list.add( new RuleCompletionProposal( documentOffset - prefix.length(),
                                              prefix.length(),
                                              "expander",
                                              "expander " ) );
        list.add( new RuleCompletionProposal( documentOffset - prefix.length(),
                                              prefix.length(),
                                              "global",
                                              "global " ) );
        list.add( new RuleCompletionProposal( documentOffset - prefix.length(),
                                              prefix.length(),
                                              "package",
                                              "package " ) );
        list.add( new RuleCompletionProposal( documentOffset - prefix.length(),
                                              prefix.length(),
                                              "query",
                                              NEW_QUERY_TEMPLATE ) );
        list.add( new RuleCompletionProposal( documentOffset - prefix.length(),
                                              prefix.length(),
                                              "function",
                                              NEW_FUNCTION_TEMPLATE,
                                              14 ) );
        list.add( new RuleCompletionProposal( documentOffset - prefix.length(),
                                              prefix.length(),
                                              "template",
                                              NEW_TEMPLATE_TEMPLATE,
                                              9 ) );
        list.add( new RuleCompletionProposal( documentOffset - prefix.length(),
                                              prefix.length(),
                                              "dialect \"java\"",
                                              "dialect \"java\" " ) );
        list.add( new RuleCompletionProposal( documentOffset - prefix.length(),
                                              prefix.length(),
                                              "dialect \"mvel\"",
                                              "dialect \"mvel\" " ) );
        filterProposalsOnPrefix( prefix,
                                 list );
        return list;
    }

    protected List<ICompletionProposal> getJavaCompletionProposals(final int documentOffset,
                                              final String javaText,
                                              final String prefix,
                                              Map<String, String> params) {
        return getJavaCompletionProposals(documentOffset, javaText, prefix, params, true, false);
    }

    protected List<ICompletionProposal> getJavaCompletionProposals(final int documentOffset,
                                              final String javaText,
                                              final String prefix,
                                              Map<String, String> params,
                                              boolean useDrools,
                                              boolean useContext) {
        final List<ICompletionProposal> list = new ArrayList<ICompletionProposal>();
        requestJavaCompletionProposals( javaText,
                                        prefix,
                                        documentOffset,
                                        params,
                                        list,
                                        useDrools,
                                        useContext);
        return list;
    }

    /*
     * do we already have a completion for that string that would be either a local variable or a field?
     */
    protected static boolean doesNotContainFieldCompletion(String completion, List<ICompletionProposal> completions) {
        if ( completion == null || completion.length() == 0 || completions == null ) {
            return false;
        }
        for ( Iterator<ICompletionProposal> iter = completions.iterator(); iter.hasNext(); ) {
            Object o = iter.next();
            if ( o instanceof AbstractJavaCompletionProposal ) {
                AbstractJavaCompletionProposal prop = (AbstractJavaCompletionProposal) o;
                String content = prop.getReplacementString();
                if ( completion.equals( content ) ) {
                    IJavaElement javaElement = prop.getJavaElement();
                    if ( javaElement instanceof ILocalVariable || javaElement instanceof IField ) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    protected void requestJavaCompletionProposals(final String javaText,
                                                  final String prefix,
                                                  final int documentOffset,
                                                  Map<String, String> params,
                                                  Collection<ICompletionProposal> results) {
        requestJavaCompletionProposals(javaText, prefix, documentOffset, params, results, true, false);
    }

    protected void requestJavaCompletionProposals(final String javaText,
                                                  final String prefix,
                                                  final int documentOffset,
                                                  Map<String, String> params,
                                                  Collection<ICompletionProposal> results,
                                                  boolean useDrools,
                                                  boolean useContext) {

        String javaTextWithoutPrefix = CompletionUtil.getTextWithoutPrefix( javaText,
                                                                            prefix );
        // boolean to filter default Object methods produced by code completion when in the beginning of a statement
        boolean filterObjectMethods = false;
        if ( "".equals( javaTextWithoutPrefix.trim() ) || CompletionUtil.START_OF_NEW_JAVA_STATEMENT.matcher( javaTextWithoutPrefix ).matches() ) {
            filterObjectMethods = true;
        }
        IJavaProject javaProject = getCurrentJavaProject();
        if ( javaProject == null ) {
            return;
        }

        CompletionProposalCollector collector = new CompletionProposalCollector( javaProject );
        collector.acceptContext( new CompletionContext() );

        try {
            IEvaluationContext evalContext = javaProject.newEvaluationContext();
            List<String> imports = getImports();
            if ( imports != null && imports.size() > 0 ) {
                evalContext.setImports(imports.toArray(new String[imports.size()]));
            }
            StringBuffer javaTextWithParams = new StringBuffer();
            for (Entry<String, String> entry : params.entrySet()) {
                // this does not seem to work, so adding variables manually
                // evalContext.newVariable((String) entry.getValue(), (String) entry.getKey(), null);
                javaTextWithParams.append( entry.getValue() + " " + entry.getKey() + ";\n" );
            }
            if (useDrools) {
                javaTextWithParams.append( "org.kie.api.runtime.rule.RuleContext kcontext;" );
            }
            if (useContext) {
                javaTextWithParams.append( "org.kie.api.runtime.process.ProcessContext kcontext;" );
            }
            javaTextWithParams.append( javaText );
            String jtext = javaTextWithParams.toString();
            String fixedText = KnowledgeHelperFixer.fix(jtext);

            evalContext.codeComplete( fixedText,
                                      fixedText.length(),
                                      collector );
            IJavaCompletionProposal[] proposals = collector.getJavaCompletionProposals();
            for ( int i = 0; i < proposals.length; i++ ) {
                if ( proposals[i] instanceof AbstractJavaCompletionProposal ) {
                    AbstractJavaCompletionProposal javaProposal = (AbstractJavaCompletionProposal) proposals[i];
                    int replacementOffset = documentOffset - (fixedText.length() - javaProposal.getReplacementOffset());
                    javaProposal.setReplacementOffset( replacementOffset );
                    if ( javaProposal instanceof LazyJavaTypeCompletionProposal ) {
                        String completionPrefix = javaText.substring( javaText.length() - javaProposal.getReplacementLength() );
                        int dotIndex = completionPrefix.lastIndexOf( '.' );
                        // match up to the last dot in order to make higher level matching still work (camel case...)
                        if ( dotIndex != -1 ) {
                            javaProposal.setReplacementString( ((LazyJavaTypeCompletionProposal) javaProposal).getQualifiedTypeName() );
                        }
                    }
                    if ( !filterObjectMethods || !(proposals[i] instanceof JavaMethodCompletionProposal) ) {
                        results.add( proposals[i] );
                    }
                }
            }
        } catch ( Throwable t ) {
            DroolsEclipsePlugin.log( t );
        }
    }

    protected String getPackage() {
        if ( getEditor() instanceof DRLRuleEditor ) {
            return ((DRLRuleEditor) getEditor()).getPackage();
        }
        return "";
    }

    protected List<String> getImports() {
        if ( getEditor() instanceof DRLRuleEditor ) {
            return ((DRLRuleEditor) getEditor()).getImports();
        }
        return Collections.emptyList();
    }

    protected Set<String> getUniqueImports() {
        HashSet<String> set = new HashSet<String>();
        set.addAll( getImports() );
        return set;
    }

    protected List<String> getFunctions() {
        if ( getEditor() instanceof DRLRuleEditor ) {
            return ((DRLRuleEditor) getEditor()).getFunctions();
        }
        return Collections.emptyList();
    }

    protected Map<String, String> getAttributes() {
        if ( getEditor() instanceof DRLRuleEditor ) {
            return ((DRLRuleEditor) getEditor()).getAttributes();
        }
        return Collections.emptyMap();
    }

    protected List<GlobalDescr> getGlobals() {
        if ( getEditor() instanceof DRLRuleEditor ) {
            return ((DRLRuleEditor) getEditor()).getGlobals();
        }
        return Collections.emptyList();
    }

    protected List<String> getClassesInPackage() {
        if ( getEditor() instanceof DRLRuleEditor ) {
            return ((DRLRuleEditor) getEditor()).getClassesInPackage();
        }
        return Collections.emptyList();
    }
}


/*
 * Copyright 2010 Red Hat, Inc. and/or its affiliates.
 *
 * 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.drools.eclipse.dsl.editor;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.drools.compiler.lang.dsl.DSLMapping;
import org.drools.compiler.lang.dsl.DSLMappingEntry;
import org.drools.compiler.lang.dsl.DSLTokenizedMappingFile;
import org.drools.eclipse.DroolsEclipsePlugin;
import org.drools.eclipse.builder.Util;
import org.drools.eclipse.editors.completion.DSLTree;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.runtime.CoreException;

/**
 * This holds the DSL configuration for an editor instance.
 * When loading, it will find the DSL file, and load the applicable lists.
 *
 * This provides a link between the editor and the DSL features of the rule language.
 *
 * It will look for a DSL configuration, as named in the rule file, in the same directory as the rule file.
 * Failing this, it will search one directory above the rule file.
 * Failing that, it will search the root of the project in the workspace.
 */
public class DSLAdapter {

    private String dslConfigName;
    private boolean valid = false;
    private List<String> conditionProposals = new ArrayList<String>();
    private List<String> consequenceProposals = new ArrayList<String>();
    private DSLTree dslTree = new DSLTree();

    //to dig out the expander, without using the parser.
    private static final Pattern EXPANDER_PATTERN = Pattern.compile( "\\n\\s*expander\\s*(.*)\\.dsl",
                                                             Pattern.DOTALL | Pattern.MULTILINE );
    /**
     * This will sniff out the DSL config file name from the content.
     * It will then use the IFile input to search around for the file itself.
     * TODO: provide an alternative that just loads off a stream (for non IDEs workbenches like jlibrary).
     * @param content Rule source
     * @param input File from the FileEditorInput
     */
    public DSLAdapter(String content, IFile input) throws CoreException {
        dslConfigName = findDSLConfigName( content, input );
        if (dslConfigName == null) {
            return;
        }
        loadConfig( input );
    }

    /** Get a reader to the DSL contents */
    public static Reader getDSLContent(String ruleSource, IResource input) throws CoreException {
        String dslFileName = findDSLConfigName( ruleSource, input );
        if (dslFileName == null) {
            return null;
        }
        IResource res = findDSLResource( input, dslFileName );
        if (res instanceof IFile) {
            IFile dslConf = (IFile) res;
            if (dslConf.exists()) {
                return new InputStreamReader(dslConf.getContents());
            }
        }
        return null;
    }

    /**
     * This does the hunting around the projec to find the .dsl file.
     */
    private void loadConfig(IFile input) {
        IResource res = findDSLResource( input, dslConfigName );
        if (res instanceof IFile) {
            IFile dslConf = (IFile) res;
            if (dslConf.exists()) {
                InputStream stream = null;
                try {
                    stream = dslConf.getContents();
                    readConfig( stream );
                    valid = true;
                } catch ( Exception e ) {
                    throw new IllegalStateException("Unable to open DSL config file. (Exception: " + e.getMessage() + ")");
                } finally {
                    closeStream( stream );
                }

            }
        }
    }

    private static IResource findDSLResource(IResource input, String dslFileName) {
        IResource res = input.getParent().findMember( dslFileName );
        if (res == null) res = input.getParent().getParent().findMember( dslFileName ); //try parent directory
        if (res == null) res = input.getProject().findMember( dslFileName ); //try root of project.
        return res;
    }

    /** This will load in the DSL config file, using the DSLMapping from drools-compiler */
    void readConfig(InputStream stream) throws IOException, CoreException {
        DSLTokenizedMappingFile file = new DSLTokenizedMappingFile();
        file.parseAndLoad(new InputStreamReader(stream));

        DSLMapping grammar = file.getMapping();
        List<DSLMappingEntry> conditions = grammar.getEntries( DSLMappingEntry.CONDITION );
        List<DSLMappingEntry> consequences = grammar.getEntries( DSLMappingEntry.CONSEQUENCE );

        conditionProposals = buildProposals(conditions);
        consequenceProposals = buildProposals(consequences);

        dslTree.buildTree(grammar);
    }

    private List<String> buildProposals(List<DSLMappingEntry> suggestions) {
        List<String> result = new ArrayList<String>(suggestions.size());
        for (DSLMappingEntry text : suggestions) {
            result.add(text.getMappingKey());
        }
        return result;
    }

    private void closeStream(InputStream stream) {
        if (stream != null) try {
            stream.close();
        } catch ( IOException e ) {}
    }

    DSLAdapter() {

    }

    private static String findDSLConfigName(String content, IResource input) throws CoreException {
        String dslConfigName = findDSLConfigName( content );
        if (dslConfigName == null)  {
            // try searching the .package file
            if (input != null && input.getParent() != null) {
                MyResourceVisitor visitor = new MyResourceVisitor();
                input.getParent().accept(visitor, IResource.DEPTH_ONE, IResource.NONE);
                IResource packageDef = visitor.getPackageDef();
                if (packageDef != null) {
                    if (packageDef instanceof IFile) {
                        IFile file = (IFile) packageDef;
                        try {
                            String pContent = new String(Util.getResourceContentsAsCharArray(file));
                            dslConfigName = findDSLConfigName( pContent );
                        } catch (CoreException e) {
                            DroolsEclipsePlugin.log(e);
                        }
                    }
                }
            }
        }
        return dslConfigName;
    }

    /** Sniffs out the expander/DSL config name as best it can. */
    static String findDSLConfigName(String content) {
        String name = null;
        Matcher matches = EXPANDER_PATTERN.matcher( content );
        if (matches.find()) {
            name = matches.group(1) + ".dsl";
        }
        return name;
    }

    String getDSLConfigName() {
        return dslConfigName;
    }

    public boolean isValid() {
        return valid;
    }

    public boolean hasConditions() {
        return conditionProposals.size() > 0;
    }

    public boolean hasConsequences() {
        return consequenceProposals.size() > 0;
    }

    public List<String> listConditionItems() {
        return conditionProposals;
    }

    public List<String> listConsequenceItems() {
        return consequenceProposals;
    }

    public DSLTree getDSLTree() {
        return dslTree;
    }

    private static class MyResourceVisitor implements IResourceVisitor {
        private IResource packageDef;
        public boolean visit(IResource resource) throws CoreException {
            if ("package".equals(resource.getFileExtension())) {
                packageDef = resource;
            }
            return true;
        }
        public IResource getPackageDef() {
            return packageDef;
        }
    }
}


/*
 * Copyright 2015 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 *      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.eclipse.webdav.client;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Vector;
import org.eclipse.webdav.internal.kernel.utils.Assert;

/**
 * A utility for manipulating URLs.
 *

 * Note: This class/interface is part of an interim API that is still under
 * development and expected to change significantly before reaching stability.
 * It is being made available at this early stage to solicit feedback from pioneering
 * adopters on the understanding that any code that uses this API will almost
 * certainly be broken (repeatedly) as the API evolves.
 *

 */
public class URLTool {
    /**
     * Returns the given URL with a trailing slash appended to it. If the URL
     * already has a trailing slash the URL is returned unchanged.
     *

     *
Example

     *

     *   Given URL
     *   Returned URL
     *

     *   "http://hostname/folder"
     *   "http://hostname/folder/"
     *

     *   "http://hostname/folder/
     *   "http://hostname/folder/"
     *

     *
     * @param url a URL
     * @return    the given URL with a trailing slash
     * @throws    MalformedURLException if the given URL is malformed
     */
    public static URL appendTrailingSlash(String url) throws MalformedURLException {
        return appendTrailingSlash(new URL(url));
    }

    /**
     * Returns the given URL with a trailing slash appended to
     * it. If the URL already has a trailing slash the
     * URL is returned unchanged.
     *

     *
Example

     *

     *   Given URL
     *   Returned URL
     *

     *   "http://hostname/folder"
     *   "http://hostname/folder/"
     *

     *   "http://hostname/folder/
     *   "http://hostname/folder/"
     *

     *
     * @param url a URL
     * @return    the given URL with a trailing slash
     */
    public static URL appendTrailingSlash(URL url) {
        String file = url.getFile();
        if (file.endsWith("/")) { //$NON-NLS-1$
            return url;
        }
        try {
            return new URL(url.getProtocol(), url.getHost(), url.getPort(), file + "/"); //$NON-NLS-1$
        } catch (MalformedURLException e) {
            Assert.isTrue(false, Policy.bind("assert.internalError")); //$NON-NLS-1$
        }
        return null;
    }

    /**
     * Returns the child URL formed by joining the given member with the
     * given parent URL.
     *
     * @return a child URL of the given parent
     * @throws MalformedURLException if the given parent is malformed
     */
    public static URL getChild(String parent, String member) throws MalformedURLException {
        return getChild(new URL(parent), member);
    }

    /**
     * Returns the child URL formed by joining the given member with the
     * given parent URL.
     *
     * @return a child URL of the given parent
     */
    public static URL getChild(URL parent, String member) {
        String file = parent.getFile();
        if (!file.endsWith("/")) //$NON-NLS-1$
            file = file + "/"; //$NON-NLS-1$
        try {
            return new URL(parent.getProtocol(), parent.getHost(), parent.getPort(), file + member);
        } catch (MalformedURLException e) {
            Assert.isTrue(false, Policy.bind("assert.internalError")); //$NON-NLS-1$
        }
        return null;
    }

    /**
     * Returns all elements in the given URLs path.
     *

     *
Example

     *

     *   Given URL
     *   Element
     *

     *   "http://hostname/"
     *   []
     *

     *   "http://hostname/folder/
     *   [folder]
     *

     *   "http://hostname/folder/file
     *   [folder, file]
     *

     * @param url a URL
     * @return    all elements in the given URLs path
     * @throws    MalformedURLException if the given URL is malformed
     */
    public static Vector getElements(String url) throws MalformedURLException {
        return getElements(new URL(url));
    }

    /**
     * Returns all elements in the given URLs path.
     *

     *
Example

     *

     *   Given URL
     *   Element
     *

     *   "http://hostname/"
     *   []
     *

     *   "http://hostname/folder/
     *   [folder]
     *

     *   "http://hostname/folder/file
     *   [folder, file]
     *

     * @param url a URL
     * @return    all elements in the given URLs path
     */
    public static Vector getElements(URL url) {
        Vector result = new Vector(5);
        String lastElement = null;
        while ((lastElement = getLastElement(url)) != null) {
            result.insertElementAt(lastElement, 0);
            url = getParent(url);
        }
        return result;
    }

    /**
     * Returns the last element in the given URLs path, or null
     * if the URL is the root.
     *

     *
Example

     *

     *   Given URL
     *   Last Element
     *

     *   "http://hostname/"
     *   null
     *

     *   "http://hostname/folder/
     *   folder
     *

     *   "http://hostname/folder/file
     *   file
     *

     * @param url a URL
     * @return    the last element in the given URLs path, or
     *            null if the URL is the root
     * @throws    MalformedURLException if the given URL is malformed
     */
    public static String getLastElement(String url) throws MalformedURLException {
        return getLastElement(new URL(url));
    }

    /**
     * Returns the last element in the given URLs path, or null
     * if the URL is the root.
     *

     *
Example

     *

     *   Given URL
     *   Last Element
     *

     *   "http://hostname/"
     *   null
     *

     *   "http://hostname/folder/
     *   folder
     *

     *   "http://hostname/folder/file
     *   file
     *

     * @param url a URL
     * @return    the last element in the given URLs path, or
     *            null if the URL is the root
     */
    public static String getLastElement(URL url) {
        String file = url.getFile();
        int len = file.length();

        if (len == 0 || len == 1 && file.charAt(0) == '/') {
            return null;
        }

        int lastSlashIndex = -1;
        for (int i = len - 2; lastSlashIndex == -1 && i >= 0; --i) {
            if (file.charAt(i) == '/') {
                lastSlashIndex = i;
            }
        }

        boolean isDirectory = file.charAt(len - 1) == '/';
        if (lastSlashIndex == -1) {
            if (isDirectory)
                return file.substring(0, len - 1);
            return file;
        }
        if (isDirectory)
            return file.substring(lastSlashIndex + 1, len - 1);
        return file.substring(lastSlashIndex + 1, len);
    }

    /**
     * Returns the parent URL of the given URL, or null if the
     * given URL is the root.
     *

     *
Example

     *

     *   Given URL
     *   Parent URL
     *

     *   "http://hostname/"
     *   null
     *

     *   "http://hostname/folder/file
     *   "http://hostname/folder/
     *

     *
     * @param url a URL
     * @return    the parent of the given URL
     * @throws    MalformedURLException if the given URL is malformed
     */
    public static URL getParent(String url) throws MalformedURLException {
        return getParent(new URL(url));
    }

    /**
     * Returns the parent URL of the given URL, or null if the
     * given URL is the root.
     *

     *
Example

     *

     *   Given URL
     *   Parent URL
     *

     *   "http://hostname/"
     *   null
     *

     *   "http://hostname/folder/file
     *   "http://hostname/folder/
     *

     *
     * @param url a URL
     * @return    the parent of the given URL
     */
    public static URL getParent(URL url) {
        String file = url.getFile();
        int len = file.length();

        if (len == 0 || len == 1 && file.charAt(0) == '/')
            return null;

        int lastSlashIndex = -1;
        for (int i = len - 2; lastSlashIndex == -1 && i >= 0; --i) {
            if (file.charAt(i) == '/')
                lastSlashIndex = i;
        }

        if (lastSlashIndex == -1)
            file = ""; //$NON-NLS-1$
        else
            file = file.substring(0, lastSlashIndex + 1);

        try {
            url = new URL(url.getProtocol(), url.getHost(), url.getPort(), file);
        } catch (MalformedURLException e) {
            Assert.isTrue(false, e.getMessage());
        }

        return url;
    }

    /**
     * Returns the root URL of the given URL.
     *

     *
Example

     *

     *   Given URL
     *   Root URL
     *

     *   "http://hostname/"
     *   "http://hostname/"
     *

     *   "http://hostname/folder/file
     *   "http://hostname/"
     *

     *
     * @param urlString a URL
     * @return          the root url of the given URL
     * @throws          MalformedURLException if the given URL is malformed
     */
    public static URL getRoot(String urlString) throws MalformedURLException {
        return getRoot(new URL(urlString));
    }

    /**
     * Returns the root URL of the given URL.
     *

     *
Example

     *

     *   Given URL
     *   Root URL
     *

     *   "http://hostname/"
     *   "http://hostname/"
     *

     *   "http://hostname/folder/file
     *   "http://hostname/"
     *

     *
     * @param url a URL
     * @return    the root URL of the given URL
     */
    public static URL getRoot(URL url) {
        try {
            return new URL(url.getProtocol(), url.getHost(), url.getPort(), "/"); //$NON-NLS-1$
        } catch (MalformedURLException e) {
            Assert.isTrue(false, Policy.bind("assert.internalError")); //$NON-NLS-1$
        }
        return null;
    }

    /**
     * Returns the given URL with its trailing slash removed. If the URL has
     * no trailing slash, the URL is returned unchanged.
     *

     *
Example

     *

     *   Given URL
     *   Returned URL
     *

     *   "http://hostname/folder"
     *   "http://hostname/folder"
     *

     *   "http://hostname/folder/
     *   "http://hostname/folder"
     *

     *
     * @param url a URL
     * @return    the given URL with its last slash removed
     * @throws    MalformedURLException if the given URL is malformed
     */
    public static URL removeTrailingSlash(String url) throws MalformedURLException {
        return removeTrailingSlash(new URL(url));
    }

    /**
     * Returns the given URL with its trailing slash removed. If the URL has
     * no trailing slash, the URL is returned unchanged.
     *

     *
Example

     *

     *   Given URL
     *   Returned URL
     *

     *   "http://hostname/folder"
     *   "http://hostname/folder"
     *

     *   "http://hostname/folder/
     *   "http://hostname/folder"
     *

     *
     * @param url a URL
     * @return    the given URL with its last slash removed
     */
    public static URL removeTrailingSlash(URL url) {
        String file = url.getFile();

        if (file.endsWith("/")) { //$NON-NLS-1$
            file = file.substring(0, file.length() - 1);
            try {
                return new URL(url.getProtocol(), url.getHost(), url.getPort(), file);
            } catch (MalformedURLException e) {
                Assert.isTrue(false, e.getMessage());
            }
        } else {
            return url;
        }

        return null;
    }

    /**
     * Returns a boolean indicating whether the given URLs overlap.
     *

     *
Example

     *

     *   First URL
     *   Second URL
     *   Do they overlap
     *

     *   "http://hostname/folder/"
     *   "http://hostname/folder/"
     *   true
     *

     *   "http://hostname/folder/"
     *   "http://hostname/folder/file"
     *   true
     *

     *   "http://hostname/folder/file"
     *   "http://hostname/folder/"
     *   true
     *

     *   "http://hostname/folder1/"
     *   "http://hostname/folder2/"
     *   false
     *

     * @param  url1 firt URL
     * @param  url2 second URL
     * @return a boolean indicating whether the given URLs overlap
     */
    public static boolean urlsOverlap(String url1, String url2) throws MalformedURLException {
        return urlsOverlap(new URL(url1), new URL(url2));
    }

    /**
     * Returns a boolean indicating whether the given URLs overlap.
     *

     *
Example

     *

     *   First URL
     *   Second URL
     *   Do they overlap
     *

     *   "http://hostname/folder/"
     *   "http://hostname/folder/"
     *   true
     *

     *   "http://hostname/folder/"
     *   "http://hostname/folder/file"
     *   true
     *

     *   "http://hostname/folder/file"
     *   "http://hostname/folder/"
     *   true
     *

     *   "http://hostname/folder1/"
     *   "http://hostname/folder2/"
     *   false
     *

     *   "http://hostname1/folder/"
     *   "http://hostname2/folder/"
     *   false
     *

     * @param  url1 firt URL
     * @param  url2 second URL
     * @return a boolean indicating whether the given URLs overlap
     */
    public static boolean urlsOverlap(URL url1, URL url2) {
        if (!getRoot(url1).equals(getRoot(url2))) {
            return false;
        }
        Vector elements1 = URLTool.getElements(url1);
        Vector elements2 = URLTool.getElements(url2);
        for (int i = 0; i < elements1.size() && i < elements2.size(); ++i) {
            String element1 = (String) elements1.elementAt(i);
            String element2 = (String) elements2.elementAt(i);
            if (!element1.equals(element2)) {
                return false;
            }
        }
        return true;
    }
}


/*
 * Copyright 2010 Red Hat, Inc. and/or its affiliates.
 *
 * 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.drools.eclipse.menu;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.drools.eclipse.wizard.decisiontable.NewDTFileWizard;
import org.drools.eclipse.wizard.dsl.NewDSLFileWizard;
import org.drools.eclipse.wizard.project.NewDroolsProjectWizard;
import org.drools.eclipse.wizard.rule.NewRulePackageWizard;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowPulldownDelegate;
import org.kie.eclipse.wizard.project.AbstractKieProjectWizard;

/**
 * Menu driver for launching wizards etc from the top level toolbar.
 *
 * More can be added to this as needed.
 */
public class RuleHelperActionDelegate
    implements
    IWorkbenchWindowPulldownDelegate {

    private IWorkbench workbench;
    private Menu menu;

    /** Return a menu which launches the various wizards */
    public Menu getMenu(Control parent) {

        setMenu( new Menu( parent ) );

        final Shell shell = parent.getShell();
        addProjectWizard( menu,
                shell );

        addRuleWizard( menu,
                       shell );

        addDSLWizard( menu,
                      shell );

        addDTWizard( menu,
                      shell );

        return menu;
    }

    private void setMenu(Menu menu) {
        if (this.menu != null) {
            this.menu.dispose();
        }
        this.menu = menu;
    }

    private void addDTWizard(Menu menu,
                             final Shell shell) {
        MenuItem dsl = new MenuItem( menu,
                                     SWT.NONE );
        dsl.setText( "New Decision Table" );
        dsl.addSelectionListener( new SelectionListener() {

            public void widgetSelected(SelectionEvent e) {
                NewDTFileWizard wizard = new NewDTFileWizard();
                launchWizard( shell, wizard );
            }
            public void widgetDefaultSelected(SelectionEvent e) {}
        });

    }

    private void addProjectWizard(Menu menu, final Shell shell) {
        MenuItem rule = new MenuItem(menu, SWT.NONE);
        rule.setText("New Drools Project");

        rule.addSelectionListener(new SelectionListener() {
            public void widgetSelected(SelectionEvent e) {
                AbstractKieProjectWizard wizard = new NewDroolsProjectWizard();
                launchWizard(shell, wizard);
            }

            public void widgetDefaultSelected(SelectionEvent e) {
            }
        });
    }

    private void addRuleWizard(Menu menu,
                               final Shell shell) {
        MenuItem rule = new MenuItem( menu,
                                      SWT.NONE );
        rule.setText( "New Rule" );

        rule.addSelectionListener( new SelectionListener() {
            public void widgetSelected(SelectionEvent e) {
                NewRulePackageWizard wizard = new NewRulePackageWizard();
                launchWizard( shell,
                              wizard );
            }
            public void widgetDefaultSelected(SelectionEvent e) {}
        });
    }

    private void addDSLWizard(Menu menu,
                              final Shell shell) {
        MenuItem dsl = new MenuItem( menu,
                                     SWT.NONE );
        dsl.setText( "New Domain Specific Language" );
        dsl.addSelectionListener( new SelectionListener() {

            public void widgetSelected(SelectionEvent e) {
                NewDSLFileWizard wizard = new NewDSLFileWizard();
                launchWizard( shell, wizard );
            }
            public void widgetDefaultSelected(SelectionEvent e) {}
        });
    }

    private void launchWizard(Shell shell,
                              INewWizard wizard) {
        wizard.init( workbench,
                     new DummySelection() );
        WizardDialog dialog = new WizardDialog( shell,
                                                wizard );
        dialog.open();
    }

    public void dispose() {
    }

    public void init(IWorkbenchWindow window) {
        workbench = window.getWorkbench();
    }

    public void run(IAction action) {
    }

    public void selectionChanged(IAction action,
                                 ISelection selection) {
    }

    /** Stub structured selection listener, as is required to launch the wizard */
    static class DummySelection implements IStructuredSelection {
        public Object getFirstElement() {
            return null;
        }

        public Iterator<?> iterator() {
            return (new ArrayList<Object>()).iterator();
        }

        public int size() {
            return 0;
        }

        public Object[] toArray() {
            return null;
        }

        public List<?> toList() {
            return null;
        }

        public boolean isEmpty() {
            return true;
        }
    }

}


/*
 * Copyright 2015 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 *      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.eclipse.webdav.http.client;

import java.io.*;
import org.eclipse.webdav.IContext;
import org.eclipse.webdav.IResponse;
import org.eclipse.webdav.internal.kernel.DocumentMarshaler;
import org.eclipse.webdav.internal.kernel.IDocumentMarshaler;
import org.eclipse.webdav.internal.kernel.utils.Assert;
import org.w3c.dom.Document;

/**
 * An HTTP response message.
 *

 * Note: This class/interface is part of an interim API that is still under
 * development and expected to change significantly before reaching stability.
 * It is being made available at this early stage to solicit feedback from pioneering
 * adopters on the understanding that any code that uses this API will almost
 * certainly be broken (repeatedly) as the API evolves.
 *

 */
public class Response extends Message implements IResponse, IStatusCodes {
    protected int statusCode;
    protected String statusMessage;
    protected boolean hasDocumentBody;
    protected Document document;

    /**
     * Creates a response.
     *
     * @param context the response's header, or null for an
     * empty header
     * @param inputStream an input stream containing the response's body, or
     * null for an empty body
     * @param statusCode the response's status code
     * @param statusMessage the response's status message
     */
    public Response(int statusCode, String statusMessage, IContext context, InputStream inputStream) {
        super(context, inputStream);

        Assert.isTrue(statusCode >= 100 && statusCode < 600);
        Assert.isNotNull(statusMessage);

        this.statusCode = statusCode;
        this.statusMessage = statusMessage;
        this.hasDocumentBody = false;

        // Now determine if the response has a document (XML) body
        // or is raw bytes.
        ContentType contentType = getContentType();
        if (contentType != null) {
            hasDocumentBody = "xml".equals(contentType.getSubtype()); //$NON-NLS-1$
        }
    }

    /**
     * Returns the content length of this message's body, or -1 if the
     * content length is unknown.
     *
     * @return the content length of this message's body
     */
    public long getContentLength() {

        // Get the declared content length.
        long contentLength = context.getContentLength();

        // If it is defined send the answer.
        if (contentLength != -1)
            return contentLength;

        // Certain messages are defined as having zero length
        // message bodies.
        int statusCode = getStatusCode();
        if (statusCode == IResponse.SC_NO_CONTENT || statusCode == IResponse.SC_NOT_MODIFIED || statusCode >= 100 && statusCode < 200)
            return 0;

        // We don't know how long the body is.
        return -1;
    }

    /**
     * Returns the content type of this response's body, or null
     * if the content type is unknown.
     *
     * @return the content type of this response's body
     */
    public ContentType getContentType() {
        String contentTypeString = context.getContentType();
        if (contentTypeString == null)
            return null;
        ContentType contentType = null;
        try {
            contentType = new ContentType(contentTypeString);
        } catch (IllegalArgumentException e) {
            // ignore or log?
        }
        return contentType;
    }

    /**
     * Returns this response's body as a DOM Document. This
     * response must have a document body.
     *
     * @exception IOException if there is an I/O error
     */
    public Document getDocumentBody() throws IOException {
        Assert.isTrue(hasDocumentBody);
        Assert.isTrue(!hasInputStream);
        // Lazily parse the message body.
        if (document == null) {
            String characterEncoding = null;
            ContentType contentType = getContentType();
            if (contentType != null) {
                characterEncoding = contentType.getValue("charset"); //$NON-NLS-1$
            }
            if (characterEncoding == null) {
                characterEncoding = "ASCII"; //$NON-NLS-1$
            }
            IDocumentMarshaler marshaler = new DocumentMarshaler();
            document = marshaler.parse(new InputStreamReader(is, characterEncoding));
        }
        return document;
    }

    /**
     * Returns this response's status code.
     *
     * @return this response's status code
     */
    public int getStatusCode() {
        return statusCode;
    }

    /**
     * Returns this response's status message.
     *
     * @return this response's status message
     */
    public String getStatusMessage() {
        return statusMessage;
    }

    /**
     * Returns a boolean indicating whether this response has a body that can
     * be marshaled to become a DOM Document.
     *
     * @return a boolean indicating whether this response has a body that can
     * be marshaled to become a DOM Document
     * @see Document
     */
    public boolean hasDocumentBody() {
        return hasDocumentBody;
    }

    public String toString() {
        StringBuffer buffer = new StringBuffer();
        buffer.append(statusCode);
        buffer.append(' ');
        buffer.append(statusMessage);
        buffer.append('\n');
        buffer.append(super.toString());
        return buffer.toString();
    }
}


/*
 * Copyright 2010 Red Hat, Inc. and/or its affiliates.
 *
 * 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.drools.eclipse.reteoo;

import org.drools.core.reteoo.QueryElementNode;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.swt.graphics.Color;

/**
 * Wraps {@link org.drools.core.reteoo.QueryTerminalNode} and adds visual extras like color information
 */
public class QueryElementNodeVertex extends BaseVertex {

    private static final String NODE_NAME = "QueryElementNode";

    private final QueryElementNode node;

    /**
     * Constructor
     *
     * @param node node to be wrapped
     */
    public QueryElementNodeVertex(final QueryElementNode node) {
        super();
        this.node = node;
    }

    /* (non-Javadoc)
     * @see org.drools.core.reteoo.BaseNodeVertex#getHtml()
     */
    public String getHtml() {
        return NODE_NAME + " : " + this.node.getId() + " : " + this.node.getQueryElement() == null ? "" : this.node.getQueryElement().getQueryName();
    }

    /* (non-Javadoc)
     * @see org.drools.eclipse.editors.rete.model.BaseVertex#toString()
     */
    public String toString() {
        return NODE_NAME + " : " + this.node.getId() + " : " + this.node.getQueryElement() == null ? "" : this.node.getQueryElement().getQueryName();
    }

    /* (non-Javadoc)
     * @see org.drools.core.reteoo.BaseNodeVertex#getFillColor()
     */
    public Color getFillColor() {
        return ColorConstants.white;
    }

    /**
     * Node ID
     *
     * @return id
     */
    public int getId() {
        return this.node.getId();
    }

    /**
     * @return
     */
    public String getQueryName() {
        return node.getQueryElement() == null ? null : node.getQueryElement().getQueryName();
    }

}


/*
 * Copyright 2015 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 *      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.eclipse.webdav.dom;

import java.util.Enumeration;
import java.util.NoSuchElementException;
import org.eclipse.webdav.Policy;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * An element editor for the WebDAV multistatus element. See RFC2518
 * section 12.9 for the element's definition.
 *

 * Note: This class/interface is part of an interim API that is still under
 * development and expected to change significantly before reaching stability.
 * It is being made available at this early stage to solicit feedback from pioneering
 * adopters on the understanding that any code that uses this API will almost
 * certainly be broken (repeatedly) as the API evolves.
 *

 *
 * @see ResponseBody
 */
public class MultiStatus extends ElementEditor {
    /**
     * An ordered collection of the element names of the multistatus
     * element's children.
     */
    protected static final String[] childNames = new String[] {"response", "responsedescription"}; //$NON-NLS-1$ //$NON-NLS-2$

    /**
     * Creates a new editor on the given WebDAV multistatus element. The
     * element is assumed to be well formed.
     *
     * @param root a multistatus element
     * @throws        MalformedElementException if there is reason to
     *                believe that the element is not well formed
     */
    public MultiStatus(Element root) throws MalformedElementException {
        super(root, "multistatus"); //$NON-NLS-1$
    }

    /**
     * Creates and adds a response element to this multistatus and returns
     * an editor on it.
     *
     * @return an editor on a response element
     */
    public ResponseBody addResponse() {
        Element response = addChild(root, "response", childNames, true); //$NON-NLS-1$
        try {
            return new ResponseBody(response);
        } catch (MalformedElementException e) {
            Assert.isTrue(false, Policy.bind("assert.internalError")); //$NON-NLS-1$
            return null; // Never reached.
        }
    }

    /**
     * Creates a new WebDAV multistatus element and sets it as the root of
     * the given document.  Returns an editor on the new multistatus element.
     *

     * The document must not be null, and must not already have
     * a root element.

     *
     * @param document the document that will become the root of a new
     *                 multistatus element
     * @return         an element editor on a multistatus element
     */
    public static MultiStatus create(Document document) {
        Assert.isNotNull(document);
        Assert.isTrue(document.getOwnerDocument() == null);
        Element element = create(document, "multistatus"); //$NON-NLS-1$
        try {
            return new MultiStatus(element);
        } catch (MalformedElementException e) {
            Assert.isTrue(false, Policy.bind("assert.internalError")); //$NON-NLS-1$
            return null; // Never reached.
        }
    }

    /**
     * Returns this multistatus' response description, or null
     * if it has none.
     *
     * @return this multistatus' response description, or null
     * @throws MalformedElementException if there is reason to believe that
     *         this editor's underlying element is not well formed
     */
    public String getResponseDescription() throws MalformedElementException {
        return getChildText(root, "responsedescription", false); //$NON-NLS-1$
    }

    /**
     * Returns an Enumeration over this multistatus' responses.
     *
     * @return an Enumeration of ResponseBodys
     * @throws MalformedElementException if there is reason to believe that
     *         this editor's underlying element is not well formed
     */
    public Enumeration getResponses() throws MalformedElementException {

        final Element firstResponse = getFirstChild(root, "response"); //$NON-NLS-1$
        ensureNotNull(Policy.bind("ensure.missingResponseElmt"), firstResponse); //$NON-NLS-1$

        Enumeration e = new Enumeration() {
            Element currentResponse = firstResponse;

            public boolean hasMoreElements() {

                return currentResponse != null;
            }

            public Object nextElement() {

                if (!hasMoreElements())
                    throw new NoSuchElementException();

                ResponseBody responseBody = null;
                try {
                    responseBody = new ResponseBody(currentResponse);
                } catch (MalformedElementException ex) {
                    Assert.isTrue(false, Policy.bind("assert.internalError")); //$NON-NLS-1$
                }

                currentResponse = getTwin(currentResponse, true);

                return responseBody;
            }
        };

        return e;
    }

    /**
     * Sets this multistatus' response description to the given value. If
     * the value is null and a response description has already
     * been set, it is removed.
     *
     * @param value a response description, or null
     */
    public void setResponseDescription(String value) {
        if (value == null) {
            Element child = getLastChild(root, "responsedescription"); //$NON-NLS-1$
            if (child != null)
                root.removeChild(child);
        } else
            setChild(root, "responsedescription", value, childNames, false); //$NON-NLS-1$
    }
}


/*
 * Copyright 2010 Red Hat, Inc. and/or its affiliates.
 *
 * 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.guvnor.tools;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.viewers.IDecoration;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ILightweightLabelDecorator;
import org.guvnor.tools.preferences.GuvnorPreferencePage;
import org.guvnor.tools.preferences.IGuvnorPreferenceConstants;
import org.guvnor.tools.utils.GuvnorMetadataProps;
import org.guvnor.tools.utils.GuvnorMetadataUtils;
/**
 * Handles decorating Guvnor resources with an icon overlay and label text.
 */
public class GuvnorDecorator implements ILightweightLabelDecorator {

    public static final String DECORATOR_ID = "org.guvnor.tools.decorator"; //$NON-NLS-1$

    private boolean isGuvnorResource(Object element) {
        if (element instanceof IResource) {
            return GuvnorMetadataUtils.findGuvnorMetadata((IResource)element) != null;
        } else {
            return false;
        }
    }

    private void decorateResource(IResource resource, IDecoration decoration) {
        try {
            if (resource instanceof IFile) {

                if(!((IFile)resource).exists()){
                    return ;
                }

                addGuvnorOverlay(decoration);
                addChangeIndicator(resource, decoration);
                addResourceDetails(resource, decoration);
            }
        } catch (Exception e) {
            Activator.getDefault().writeLog(IStatus.ERROR, e.getMessage(), e);
        }
    }

    private void addGuvnorOverlay(IDecoration decoration) {
        int overlayLoc = GuvnorPreferencePage.getOverlayLocationPref();
        if (overlayLoc != IGuvnorPreferenceConstants.NO_OVERLAY) {
            decoration.addOverlay(Activator.getImageDescriptor(Activator.IMG_GUVCONTROLLED),
                                 overlayLoc);
        }
    }

    private void addResourceDetails(IResource resource, IDecoration decoration)
            throws Exception {
        GuvnorMetadataProps props = GuvnorMetadataUtils.getGuvnorMetadata(resource);
        if (props.getVersion() != null) {
            boolean showRevision = GuvnorPreferencePage.shouldShowRevision();
            boolean showDateTime = GuvnorPreferencePage.shouldShowTimeDateStamp();
            if (showRevision || showDateTime) {
                decoration.addSuffix(" ");     //$NON-NLS-1$
            }
            if (showRevision) {
                decoration.addSuffix(props.getRevision());
            }
            if (showDateTime) {
                if (showRevision) {
                    decoration.addSuffix(", " + props.getVersion());         //$NON-NLS-1$
                } else {
                    decoration.addSuffix(props.getVersion());
                }
            }
        }
    }

    private void addChangeIndicator(IResource resource, IDecoration decoration)
            throws CoreException {
        if (!GuvnorMetadataUtils.isGuvnorResourceCurrent(resource)
           && GuvnorPreferencePage.shouldShowChangeIndicator()) {
            decoration.addSuffix(" >"); //$NON-NLS-1$
        }
    }

    public void decorate(Object element, IDecoration decoration) {
        if (isGuvnorResource(element)) {
            if (element instanceof IResource) {
                decorateResource((IResource)element, decoration);
            } else {
                Activator.getDefault().writeLog(IStatus.ERROR,
                        "Called to decorate unknown: " + element.getClass().toString(), new Exception()); //$NON-NLS-1$
            }
        }
    }

    public void addListener(ILabelProviderListener listener) { }

    public void dispose() { }

    public boolean isLabelProperty(Object element, String property) {
        return false;
    }

    public void removeListener(ILabelProviderListener listener) { }
}


/*
 * Copyright 2015 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 *      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.eclipse.webdav.dom;

import java.util.Enumeration;
import java.util.NoSuchElementException;
import org.eclipse.webdav.Policy;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * An element editor for sets of hrefs, for example, the WebDAV
 * predecessor-set element.
 *

 * Note: This class/interface is part of an interim API that is still under
 * development and expected to change significantly before reaching stability.
 * It is being made available at this early stage to solicit feedback from pioneering
 * adopters on the understanding that any code that uses this API will almost
 * certainly be broken (repeatedly) as the API evolves.
 *

 */
public class HrefSet extends ElementEditor {
    /**
     * Creates a new editor on the given href set element with the given
     * name. The element is assumed to be well formed.
     *
     * @param root    an href element
     * @param name    the name of the element that this editor is expected
     *                to manipulate.
     * @throws        MalformedElementException if there is reason to
     *                believe that the element is not well formed
     */
    public HrefSet(Element root, QualifiedName name) throws MalformedElementException {
        super(root, name.getLocalName());
        ensure(DAV_NS.equals(name.getQualifier()), Policy.bind("ensure.mustHaveDAVQualifier")); //$NON-NLS-1$
    }

    /**
     * Adds the given href to the end of the set of hrefs. If the href
     * already exists it is not added.
     *
     * @param href    the href to add to the end of the set of hrefs
     */
    public void addHref(String href) {
        String encodedHref = encodeHref(href);
        if (isDuplicate(encodedHref))
            return;
        appendChild(root, "href", encodedHref); //$NON-NLS-1$
    }

    /**
     * Creates a new href set element with the given name and sets it as
     * the root of the given document. Returns an editor on the new href set
     * element. The document must not be null, and must not
     * already have a root element.
     *
     * @param document the document that will become the root of a new
     *                 href set element
     * @return         an element editor on a href set element
     */
    public static HrefSet create(Document document, QualifiedName name) {
        Assert.isNotNull(document);
        Assert.isTrue(document.getOwnerDocument() == null);
        Assert.isNotNull(name);
        Assert.isTrue(DAV_NS.equals(name.getQualifier()));
        Element element = create(document, name.getLocalName());
        try {
            return new HrefSet(element, name);
        } catch (MalformedElementException e) {
            Assert.isTrue(false, Policy.bind("assert.internalError")); //$NON-NLS-1$
            return null; // Never reached.
        }
    }

    /**
     * Returns an Enumeration over the set of hrefs.
     *
     * @return an Enumeration of href Strings
     */
    public Enumeration getHrefs() {
        final Element firstHref = getFirstChild(root, "href"); //$NON-NLS-1$
        Enumeration e = new Enumeration() {
            Element currentHref = firstHref;

            public boolean hasMoreElements() {
                return currentHref != null;
            }

            public Object nextElement() {
                if (!hasMoreElements())
                    throw new NoSuchElementException();
                String href = getFirstText(currentHref);
                currentHref = getNextSibling(currentHref, "href"); //$NON-NLS-1$
                return decodeHref(href);
            }
        };
        return e;
    }

    /**
     * Inserts the given newHref after the given refHref in the set of
     * hrefs. If newHref already exists it is not inserted.
     *
     * @param refHref the existing href
     * @param newHref the new href to be inserted after the existing href
     */
    public void insertHrefAfter(String refHref, String newHref) {
        String refHrefEncoded = encodeHref(refHref);
        String newHrefEncoded = encodeHref(newHref);
        if (isDuplicate(newHrefEncoded))
            return;
        Element child = getFirstChild(root, "href"); //$NON-NLS-1$
        while (child != null) {
            if (refHrefEncoded.equals(getFirstText(child))) {
                Element nextSibling = getNextSibling(child, "href"); //$NON-NLS-1$
                if (nextSibling == null)
                    appendChild(root, "href", newHrefEncoded); //$NON-NLS-1$
                else
                    insertBefore(nextSibling, "href", newHrefEncoded); //$NON-NLS-1$
                return;
            }
            child = getNextSibling(child, "href"); //$NON-NLS-1$
        }
        Assert.isTrue(false, Policy.bind("assert.noHrefRef")); //$NON-NLS-1$
    }

    /**
     * Inserts the given newHref before the given refHref in the set of
     * hrefs. If newHref already exists it is not inserted.
     *
     * @param refHref the existing href
     * @param newHref the new href to be inserted before the existing href
     */
    public void insertHrefBefore(String newHref, String refHref) {
        String refHrefEncoded = encodeHref(refHref);
        String newHrefEncoded = encodeHref(newHref);
        if (isDuplicate(newHrefEncoded))
            return;
        Element child = getFirstChild(root, "href"); //$NON-NLS-1$
        while (child != null) {
            if (refHrefEncoded.equals(getFirstText(child))) {
                insertBefore(child, "href", newHrefEncoded); //$NON-NLS-1$
                return;
            }
            child = getNextSibling(child, "href"); //$NON-NLS-1$
        }
        Assert.isTrue(false, Policy.bind("assert.noHrefRef")); //$NON-NLS-1$
    }

    protected boolean isDuplicate(String encodedHref) {
        Element child = getFirstChild(root, "href"); //$NON-NLS-1$
        while (child != null) {
            if (encodedHref.equals(getFirstText(child)))
                return true;
            child = getNextSibling(child, "href"); //$NON-NLS-1$
        }
        return false;
    }

    /**
     * Remove the given href from the set of hrefs.
     *
     * @param href    the href to remove from the set of hrefs
     */
    public void removeHref(String href) {
        String encodedHref = encodeHref(href);
        Element child = getFirstChild(root, "href"); //$NON-NLS-1$
        while (child != null) {
            if (encodedHref.equals(getFirstText(child))) {
                root.removeChild(child);
                return;
            }
            child = getNextSibling(child, "href"); //$NON-NLS-1$
        }
    }
}