/*
 * 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.Collections;
import java.util.Iterator;
import java.util.List;

import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.contentassist.IContextInformationValidator;
import org.eclipse.ui.IEditorPart;

public abstract class AbstractCompletionProcessor implements IContentAssistProcessor {

    private IEditorPart editor;

    public AbstractCompletionProcessor(IEditorPart editor) {
        this.editor = editor;
    }

    protected IEditorPart getEditor() {
        return editor;
    }

    public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int documentOffset) {
        List<ICompletionProposal> proposals = getCompletionProposals(viewer, documentOffset);
        if (proposals == null) {
            return new ICompletionProposal[0];
        }
        Collections.sort(proposals, new RuleCompletionProposal.RuleCompletionProposalComparator());
        return proposals.toArray(new ICompletionProposal[proposals.size()]);
    }

    /**
     * Returns a list of RuleCompletionProposals.
     *
     * @param viewer
     * @param documentOffset
     * @return
     */
    protected abstract List<ICompletionProposal> getCompletionProposals(ITextViewer viewer, int documentOffset);

    /**
     *  Filter out the proposals whose content does not start with the given prefix.
     */
    protected static void filterProposalsOnPrefix(String prefix, List<ICompletionProposal> props) {
        if ( prefix != null && prefix.trim().length() > 0 ) {
            Iterator<ICompletionProposal> iterator = props.iterator();
            String prefixLc = prefix.toLowerCase();
            while ( iterator.hasNext() ) {
                ICompletionProposal item = iterator.next();
                String content = item.getDisplayString().toLowerCase();
                if ( !content.toLowerCase().startsWith( prefixLc ) ) {
                    iterator.remove();
                }
            }
        }
    }

    /**
     * Read some text from behind the cursor position.
     * This provides context to both filter what is shown based
     * on what the user has typed in, and also to provide more information for the
     * list of suggestions based on context.
     */
    protected String readBackwards(int documentOffset, IDocument doc) throws BadLocationException {
        int startPart = doc.getPartition(documentOffset).getOffset();
        String prefix = doc.get(startPart, documentOffset - startPart);
        return prefix;
    }

    /*
     * @see IContentAssistProcessor
     */
    public char[] getCompletionProposalAutoActivationCharacters() {
        return null;
    }

    /*
     * @see IContentAssistProcessor
     */
    public char[] getContextInformationAutoActivationCharacters() {
        return null;
    }

    /*
     * @see IContentAssistProcessor
     */
    public IContextInformationValidator getContextInformationValidator() {
        return null;
    }

    /*
     * @see IContentAssistProcessor
     */
    public IContextInformation[] computeContextInformation(ITextViewer viewer, int documentOffset) {
        return null;
    }

    /*
     * @see IContentAssistProcessor
     */
    public String getErrorMessage() {
        return null;
    }
}


/*
 * 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.rete;

import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.drools.eclipse.editors.rete.model.Connection;
import org.drools.eclipse.editors.rete.model.ReteGraph;
import org.drools.eclipse.reteoo.BaseVertex;
import org.eclipse.draw2d.geometry.Point;

/**
 * Factory methods for calculating and layouting reteoo graph
 */
public class ReteooLayoutFactory {

    /**
     * Calculates layouting for provided graph.
     *
     * @param root graph root vertex
     *
     * @return Optimally layouted rows from provided graph
     */
    public static RowList calculateReteRows(BaseVertex root) {
        RowList rowList = new RowList();

        rowList.add( 0,
                     root );

        int curRow = 0;

        final Set<BaseVertex> seenVertices = new HashSet<BaseVertex>();
        seenVertices.add( root );

        while ( curRow < rowList.getDepth() ) {
            final List<BaseVertex> rowVertices = rowList.get( curRow ).getVertices();

            for ( final Iterator<BaseVertex> rowNodeIter = rowVertices.iterator(); rowNodeIter.hasNext(); ) {
                final BaseVertex rowNode = rowNodeIter.next();

                final List<Connection> edges = rowNode.getSourceConnections();

                for ( final Iterator<Connection> edgeIter = edges.iterator(); edgeIter.hasNext(); ) {

                    final Connection edge = edgeIter.next();
                    final BaseVertex destNode = edge.getOpposite( rowNode );

                    if ( !seenVertices.contains( destNode ) ) {
                        rowList.add( curRow + 1,
                                     destNode );
                        seenVertices.add( destNode );
                    }
                }

                seenVertices.add( rowNode );
            }

            ++curRow;
        }

        rowList.optimize();

        return rowList;
    }

    /**
     * Adds all vertices from rowList to the graph.
     *
     * @param graph
     * @param rowList
     */
    public static void layoutRowList(ReteGraph graph,
                                     RowList rowList) {
        new LayoutCalculator( graph,
                              rowList );
    }

    private static class LayoutCalculator {

        public final static String COORDS                = "drools.LayoutCalculator.coords";

        private static final int   COLUMN_SPACE          = 40;
        private static final int   ROW_HEIGHT_MULTIPLIER = 6;

        private RowList            rowList;

        private int                columnWidth;
        private int                rowHeight;

        private ReteGraph          graph;

        private LayoutCalculator(final ReteGraph graph,
                                 final RowList rowList) {
            this.graph = graph;
            this.rowList = rowList;
            computeSize();

            List<BaseVertex> vertices = getGraph().getChildren();
            for (BaseVertex v : vertices) {
                initialize_local_vertex( v );
            }

        }

        private void computeSize() {
            final List<BaseVertex> vertices = getGraph().getChildren();

            for (final BaseVertex vertex : vertices) {

                final int width = vertex.getSize().width;
                final int height = vertex.getSize().height;

                if ( width > this.columnWidth ) {
                    this.columnWidth = width;
                }

                if ( height > this.rowHeight ) {
                    this.rowHeight = height;
                }
            }

            this.columnWidth = this.columnWidth + LayoutCalculator.COLUMN_SPACE;
        }

        private void initialize_local_vertex(final BaseVertex vertex) {
            final int row = this.rowList.getRow( vertex );
            final int col = this.rowList.getColumn( vertex );

            final int rowWidth = this.rowList.getWidth( row );

            final int columnWidthPx = columnWidth;
            final int rowHeightPx = rowHeight;

            double x = (col * columnWidthPx);
            double y = (row * (rowHeightPx * LayoutCalculator.ROW_HEIGHT_MULTIPLIER));

            x = x + (columnWidthPx / 2) - ((rowWidth - 1) * (columnWidthPx / 2));
            y = y + (rowHeightPx / 2) + 3;

            vertex.setLocation( new Point( x,
                                           y ) );
        }

        private ReteGraph getGraph() {
            return graph;
        }
    }

}


/*
 * 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.rete.figure;

import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;

/**
 * Figure representing BaseVertex
 */
public class VertexFigure extends Figure {

    final private Color backgroundColor;
    final private Color borderColor;

    /**
     * Initializing Figure
     *
     * @param backgroundColor background color
     * @param borderColor border color
     */
    public VertexFigure(Color backgroundColor,
                        Color borderColor) {
        this.backgroundColor = backgroundColor;
        this.borderColor = borderColor;
    }

    /**
     * Painting antialiased vertex
     */
    public void paint(Graphics g) {
        g.setAntialias( SWT.ON );
        Rectangle r = getBounds().getCopy();
        g.translate( r.getLocation() );
        g.setBackgroundColor( backgroundColor );
        g.setForegroundColor( borderColor );
        g.fillArc( 0,
                   0,
                   15,
                   15,
                   0,
                   360 );
        g.drawArc( 0,
                   0,
                   14,
                   14,
                   0,
                   360 );
        super.paint( g );
    }

}


/*
 * 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.rete.part;

import org.drools.eclipse.DroolsEclipsePlugin;
import org.drools.eclipse.editors.rete.model.Connection;
import org.drools.eclipse.editors.rete.model.ReteGraph;
import org.drools.eclipse.reteoo.BaseVertex;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartFactory;

/**
 * Factory mapping model elements to edit parts
 */
public class VertexEditPartFactory
    implements
    EditPartFactory {

    /*
     * (non-Javadoc)
     * @see org.eclipse.gef.EditPartFactory#createEditPart(org.eclipse.gef.EditPart, java.lang.Object)
     */
    public EditPart createEditPart(EditPart context,
                                   Object modelElement) {
        // get EditPart for model element
        EditPart part = getPartForElement( modelElement );
        // store model element in EditPart
        part.setModel( modelElement );
        return part;
    }

    /**
     * Maps object to EditPart.
     *
     * @throws RuntimeException if no match was found
     */
    private EditPart getPartForElement(Object modelElement) {
        if ( modelElement instanceof ReteGraph ) {
            return new DiagramEditPart();
        }
        if ( modelElement instanceof BaseVertex ) {
            return new VertexEditPart();
        }
        if ( modelElement instanceof Connection ) {
            return new ConnectionEditPart();
        }
        DroolsEclipsePlugin.log( new Exception( "Can't create part for model element: " + ((modelElement != null) ? modelElement.getClass().getName() : "null") ) );
        return null;

    }

}


/*
 * 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.jbpm.eclipse;

import java.util.MissingResourceException;
import java.util.ResourceBundle;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugException;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;

/**
 * The main plugin class to be used in the desktop.
 *
 */
public class JBPMEclipsePlugin extends AbstractUIPlugin {

    public static final String          PLUGIN_ID                  = "org.jbpm.eclipse";

    // The shared instance.
    private static JBPMEclipsePlugin    plugin;

    /**
     * The constructor.
     */
    public JBPMEclipsePlugin() {
        super();
        plugin = this;
    }

    /**
     * This method is called upon plug-in activation
     */
    public void start(BundleContext context) throws Exception {
        super.start( context );
    }

    /**
     * This method is called when the plug-in is stopped
     */
    public void stop(BundleContext context) throws Exception {
        super.stop( context );
        plugin = null;
    }

    /**
     * Returns the shared instance.
     */
    public static JBPMEclipsePlugin getDefault() {
        return plugin;
    }

    /**
     * Returns the string from the plugin's resource bundle,
     * or 'key' if not found.
     */
    public static String getResourceString(String key) {
        ResourceBundle bundle = JBPMEclipsePlugin.getDefault().getResourceBundle();
        try {
            return (bundle != null) ? bundle.getString( key ) : key;
        } catch ( MissingResourceException e ) {
            return key;
        }
    }

    /**
     * Returns the plugin's resource bundle,
     */
    public ResourceBundle getResourceBundle() {
        return null;
    }

    /**
     * Returns an image descriptor for the image file at the given
     * plug-in relative path.
     * Uses the plug ins image registry to "cache" it.
     *
     * @param path the path
     * @return the image descriptor
     */
    public static ImageDescriptor getImageDescriptor(String path) {
        JBPMEclipsePlugin plugin = getDefault();
        ImageRegistry reg = plugin.getImageRegistry();
        ImageDescriptor des = reg.getDescriptor(path);
        if (des == null) {
            des = AbstractUIPlugin.imageDescriptorFromPlugin("org.jbpm.eclipse", path);
            reg.put(path, des);
        }
        return des;
    }

    public static String getUniqueIdentifier() {
        if (getDefault() == null) {
            return PLUGIN_ID;
        }
        return getDefault().getBundle().getSymbolicName();
    }

    protected void initializeDefaultPreferences(IPreferenceStore store) {
    }

    public static void log(Throwable t) {
        Throwable top = t;
        if (t instanceof DebugException) {
            DebugException de = (DebugException) t;
            IStatus status = de.getStatus();
            if (status.getException() != null) {
                top = status.getException();
            }
        }
        log(new Status(IStatus.ERROR,
                       getUniqueIdentifier(),
                       1033,
                       "Internal error in jBPM Plugin: ",
                       top ) );
    }

    public static void log(IStatus status) {
        getDefault().getLog().log( status );
    }
}


/*
 * 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;

import java.net.MalformedURLException;
import java.net.URL;

import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.swt.graphics.Image;

/**
 * Handles the images used in this plugin.
 */
public class DroolsPluginImages {

    public static final String IMG_LOGICAL = "ImageLogical";
    public static final String IMG_LOGICAL_DISABLED = "ImageLogicalDisabled";
    public static final String REFRESH_LOG = "RefreshLog";
    public static final String REFRESH_LOG_DISABLED = "RefreshLogDisabled";
    public static final String OPEN_LOG = "OpenLog";
    public static final String DELETE_LOG = "ClearLog";
    public static final String DELETE_LOG_DISABLED = "ClearLogDisabled";
    public static final String INSERT = "Insert";
    public static final String UPDATE = "Update";
    public static final String RETRACT = "RetractO";
    public static final String CREATE_ACTIVATION = "CreateActivation";
    public static final String CANCEL_ACTIVATION = "CancelActivation";
    public static final String EXECUTE_ACTIVATION = "ExecuteActivation";
    public static final String CLASS = "Class";
    public static final String PACKAGE = "Package";
    public static final String METHOD = "Method";
    public static final String VARIABLE = "Variable";
    public static final String DROOLS = "Drools";
    public static final String RULE = "DroolsRule";
    public static final String QUERY = "DroolsQuery";
    public static final String DSL_EXPRESSION = "DslExpression";
    public static final String IMPORT = "Import";
    public static final String DSL = "DSL";
    public static final String GLOBAL = "Global";
    public static final String RULEFLOW = "RuleFlow";
    public static final String RULEFLOW_GROUP = "RuleFlowGroup";
    public static final String RULEFLOW_NODE_TRIGGERED = "RuleFlowNodeTriggered";
    public static final String RULEGROUP = "RuleGroup";
    public static final String DEFAULTRULEGROUP = "DefaultRuleGroup";

    // TODO : Change Image
    public static final String GROUPS = "RuleFlowGroup";

    private static ImageRegistry imageRegistry;
    private static final String PATH_SUFFIX = "/icons/";
    private static final URL ICON_BASE_URL =
        DroolsEclipsePlugin.getDefault().getBundle().getEntry(PATH_SUFFIX);

    private static void declareImages() {
        declareRegistryImage(IMG_LOGICAL, "logical_structure.gif");
        declareRegistryImage(IMG_LOGICAL_DISABLED, "logical_structure_disabled.gif");
        declareRegistryImage(REFRESH_LOG, "refresh.gif");
        declareRegistryImage(REFRESH_LOG_DISABLED, "refresh_disabled.gif");
        declareRegistryImage(OPEN_LOG, "open.gif");
        declareRegistryImage(DELETE_LOG, "clear.gif");
        declareRegistryImage(DELETE_LOG_DISABLED, "clear_disabled.gif");
        declareRegistryImage(INSERT, "greensquare.GIF");
        declareRegistryImage(UPDATE, "yellowsquare.GIF");
        declareRegistryImage(RETRACT, "redsquare.GIF");
        declareRegistryImage(CREATE_ACTIVATION, "arrowright.GIF");
        declareRegistryImage(CANCEL_ACTIVATION, "arrowleft.GIF");
        declareRegistryImage(EXECUTE_ACTIVATION, "bluediamond.GIF");
        declareRegistryImage(CLASS, "class_obj.gif");
        declareRegistryImage(PACKAGE, "package_obj.gif");
        declareRegistryImage(METHOD, "methpub_obj.gif");
        declareRegistryImage(VARIABLE, "field_private_obj.gif");
        declareRegistryImage(DROOLS, "drools.gif");
        declareRegistryImage(RULE, "drools-rule.GIF");
        declareRegistryImage(QUERY, "drools-query.GIF");
        declareRegistryImage(DSL_EXPRESSION, "dsl_expression.gif");
        declareRegistryImage(IMPORT, "import.gif");
        declareRegistryImage(DSL, "dsl.GIF");
        declareRegistryImage(GLOBAL, "field_public_obj.gif");
        declareRegistryImage(RULEFLOW, "process.gif");
        declareRegistryImage(RULEFLOW_GROUP, "activity.gif");
        declareRegistryImage(RULEFLOW_NODE_TRIGGERED, "node-triggered.gif");
        declareRegistryImage(RULEGROUP, "package_obj.gif");
        declareRegistryImage(DEFAULTRULEGROUP, "package_obj.gif");
    }

    /**
     * Declare an Image in the registry table.
     * @param key   The key to use when registering the image
     * @param path  The path where the image can be found. This path is relative to where
     *              this plugin class is found (i.e. typically the packages directory)
     */
    public final static void declareRegistryImage(String key, String path) {
        ImageDescriptor desc= ImageDescriptor.getMissingImageDescriptor();
        try {
            desc= ImageDescriptor.createFromURL(makeIconFileURL(path));
        } catch (MalformedURLException e) {
            DroolsEclipsePlugin.log(e);
        }
        imageRegistry.put(key, desc);
    }

    /**
     * Returns the ImageRegistry.
     */
    public static ImageRegistry getImageRegistry() {
        if (imageRegistry == null) {
            initializeImageRegistry();
        }
        return imageRegistry;
    }

    public static ImageRegistry initializeImageRegistry() {
        imageRegistry = new ImageRegistry();
        declareImages();
        return imageRegistry;
    }

    /**
     * Returns the Image identified by the given key,
     * or null if it does not exist.
     */
    public static Image getImage(String key) {
        return getImageRegistry().get(key);
    }

    public static void putImage(String key, Image image) {
        getImageRegistry().put(key, image);
    }

    /**
     * Returns the ImageDescriptor identified by the given key,
     * or null if it does not exist.
     */
    public static ImageDescriptor getImageDescriptor(String key) {
        return getImageRegistry().getDescriptor(key);
    }

    private static URL makeIconFileURL(String iconPath) throws MalformedURLException {
        if (ICON_BASE_URL == null) {
            throw new MalformedURLException();
        }

        return new URL(ICON_BASE_URL, iconPath);
    }
}


/*
 * 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.internal.authentication;

import java.net.*;
import java.security.SecureRandom;
import java.util.*;
import org.eclipse.webdav.IResponse;
import org.eclipse.webdav.client.Policy;
import org.eclipse.webdav.http.client.*;
import org.eclipse.webdav.internal.kernel.utils.Assert;

/**
 * The DigestAuthority provides the necessary behavior to
 * authorizes client Request</codes>s for communication with HTTP
 * servers using the Digest authentication scheme.
 *
 * @see AuthorizationAuthority
 */
public class DigestAuthority extends AuthorizationAuthority {

    /**
     * Creates a new authenticator that stores its authentication information
     * in the given authentication store.
     *
The DigestAuthenticator authenticates according to the
     * "Digest" authentication scheme.
     *
Instances of this class must not be created directly, instead, use
     * an instance of the class Authenticator to authorize
     * requests.
     *
     * @param authenticatorStore a store that holds authentication
     * information
     */
    public DigestAuthority(IAuthenticator authenticatorStore) {
        super(authenticatorStore);
    }

    /**
     * @see Authenticator#confirmResponse(Request, Response, URL)
     */
    protected boolean confirmResponse(Request request, IResponse response, URL proxyServerUrl) {
        Assert.isNotNull(request);
        Assert.isNotNull(response);

        String authInfoString = response.getContext().get("Authentication-Info"); //$NON-NLS-1$
        if (authInfoString == null) {
            return false;
        }

        AuthenticationInfo authInfo = null;
        try {
            authInfo = new AuthenticationInfo(authInfoString);
        } catch (ParserException e) {
            return false;
        }

        String nextNonce = authInfo.getNextNonce();
        String messageQop = authInfo.getMessageQop();
        String responseAuth = authInfo.getResponseAuth();
        String cnonce = authInfo.getCNonce();
        String nonceCount = authInfo.getNonceCount();

        URL resourceUrl = request.getResourceUrl();
        URL serverUrl = null;
        try {
            serverUrl = new URL(resourceUrl.getProtocol(), resourceUrl.getHost(), resourceUrl.getPort(), "/"); //$NON-NLS-1$
        } catch (MalformedURLException e) {
            return false;
        }

        String realm = authenticatorStore.getProtectionSpace(resourceUrl);
        if (realm == null) {
            return false;
        }

        Map info = authenticatorStore.getAuthenticationInfo(serverUrl, realm, "Digest"); //$NON-NLS-1$
        if (info == null) {
            return false;
        }

        String username = (String) info.get("username"); //$NON-NLS-1$
        String password = (String) info.get("password"); //$NON-NLS-1$
        String algorithm = (String) info.get("algorithm"); //$NON-NLS-1$
        String nonce = (String) info.get("nonce"); //$NON-NLS-1$
        String iNonceCount = (String) info.get("nc"); //$NON-NLS-1$
        String iCnonce = (String) info.get("cnonce"); //$NON-NLS-1$

        if (username == null || password == null || nonce == null) {
            return false;
        }

        if (cnonce != null && !cnonce.equals(iCnonce)) {
            return false;
        }

        if (nonceCount != null && !nonceCount.equals(iNonceCount)) {
            return false;
        }

        if (responseAuth != null) {
            try {
                String digestUri = resourceUrl.toString();
                if (proxyServerUrl == null) {
                    digestUri = resourceUrl.getFile();
                    String ref = resourceUrl.getRef();
                    if (ref != null) {
                        digestUri += "#" + ref; //$NON-NLS-1$
                    }
                }
                String iResponseAuth = response(request, realm, username, password, algorithm, messageQop, nonce, nonceCount, cnonce, request.getMethod(), digestUri);
                if (!responseAuth.equals(iResponseAuth)) {
                    return false;
                }
            } catch (Exception e) {
                return false;
            }
        }

        info.put("nonce", nextNonce); //$NON-NLS-1$

        return true;
    }

    /**
     * Returns the Digest authorization credentials for the given directives.
     * The credentials have the following form:
     *
     * credentials        = "Digest" digest-response
     * digest-response    = 1#( username | realm | nonce | digest-uri
     *                     | response | [ algorithm ] | [cnonce] |
     *                     [opaque] | [message-qop] |
     *                     [nonce-count]  | [auth-param] )
     * username            = "username" "=" username-value
     * username-value    = quoted-string
     * realm            = "realm" "=" realm-value
     * realm-value        = quoted-string
     * nonce            = "nonce" "=" nonce-value
     * nonce-value        = quoted-string
     * digest-uri        = "uri" "=" digest-uri-value
     * digest-uri-value    = request-uri   ; As specified by HTTP/1.1
     * response            = "response" "=" request-digest
     * request-digest    = <"> 32LHEX <">
     * LHEX                = "0" | "1" | "2" | "3" |
     *                       "4" | "5" | "6" | "7" |
     *                       "8" | "9" | "a" | "b" |
     *                       "c" | "d" | "e" | "f"
     * algorithm        = "algorithm" "=" ("MD5" | "MD5-sess" | token)
     * cnonce            = "cnonce" "=" cnonce-value
     * cnonce-value        = nonce-value
     * opaque            = "opaque" "=" quoted-string
     * message-qop        = "qop" "=" qop-value
     * nonce-count        = "nc" "=" nc-value
     * nc-value            = 8LHEX
     *
     *
If the "qop" value is "auth" or "auth-int":
     *
     * request-digest    = <"> < KD ( H(A1),        unq(nonce-value)
     *                                                     ":" nc-value
     *                                                     ":" unq(cnonce-value)
     *                                                     ":" unq(qop-value)
     *                                                     ":" H(A2)
     *                                         ) <">
     * KD(secret, data)    = H(concat(secret, ":", data))
     * H(data)            = MD5(data)
     * unq(data)        = unqouted(data)
     *
     *
If the "qop" directive is not present:
     *
     * request-digest    = <"> < KD ( H(A1),
     *                                                         unq(nonce-value)
     *                                                     ":" H(A2)
     *                                         ) <">
     *
     *
If the "algorithm" directive's value is "MD5" or is unspecified,
     * then A1 is:
     *
     * A1                = unq(username-value) ":" unq(realm-value) ":" passwd
     * passwd            = < user's password >
     *
     *
If the "algorithm" directive's value is "MD5-sess", then A1 is:
     *
     * A1                = H( unq(username-value) ":" unq(realm-value)
     *                             ":" passwd )
     *                             ":" unq(nonce-value) ":" unq(cnonce-value)
     *
     *
If the "qop" directive's value is "auth" or is unspecified, then
     * A2 is:
     *
     * A2                = Method ":" digest-uri-value
     *
     *
If the "qop" value is "auth-int", then A2 is:
     *
     * A2                = Method ":" digest-uri-value ":" H(entity-body)
     *
     * @param request
     * @param realm
     * @param username
     * @param password
     * @param algorithm
     * @param messageQop
     * @param nonce
     * @param nonceCount
     * @param opaque
     * @param cnonce
     * @param method
     * @param digestUri
     * @return           the Digest authorization credentials for the given
     *                   directives
     */
    private String credentials(Request request, String realm, String username, String password, String algorithm, String messageQop, String nonce, String nonceCount, String opaque, String cnonce, String method, String digestUri) throws Exception {
        Assert.isNotNull(request);
        Assert.isNotNull(realm);
        Assert.isNotNull(username);
        Assert.isNotNull(password);
        Assert.isNotNull(nonce);
        Assert.isNotNull(method);
        Assert.isNotNull(digestUri);

        StringBuffer buf = new StringBuffer();

        buf.append("Digest username=\""); //$NON-NLS-1$
        buf.append(username);
        buf.append("\""); //$NON-NLS-1$

        buf.append(", realm="); //$NON-NLS-1$
        buf.append(realm);

        if (messageQop != null) {
            buf.append(", qop=\""); //$NON-NLS-1$
            buf.append(messageQop);
            buf.append("\""); //$NON-NLS-1$
        }

        if (algorithm != null) {
            buf.append(", algorithm="); //$NON-NLS-1$
            buf.append(algorithm);
        }

        buf.append(", uri=\""); //$NON-NLS-1$
        buf.append(digestUri);
        buf.append("\""); //$NON-NLS-1$

        buf.append(", nonce="); //$NON-NLS-1$
        buf.append(nonce);

        if (nonceCount != null) {
            buf.append(", nc="); //$NON-NLS-1$
            buf.append(nonceCount);
        }

        if (cnonce != null) {
            buf.append(", cnonce=\""); //$NON-NLS-1$
            buf.append(cnonce);
            buf.append("\""); //$NON-NLS-1$
        }

        if (opaque != null) {
            buf.append(", opaque="); //$NON-NLS-1$
            buf.append(opaque);
        }

        String response = response(request, realm, username, password, algorithm, messageQop, nonce, nonceCount, cnonce, method, digestUri);
        if (response == null) {
            return null;
        }

        buf.append(", response=\""); //$NON-NLS-1$
        buf.append(response);
        buf.append("\""); //$NON-NLS-1$

        return buf.toString();
    }

    /**
     * @see Authenticator#getAuthenticationInfo(AuthenticateChallenge, Map, URL, URL)
     */
    protected Map getAuthenticationInfo(AuthenticateChallenge challenge, Map oldInfo, URL serverUrl, URL protectionSpaceUrl) {
        Assert.isNotNull(challenge);
        Assert.isNotNull(serverUrl);
        Assert.isNotNull(protectionSpaceUrl);

        Hashtable info = new Hashtable(5);

        String stale = challenge.get("stale"); //$NON-NLS-1$
        if (oldInfo == null || stale == null || !Boolean.valueOf(stale).booleanValue()) {
            Map userpass = authenticatorStore.requestAuthenticationInfo(protectionSpaceUrl, challenge.getRealm(), challenge.getAuthScheme());
            if (userpass == null) {
                return null;
            }
            info.put("username", userpass.get("username")); //$NON-NLS-1$ //$NON-NLS-2$
            info.put("password", userpass.get("password")); //$NON-NLS-1$ //$NON-NLS-2$
        } else {
            info.put("username", oldInfo.get("username")); //$NON-NLS-1$ //$NON-NLS-2$
            info.put("password", oldInfo.get("password")); //$NON-NLS-1$ //$NON-NLS-2$
        }

        String realm = challenge.getRealm();
        String domain = challenge.get("domain"); //$NON-NLS-1$

        boolean addRoot = true;
        if (domain != null && domain.charAt(0) == '"' //$NON-NLS-1$
                && domain.charAt(domain.length() - 1) == '"') { //$NON-NLS-1$
            int start = 1;
            boolean inSpace = false;
            for (int i = 1; i < domain.length(); ++i) {
                if (Character.isWhitespace(domain.charAt(i)) || i == domain.length() - 1) {
                    if (!inSpace) {
                        inSpace = true;
                        String urlString = domain.substring(start, i);
                        URL url = null;
                        try {
                            url = new URL(urlString);
                        } catch (MalformedURLException e1) {
                            try {
                                url = new URL(serverUrl, urlString);
                            } catch (MalformedURLException e2) {
                                // ignore or log?
                            }
                        }
                        if (url != null) {
                            authenticatorStore.addProtectionSpace(url, realm);
                            addRoot = false;
                        }
                    }
                } else {
                    if (inSpace) {
                        inSpace = false;
                        start = i;
                    }
                }
            }
        }

        if (addRoot) {
            authenticatorStore.addProtectionSpace(serverUrl, realm);
        }

        String nonce = challenge.get("nonce"); //$NON-NLS-1$
        if (nonce == null) {
            return null;
        }
        info.put("nonce", nonce); //$NON-NLS-1$

        String opaque = challenge.get("opaque"); //$NON-NLS-1$
        if (opaque != null) {
            info.put("opaque", opaque); //$NON-NLS-1$
        }

        String algorithm = challenge.get("algorithm"); //$NON-NLS-1$
        if (algorithm != null) {
            info.put("algorithm", algorithm); //$NON-NLS-1$
        }

        String qop = challenge.get("qop"); //$NON-NLS-1$
        if (qop != null && qop.charAt(0) == '"' //$NON-NLS-1$
                && qop.charAt(qop.length() - 1) == '"') { //$NON-NLS-1$
            boolean foundAuth = false;
            boolean foundAuthInt = false;

            try {
                String token = null;
                boolean first = true;
                Parser parser = new Parser(qop.substring(1, qop.length() - 1));
                while (parser.pos < parser.s.length()) {
                    if (first) {
                        parser.skipWhiteSpace();
                        first = false;
                    } else {
                        parser.match(',');
                        parser.skipWhiteSpace();
                    }
                    token = parser.nextToken();
                    if (token.equalsIgnoreCase("auth")) { //$NON-NLS-1$
                        foundAuth = true;
                    } else if (token.equalsIgnoreCase("auth-int")) { //$NON-NLS-1$
                        foundAuthInt = true;
                    }
                    parser.skipWhiteSpace();
                }
            } catch (ParserException e) {
                // ignore or log?
            }

            if (foundAuthInt) {
                info.put("qop", "auth-int"); //$NON-NLS-1$ //$NON-NLS-2$
            } else if (foundAuth) {
                info.put("qop", "auth"); //$NON-NLS-1$ //$NON-NLS-2$
            }
        }

        return info;
    }

    /**
     * @see Authenticator#getAuthorization(Request, Map, URL, URL, URL)
     */
    protected String getAuthorization(Request request, Map info, URL serverUrl, URL protectionSpaceUrl, URL proxyServerUrl) {
        Assert.isNotNull(request);
        Assert.isNotNull(info);
        Assert.isNotNull(serverUrl);
        Assert.isNotNull(protectionSpaceUrl);

        String username = (String) info.get("username"); //$NON-NLS-1$
        String password = (String) info.get("password"); //$NON-NLS-1$
        String algorithm = (String) info.get("algorithm"); //$NON-NLS-1$
        String messageQop = (String) info.get("qop"); //$NON-NLS-1$
        String nonce = (String) info.get("nonce"); //$NON-NLS-1$
        String nonceCount = (String) info.get("nc"); //$NON-NLS-1$
        String opaque = (String) info.get("opaque"); //$NON-NLS-1$
        String cnonce = null;

        if (username == null || password == null || nonce == null) {
            return null;
        }

        if (messageQop != null) {
            if (nonceCount == null) {
                nonceCount = "00000001"; //$NON-NLS-1$
            } else {
                int nc = Integer.parseInt(nonceCount, 16) + 1;
                nonceCount = HexConverter.toHex(new int[] {nc});
            }
            info.put("nc", nonceCount); //$NON-NLS-1$

            long milliseconds = new Date().getTime();
            SecureRandom random = new SecureRandom();
            random.setSeed(milliseconds);
            byte[] bytes = new byte[16];
            random.nextBytes(bytes);
            cnonce = HexConverter.toHex(bytes);
            info.put("cnonce", cnonce); //$NON-NLS-1$
        }

        String realm = authenticatorStore.getProtectionSpace(protectionSpaceUrl);
        if (realm == null) {
            return null;
        }

        String method = request.getMethod();
        URL resourceUrl = request.getResourceUrl();
        String digestUri = resourceUrl.toString();
        if (proxyServerUrl != null) {
            digestUri = resourceUrl.getFile();
            String ref = resourceUrl.getRef();
            if (ref != null) {
                digestUri += "#" + ref; //$NON-NLS-1$
            }
        }

        try {
            return credentials(request, realm, username, password, algorithm, messageQop, nonce, nonceCount, opaque, cnonce, method, digestUri);
        } catch (Exception e) {
            return null;
        }
    }

    private String ha1(String realm, String username, String password, String algorithm, String nonce, String cnonce) throws Exception {
        Assert.isNotNull(realm);
        Assert.isNotNull(username);
        Assert.isNotNull(password);
        Assert.isNotNull(nonce);

        String ha1 = md5(unquote(username) + ":" + unquote(realm) + ":" + password); //$NON-NLS-1$ //$NON-NLS-2$
        if (algorithm != null && !algorithm.equalsIgnoreCase("MD5")) { //$NON-NLS-1$
            if (algorithm.equalsIgnoreCase("MD5-sess")) { //$NON-NLS-1$
                if (cnonce == null) {
                    return null;
                }
                ha1 = md5(ha1 + ":" + unquote(nonce) + ":" + unquote(cnonce)); //$NON-NLS-1$ //$NON-NLS-2$
            } else {
                throw new Exception(Policy.bind("exception.unregognizedAlgo", algorithm)); //$NON-NLS-1$
            }
        }

        return ha1;
    }

    private String ha2(Request request, String qop, String method, String digestUri) throws Exception {
        Assert.isNotNull(request);
        Assert.isNotNull(method);
        Assert.isNotNull(digestUri);

        String a2 = null;
        if (qop == null || qop.equalsIgnoreCase("auth")) { //$NON-NLS-1$
            a2 = md5((method == null ? "" : method) + ":" + digestUri); //$NON-NLS-1$ //$NON-NLS-2$
        } else if (qop.equalsIgnoreCase("auth-int")) { //$NON-NLS-1$
            a2 = md5((method == null ? "" : method) + ":" + digestUri + md5(request)); //$NON-NLS-1$ //$NON-NLS-2$
        } else {
            throw new Exception(Policy.bind("exception.unregognizedQop", qop)); //$NON-NLS-1$
        }

        return a2;
    }

    private String response(Request request, String realm, String username, String password, String algorithm, String qop, String nonce, String nonceCount, String cnonce, String method, String digestUri) throws Exception {
        Assert.isNotNull(request);
        Assert.isNotNull(realm);
        Assert.isNotNull(username);
        Assert.isNotNull(password);
        Assert.isNotNull(nonce);
        Assert.isNotNull(method);
        Assert.isNotNull(digestUri);

        String ha1 = ha1(realm, username, password, algorithm, nonce, cnonce);
        if (ha1 == null) {
            return null;
        }

        String ha2 = ha2(request, qop, method, digestUri);
        if (ha2 == null) {
            return null;
        }

        if (qop == null) {
            return md5(ha1 + ":" + unquote(nonce) + ":" + ha2); //$NON-NLS-1$ //$NON-NLS-2$
        }

        if (nonceCount == null || cnonce == null || qop == null) {
            return null;
        }

        return md5(ha1 + ":" //$NON-NLS-1$
                + unquote(nonce) + ":" //$NON-NLS-1$
                + nonceCount + ":" //$NON-NLS-1$
                + unquote(cnonce) + ":" //$NON-NLS-1$
                + unquote(qop) + ":" //$NON-NLS-1$
                + ha2);
    }
}


/*
 * 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.rete;

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

import org.drools.eclipse.reteoo.BaseVertex;

/**
 * Holder for Row elements.
 */
public class RowList {

    // List<Row>
    private List<Row> rows;

    /**
     * Default constructor.
     */
    public RowList() {
        super();
        this.rows = new ArrayList<Row>();
    }

    /**
     * Adds new vertex to specified depth
     *
     * @param depth depth for vertex
     * @param vertex vertex
     */
    public void add(final int depth,
                    final BaseVertex vertex) {
        if ( this.rows.size() < (depth + 1) ) {
            final int addRows = depth - this.rows.size() + 1;

            for ( int i = 0; i < addRows; ++i ) {
                this.rows.add( new Row( (depth - addRows) + i ) );
            }
        }

        ((Row) this.rows.get( depth )).add( vertex );
    }

    /**
     * @return number of rows in RowList
     */
    public int getDepth() {
        return this.rows.size();
    }

    /**
     * @param row index of the row to be returned (0..n-1)
     * @return specified row
     */
    public Row get(final int row) {
        return (Row) this.rows.get( row );
    }

    /**
     * Finds specified vertex from the rows.
     *
     * @param vertex vertex
     *
     * @return row number where vertex was found (0..n-1). <code>-1</code> if not found.
     */
    public int getRow(final BaseVertex vertex) {
        final int numRows = this.rows.size();

        for ( int i = 0; i < numRows; ++i ) {
            if ( ((Row) this.rows.get( i )).contains( vertex ) ) {
                return i;
            }
        }

        return -1;
    }

    /**
     * Finds the longest row width.
     *
     * @return width of the longest row
     */
    public int getWidth() {
        int width = 0;

        for ( final Iterator<Row> rowIter = this.rows.iterator(); rowIter.hasNext(); ) {
            final Row row = rowIter.next();
            final int rowWidth = row.getWidth();

            if ( rowWidth > width ) {
                width = rowWidth;
            }
        }

        return width;
    }

    /**
     * Width of the row at specified index.
     *
     * @param row
     * @return width
     */
    public int getWidth(final int row) {
        return ((Row) this.rows.get( row )).getWidth();
    }

    /**
     * @param vertex vertex to search
     * @return column where vertex was found
     */
    public int getColumn(final BaseVertex vertex) {
        final int row = getRow( vertex );

        if ( row < 0 ) {
            return -1;
        }

        final List<BaseVertex> rowVertices = get( row ).getVertices();

        final int numCols = rowVertices.size();

        for ( int i = 0; i < numCols; ++i ) {
            if ( rowVertices.get( i ).equals( vertex ) ) {
                return i;
            }
        }

        return -1;
    }

    /**
     * Dumps all row vertices to System.err
     */
    public void dump() {
        final int numRows = this.rows.size();

        for ( int i = 0; i < numRows; ++i ) {
            System.err.println( i + ": " + get( i ).getVertices() );
        }
    }

    /**
     * Optimizes all rows for optimal presentation
     */
    public void optimize() {
        final int numRows = this.rows.size();

        for ( int i = 0; i < numRows; ++i ) {
            get( i ).optimize();
        }
    }
}


/*
 * 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.refactoring;

import java.lang.reflect.Field;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jdt.internal.core.SourceField;
import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup;
import org.eclipse.jdt.internal.corext.refactoring.rename.JavaRenameProcessor;
import org.eclipse.jdt.internal.corext.refactoring.rename.RenameFieldProcessor;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.TextFileChange;
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
import org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor;
import org.eclipse.ltk.core.refactoring.participants.RenameParticipant;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
import org.kie.eclipse.utils.FileUtils;

/**
 * Participant to generate refactoring when a field is renamed.
 * This isn't executed by the RefactoringProcessor when a field is refactored with
 * the rename hotkey into the editor. Only is called when the Rename field dialog is used.
 */
@SuppressWarnings("restriction")
public class RuleSourceFieldRenameParticipant extends RenameParticipant {

    public static final String NAME = "Rule Source Field Rename Refactoring";

    private static final String FIELD_NAME = "(?<=[!\\(:\\s])FIELD_NAME(?=[\\s=\\),\\.<>!])";
    private static final String VARIABLE_ASSIGNED = "[\\w]*(?=\\s*:\\s*TYPE\\s*\\()";
    private static final String GETTER_NAME = "(?<=VARIABLE_NAME\\.)CURRENT_GETTER_NAME(?=\\s*\\()";
    private static final String SETTER_NAME = "(?<=VARIABLE_NAME\\.)CURRENT_SETTER_NAME(?=\\s*\\()";

    private DRLProjectDetector drlProjectDetector = new DRLProjectDetector();

    private RefactoringProcessor processor;
    private List<IFile> drlFiles;
    private SourceField sourceField;
    private String newName;
    private String currentName;

    @Override
    public RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context) throws OperationCanceledException {
        RefactoringStatus status = new RefactoringStatus();
        try {
            IFile file = getSourceFieldIFile();
            if (file==null || file.isReadOnly())
                return status;
            drlFiles = drlProjectDetector.detect(file.getProject());
            String content = null;
            // if at least one file have a reference to the renamed field => apply refactoring
            for (IFile drlFile : drlFiles) {

                if ((content = FileUtils.readFile(drlFile))==null)
                    return null;

                Pattern pattern = Pattern.compile("(?<=:\\s)" + currentName + "|" + currentName + "(?=\\s=)");
                Matcher matcher = pattern.matcher(content);

                if (matcher.find()) {
                    RenameFieldProcessor renameFieldProcessor = (RenameFieldProcessor)processor;
                    if (!renameFieldProcessor.getRenameGetter())
                        status.addInfo("The getter must be also updated to refactor the DRL files.");
                    return status;
                }

            }
        } catch (CoreException e) {
            throw new OperationCanceledException(e.getMessage());
        }
        return status;
    }

    @Override
    public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
        CompositeChange changes = null;
        String content;
        changes = new CompositeChange("Fix " + currentName + " field on DRL files");
        IFile file = getSourceFieldIFile();
        String typeName = sourceField.getParent().getElementName();

        Pattern fieldPattern = Pattern.compile(FIELD_NAME.replaceAll("FIELD_NAME", currentName));
        Pattern typePattern = Pattern.compile(VARIABLE_ASSIGNED.replace("TYPE", typeName));

        if (file!=null) {
            RenameFieldProcessor renameFieldProcessor = (RenameFieldProcessor)processor;
            for (IFile drlFile : drlFiles) {

                if ((content = FileUtils.readFile(drlFile))==null)
                    return null;

                TextFileChange change = new TextFileChange(drlFile.getName(), drlFile);
                MultiTextEdit mte = new MultiTextEdit();
                change.setEdit(mte);

                // rename the field name
                Matcher matcher = fieldPattern.matcher(content);
                while (matcher.find()) {
                	if (isFieldInRightType(content, typeName, matcher.start())) {
                		ReplaceEdit replace = new ReplaceEdit(matcher.start(), currentName.length(), newName);
                		mte.addChild(replace);
                	}
                }

                // search all the variables of the type to replace the getters/setters
                matcher = typePattern.matcher(content);
                while (matcher.find()) {
                    if (matcher.group().length() > 0) {
                        String variableNameAssigned = matcher.group();
                        if (renameFieldProcessor.getRenameGetter()) {
                            String newGetterName = renameFieldProcessor.getNewGetterName();
                            String currentGetterName = renameFieldProcessor.getGetter().getElementName();
                            String regexp = GETTER_NAME.replace("VARIABLE_NAME", variableNameAssigned).replace("CURRENT_GETTER_NAME", currentGetterName);
                            createFieldRenameChanges(mte, content, regexp, currentGetterName, newGetterName);
                        }
                        if (renameFieldProcessor.getRenameSetter()) {
                            String newSetterName = renameFieldProcessor.getNewSetterName();
                            String currentSetterName = renameFieldProcessor.getSetter().getElementName();
                            String regexp = SETTER_NAME.replace("VARIABLE_NAME", variableNameAssigned).replace("CURRENT_SETTER_NAME", currentSetterName);
                            createFieldRenameChanges(mte, content, regexp, currentSetterName, newSetterName);
                        }
                    }
                }

                if (change.getEdit().getChildrenSize() > 0)
                    changes.add(change);

            }
        }
        return (changes.getChildren().length > 0)?changes:null;
    }

    private boolean isFieldInRightType(String content, String typeName, int offset) {
    	int lastTypeOccurence = content.lastIndexOf(typeName, offset);
    	if (lastTypeOccurence < 0) {
    		return false;
    	}

    	int typeConstraintsStart = content.indexOf('(', lastTypeOccurence);
    	if (typeConstraintsStart < 0 || typeConstraintsStart > offset) {
    		return false;
    	}

    	String s = content.substring(lastTypeOccurence, typeConstraintsStart);
    	if (s.indexOf("global") >= 0 || s.indexOf("function") >= 0) {
    		return false;
    	}

    	int parenthesisCounter = 1;
    	int typeConstraintsEnd = typeConstraintsStart+1;
    	while (parenthesisCounter != 0 && typeConstraintsEnd < content.length()) {
    		if (content.charAt(typeConstraintsEnd) == '(') {
    			parenthesisCounter++;
    		} else if (content.charAt(typeConstraintsEnd) == ')') {
    			parenthesisCounter--;
    		}
    		typeConstraintsEnd++;
    	}

    	return typeConstraintsEnd < content.length() && typeConstraintsEnd > offset;
    }

    private void createFieldRenameChanges(MultiTextEdit mte, String content, String regexp, String currentName, String newName) {
        Pattern pattern = Pattern.compile(regexp);
        Matcher setterMatcher = pattern.matcher(content);
        ReplaceEdit replace = null;
        while (setterMatcher.find()) {
            replace = new ReplaceEdit(setterMatcher.start(), currentName.length(), newName);
            mte.addChild(replace);
        }
    }

    @Override
    public String getName() {
        return NAME;
    }

    // TODO: Search the Native way to find the SourceField IFile
    private IFile getSourceFieldIFile() {
        Field fReferences;
        try {
            fReferences = processor.getClass().getDeclaredField("fReferences");
            fReferences.setAccessible(true);
            SearchResultGroup object[] = (SearchResultGroup[]) fReferences.get(processor);
            for (SearchResultGroup searchResultGroup : object) {
                if (searchResultGroup.getResource() instanceof IFile)
                    return (IFile) searchResultGroup.getResource();
            }
        } catch (SecurityException e) {
            return null;
        } catch (NoSuchFieldException e) {
            return null;
        } catch (IllegalArgumentException e) {
            return null;
        } catch (IllegalAccessException e) {
            return null;
        }
        return null;
    }

    @Override
    protected boolean initialize(Object element) {
        if (element instanceof SourceField) {
            this.sourceField = (SourceField) element;
            this.processor = getProcessor();
            if (this.processor instanceof JavaRenameProcessor) {
                newName = ((JavaRenameProcessor)processor).getNewElementName();
                currentName = ((JavaRenameProcessor)processor).getCurrentElementName();
                return true;
            }
        }
        return false;
    }
}


/*
 * 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.rete;

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

import org.drools.core.RuleBaseConfiguration;
import org.drools.core.definitions.InternalKnowledgePackage;
import org.drools.core.impl.InternalKnowledgeBase;
import org.drools.eclipse.DRLInfo;
import org.drools.eclipse.DroolsEclipsePlugin;
import org.drools.eclipse.builder.DroolsBuilder;
import org.drools.eclipse.editors.DRLRuleEditor;
import org.drools.eclipse.editors.rete.model.ReteGraph;
import org.drools.eclipse.editors.rete.part.VertexEditPartFactory;
import org.drools.eclipse.util.ProjectClassLoader;
import org.drools.eclipse.reteoo.BaseVertex;
import org.drools.eclipse.reteoo.ReteooVisitor;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.ConnectionLayer;
import org.eclipse.draw2d.ConnectionRouter;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.ShortestPathConnectionRouter;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.gef.DefaultEditDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.LayerConstants;
import org.eclipse.gef.MouseWheelHandler;
import org.eclipse.gef.MouseWheelZoomHandler;
import org.eclipse.gef.editparts.LayerManager;
import org.eclipse.gef.editparts.ScalableFreeformRootEditPart;
import org.eclipse.gef.editparts.ZoomManager;
import org.eclipse.gef.ui.parts.GraphicalEditor;
import org.eclipse.gef.ui.parts.GraphicalViewerKeyHandler;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.swt.SWT;
import org.drools.core.impl.KnowledgeBaseFactory;

/**
 * GEF-based RETE Viewer
 */
public class ReteViewer extends GraphicalEditor {

    public static final String  MSG_PARSE_ERROR         = "Unable to parse rules to show RETE view!";

    private static final int     SIMPLE_ROUTER_MIN_NODES = 100;

    ScalableFreeformRootEditPart rootEditPart            = new ScalableFreeformRootEditPart();

    private ReteGraph            diagram                 = new ReteGraph();

    private boolean              relayoutRequired        = true;

    private DRLRuleEditor drlEditor;

    /**
     * Constructor.
     *
     * @param documentProvider documentProvider must contain Document with rules.
     */
    public ReteViewer(DRLRuleEditor drlEditor) {
        this.drlEditor = drlEditor;
        setEditDomain( new DefaultEditDomain( this ) );
    }

    /* (non-Javadoc)
     * @see org.eclipse.gef.ui.parts.GraphicalEditor#configureGraphicalViewer()
     */
    protected void configureGraphicalViewer() {
        super.configureGraphicalViewer();
        GraphicalViewer viewer = getGraphicalViewer();
        viewer.getControl().setBackground( ColorConstants.white );
        viewer.setEditPartFactory( new VertexEditPartFactory() );
        viewer.setRootEditPart( rootEditPart );
        viewer.setKeyHandler( new GraphicalViewerKeyHandler( viewer ) );
    }

    /* (non-Javadoc)
     * @see org.eclipse.gef.ui.parts.GraphicalEditor#getAdapter(java.lang.Class)
     */
    public Object getAdapter(@SuppressWarnings("rawtypes") Class type) {

        if ( type == ZoomManager.class ) return ((ScalableFreeformRootEditPart) getGraphicalViewer().getRootEditPart()).getZoomManager();
        if ( type == GraphicalViewer.class ) return getGraphicalViewer();
        if ( type == EditPart.class && getGraphicalViewer() != null ) return getGraphicalViewer().getRootEditPart();
        if ( type == IFigure.class && getGraphicalViewer() != null ) return ((GraphicalEditPart) getGraphicalViewer().getRootEditPart()).getFigure();
        return super.getAdapter( type );
    }

    /**
     * Loads model from rule base,
     * calculates rete view and initializes diagram model.
     * @param monitor
     * @param contents
     * @return
     */
    public ReteGraph loadReteModel(IProgressMonitor monitor,
                                   String contents) throws Throwable {
        if ( relayoutRequired == false ) {
            return diagram;
        }

        ReteGraph newDiagram = new ReteGraph();

        try {

            monitor.beginTask( "Loading RETE Tree",
                               100 );

            monitor.subTask( "Loading Rule Base" );
            InternalKnowledgeBase ruleBase = null;
            try {
                IResource resource = drlEditor.getResource();
                ClassLoader newLoader = DroolsBuilder.class.getClassLoader();
                if ( resource.getProject().getNature( "org.eclipse.jdt.core.javanature" ) != null ) {
                    IJavaProject project = JavaCore.create( resource.getProject() );
                    newLoader = ProjectClassLoader.getProjectClassLoader( project );
                }
                DRLInfo drlInfo = DroolsEclipsePlugin.getDefault().parseResource(drlEditor, true, true);
                if (drlInfo == null) {
                    throw new Exception( "Could not find DRL info" );
                }
                if (drlInfo.getBuilderErrors().length > 0) {
                    throw new Exception( drlInfo.getBuilderErrors().length + " build errors" );
                }
                if (drlInfo.getParserErrors().size() > 0) {
                    throw new Exception( drlInfo.getParserErrors().size() + " parser errors" );
                }

                InternalKnowledgePackage pkg = drlInfo.getPackage();
                RuleBaseConfiguration config = new RuleBaseConfiguration();
                config.setClassLoader(newLoader);
                ruleBase = KnowledgeBaseFactory.newKnowledgeBase(config);
                if (pkg != null) {
                    ruleBase.addPackage(pkg);
                }
            } catch ( Throwable t ) {
                DroolsEclipsePlugin.log( t );
                throw new Exception( MSG_PARSE_ERROR + " " + t.getMessage());
            }

            monitor.worked( 50 );
            if ( monitor.isCanceled() ) {
                throw new InterruptedException();
            }

            monitor.subTask( "Building RETE Tree" );
            final ReteooVisitor visitor = new ReteooVisitor( newDiagram );
            visitor.visitInternalKnowledgeBase( ruleBase );
            monitor.worked( 30 );
            if ( monitor.isCanceled() ) {
                throw new InterruptedException();
            }

            monitor.subTask( "Calculating RETE Tree Layout" );
            BaseVertex rootVertex = visitor.getRootVertex();
            RowList rowList = ReteooLayoutFactory.calculateReteRows( rootVertex );
            ReteooLayoutFactory.layoutRowList( newDiagram,
                                               rowList );
            zeroBaseDiagram( newDiagram );
            monitor.worked( 20 );
            if ( monitor.isCanceled() ) {
                throw new InterruptedException();
            }
            monitor.done();

        } catch ( Throwable t ) {
            if ( !(t instanceof InterruptedException) ) {
                DroolsEclipsePlugin.log( t );
            }
            throw t;
        }
        relayoutRequired = false;
        return newDiagram;
    }

    private ReteGraph getModel() {
        return diagram;
    }

    /**
     * Loads Rete model and initializes zoom manager.
     */
    protected void initializeGraphicalViewer() {
        ZoomManager zoomManager = rootEditPart.getZoomManager();

        //List<String>
        List<String> zoomLevels = new ArrayList<String>(3);

        zoomLevels.add( ZoomManager.FIT_ALL );
        zoomLevels.add( ZoomManager.FIT_HEIGHT );
        zoomLevels.add( ZoomManager.FIT_WIDTH );

        zoomManager.setZoomLevelContributions( zoomLevels );

        // Zoom mousewheel - Ctrl+Mousewheel for zoom in/out
        getGraphicalViewer().setProperty( MouseWheelHandler.KeyGenerator.getKey( SWT.MOD1 ),
                                          MouseWheelZoomHandler.SINGLETON );

    }

    /**
     * Moves all diagram nodes to upper left corner
     * and shifting to right if neccessary to get rid of negative XY coordinates.
     */
    private void zeroBaseDiagram(ReteGraph graph) {

        Dimension dim = rootEditPart.getContentPane().getSize();

        int minx = 0, miny = 0, maxx = 0, x = dim.width;

        final Iterator<BaseVertex> nodeIter = graph.getChildren().iterator();
        while ( nodeIter.hasNext() ) {
            Point loc = nodeIter.next().getLocation();
            minx = Math.min( loc.x,
                             minx );
            maxx = Math.max( loc.x,
                             maxx );
            miny = Math.min( loc.y,
                             miny );
        }

        int delta = (x - (maxx - minx + 20)) / 2;
        minx = minx - (delta);

        final Iterator<BaseVertex> nodeIter2 = graph.getChildren().iterator();
        while ( nodeIter2.hasNext() ) {
            final BaseVertex vertex = nodeIter2.next();
            Point loc = vertex.getLocation();
            vertex.setLocation( new Point( loc.x - minx,
                                           loc.y - miny ) );
        }
    }

    /**
     * No save operation in ReteViewer
     */
    public void doSave(IProgressMonitor monitor) {

    }

    /**
     * ReteViewer is never dirty.
     * This prevents editor close mechanism to ask file save confirmation
     * even after one of the vertices is moved.
     */
    public boolean isDirty() {
        return false;
    }

    /**
     * Fired when underlying source is modified.
     * Marks graph viewer to be relayouted when activated.
     */
    public void fireDocumentChanged() {
        relayoutRequired = true;
    }

    /**
     * Draws graph.
     *
     * @param newGraph used to replace existing graph. if null then existing graph is simply redrawn.
     */
    public void drawGraph(ReteGraph newGraph) {

        LayerManager manager = (LayerManager) getGraphicalViewer().getEditPartRegistry().get( LayerManager.ID );
        ConnectionLayer connLayer = (ConnectionLayer) manager.getLayer( LayerConstants.CONNECTION_LAYER );

        // Lazy-init model initialization
        if ( getGraphicalViewer().getContents() == null ) {
            getGraphicalViewer().setContents( getModel() );
        }

        final boolean isNewDiagram = newGraph != null && newGraph != diagram;

        if ( isNewDiagram ) {
            diagram.removeAll();
        }

        // Update connection router according to new model size
        ConnectionRouter router;
        if ( (isNewDiagram && newGraph.getChildren().size() < SIMPLE_ROUTER_MIN_NODES) || (!isNewDiagram && getModel().getChildren().size() < SIMPLE_ROUTER_MIN_NODES) ) {
            router = new ShortestPathConnectionRouter( (IFigure) rootEditPart.getContentPane().getChildren().get( 0 ) );
        } else {
            router = ConnectionRouter.NULL;
        }
        connLayer.setConnectionRouter( router );

        if ( newGraph != null && newGraph != diagram ) {
            diagram.addAll( newGraph.getChildren() );
        }

    }

}