/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you under the Apache License, Version 2.0 (the
 *  "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 *  
 *    http://www.apache.org/licenses/LICENSE-2.0
 *  
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License. 
 *  
 */

package org.apache.directory.studio.ldapbrowser.common.filtereditor;


import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.directory.api.ldap.model.constants.SchemaConstants;
import org.apache.directory.api.ldap.model.schema.AttributeType;
import org.apache.directory.api.ldap.model.schema.MatchingRule;
import org.apache.directory.api.ldap.model.schema.ObjectClass;
import org.apache.directory.studio.ldapbrowser.common.BrowserCommonActivator;
import org.apache.directory.studio.ldapbrowser.common.BrowserCommonConstants;
import org.apache.directory.studio.ldapbrowser.core.model.filter.LdapFilter;
import org.apache.directory.studio.ldapbrowser.core.model.filter.LdapFilterExtensibleComponent;
import org.apache.directory.studio.ldapbrowser.core.model.filter.LdapFilterItemComponent;
import org.apache.directory.studio.ldapbrowser.core.model.filter.parser.LdapFilterParser;
import org.apache.directory.studio.ldapbrowser.core.model.filter.parser.LdapFilterToken;
import org.apache.directory.studio.ldapbrowser.core.model.schema.Schema;
import org.apache.directory.studio.ldapbrowser.core.model.schema.SchemaUtils;
import org.eclipse.jface.fieldassist.IContentProposal;
import org.eclipse.jface.fieldassist.IContentProposalProvider;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.contentassist.CompletionProposal;
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.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.templates.Template;
import org.eclipse.jface.text.templates.TemplateCompletionProcessor;
import org.eclipse.jface.text.templates.TemplateContextType;
import org.eclipse.swt.graphics.Image;


/**
 * The FilterContentAssistProcessor computes the content proposals for the filter editor.
 *
 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
 */
public class FilterContentAssistProcessor extends TemplateCompletionProcessor implements IContentAssistProcessor,
    IContentProposalProvider
{

    private static final Comparator<String> NAME_AND_OID_COMPARATOR = new Comparator<String>()
    {
        public int compare( String s1, String s2 )
        {
            if ( s1.matches( "[0-9\\.]+" ) && !s2.matches( "[0-9\\.]+" ) ) //$NON-NLS-1$ //$NON-NLS-2$
            {
                return 1;
            }
            else if ( !s1.matches( "[0-9\\.]+" ) && s2.matches( "[0-9\\.]+" ) ) //$NON-NLS-1$ //$NON-NLS-2$
            {
                return -1;
            }
            else
            {
                return s1.compareToIgnoreCase( s2 );
            }
        }
    };

    /** The parser. */
    private LdapFilterParser parser;

    /** The source viewer, may be null. */
    private ISourceViewer sourceViewer;

    /** The auto activation characters. */
    private char[] autoActivationCharacters;

    /** The schema, used to retrieve attributeType and objectClass information. */
    private Schema schema;

    /** The possible attribute types. */
    private Map<String, AttributeType> possibleAttributeTypes;

    /** The possible filter types. */
    private Map<String, String> possibleFilterTypes;

    /** The possible object classes. */
    private Map<String, ObjectClass> possibleObjectClasses;

    /** The possible matching rules. */
    private Map<String, MatchingRule> possibleMatchingRules;


    /**
     * Creates a new instance of FilterContentAssistProcessor.
     * 
     * @param parser the parser
     */
    public FilterContentAssistProcessor( LdapFilterParser parser )
    {
        this( null, parser );
    }


    /**
     * Creates a new instance of FilterContentAssistProcessor.
     * 
     * @param sourceViewer the source viewer
     * @param parser the parser
     */
    public FilterContentAssistProcessor( ISourceViewer sourceViewer, LdapFilterParser parser )
    {
        this.parser = parser;
        this.sourceViewer = sourceViewer;

        this.autoActivationCharacters = new char[7 + 10 + 26 + 26];
        this.autoActivationCharacters[0] = '(';
        this.autoActivationCharacters[1] = ')';
        this.autoActivationCharacters[2] = '&';
        this.autoActivationCharacters[3] = '|';
        this.autoActivationCharacters[4] = '!';
        this.autoActivationCharacters[5] = ':';
        this.autoActivationCharacters[6] = '.';
        int i = 7;
        for ( char c = 'a'; c <= 'z'; c++, i++ )
        {
            this.autoActivationCharacters[i] = c;
        }
        for ( char c = 'A'; c <= 'Z'; c++, i++ )
        {
            this.autoActivationCharacters[i] = c;
        }
        for ( char c = '0'; c <= '9'; c++, i++ )
        {
            this.autoActivationCharacters[i] = c;
        }
    }


    /**
     * Sets the schema, used to retrieve attributeType and objectClass information.
     * 
     * @param schema the schema
     */
    public void setSchema( Schema schema )
    {
        this.schema = schema;

        possibleAttributeTypes = new TreeMap<String, AttributeType>( NAME_AND_OID_COMPARATOR );
        possibleFilterTypes = new LinkedHashMap<String, String>();
        possibleObjectClasses = new TreeMap<String, ObjectClass>( NAME_AND_OID_COMPARATOR );
        possibleMatchingRules = new TreeMap<String, MatchingRule>( NAME_AND_OID_COMPARATOR );

        if ( schema != null )
        {
            Collection<AttributeType> attributeTypeDescriptions = schema.getAttributeTypeDescriptions();
            for ( AttributeType atd : attributeTypeDescriptions )
            {
                possibleAttributeTypes.put( atd.getOid(), atd );
                for ( String atdName : atd.getNames() )
                {
                    possibleAttributeTypes.put( atdName, atd );
                }
            }

            possibleFilterTypes.put( "=", Messages.getString( "FilterContentAssistProcessor.Equals" ) ); //$NON-NLS-1$ //$NON-NLS-2$
            possibleFilterTypes.put( "=*", Messages.getString( "FilterContentAssistProcessor.Present" ) ); //$NON-NLS-1$ //$NON-NLS-2$
            possibleFilterTypes.put( "<=", Messages.getString( "FilterContentAssistProcessor.LessThanOrEquals" ) ); //$NON-NLS-1$ //$NON-NLS-2$
            possibleFilterTypes.put( ">=", Messages.getString( "FilterContentAssistProcessor.GreaterThanOrEquals" ) ); //$NON-NLS-1$ //$NON-NLS-2$
            possibleFilterTypes.put( "~=", Messages.getString( "FilterContentAssistProcessor.Approximately" ) ); //$NON-NLS-1$ //$NON-NLS-2$

            Collection<ObjectClass> ocds = schema.getObjectClassDescriptions();
            for ( ObjectClass ocd : ocds )
            {
                possibleObjectClasses.put( ocd.getOid(), ocd );
                for ( String name : ocd.getNames() )
                {
                    possibleObjectClasses.put( name, ocd );
                }
            }

            Collection<MatchingRule> matchingRuleDescriptions = schema.getMatchingRuleDescriptions();
            for ( MatchingRule description : matchingRuleDescriptions )
            {
                possibleMatchingRules.put( description.getOid(), description );
                for ( String name : description.getNames() )
                {
                    possibleMatchingRules.put( name, description );
                }
            }
        }
    }


    /**
     * @see org.eclipse.jface.text.templates.TemplateCompletionProcessor#getCompletionProposalAutoActivationCharacters()
     */
    public char[] getCompletionProposalAutoActivationCharacters()
    {
        return autoActivationCharacters;
    }


    /**
     * @see org.eclipse.jface.text.templates.TemplateCompletionProcessor#computeCompletionProposals(org.eclipse.jface.text.ITextViewer, int)
     */
    public ICompletionProposal[] computeCompletionProposals( ITextViewer viewer, int offset )
    {
        return computeCompletionProposals( offset );
    }


    /**
     * @see org.eclipse.jface.fieldassist.IContentProposalProvider#getProposals(java.lang.String, int)
     */
    public IContentProposal[] getProposals( final String contents, final int position )
    {
        parser.parse( contents );

        ICompletionProposal[] oldProposals = computeCompletionProposals( position );
        IContentProposal[] proposals = new IContentProposal[oldProposals.length];
        for ( int i = 0; i < oldProposals.length; i++ )
        {
            final ICompletionProposal oldProposal = oldProposals[i];
            final Document document = new Document( contents );
            oldProposal.apply( document );

            proposals[i] = new IContentProposal()
            {
                public String getContent()
                {
                    return document.get();
                }


                public int getCursorPosition()
                {
                    return oldProposal.getSelection( document ).x;
                }


                public String getDescription()
                {
                    return oldProposal.getAdditionalProposalInfo();
                }


                public String getLabel()
                {
                    return oldProposal.getDisplayString();
                }


                public String toString()
                {
                    return getContent();
                }
            };
        }

        return proposals;
    }


    /**
     * Computes completion proposals.
     * 
     * @param offset the offset
     * 
     * @return the matching completion proposals
     */
    private ICompletionProposal[] computeCompletionProposals( int offset )
    {
        String[] possibleObjectClasses = schema == null ? new String[0] : SchemaUtils.getNamesAsArray( schema
            .getObjectClassDescriptions() );
        Arrays.sort( possibleObjectClasses );

        List<ICompletionProposal> proposalList = new ArrayList<ICompletionProposal>();
        LdapFilter filter = parser.getModel().getFilter( offset );
        if ( filter != null && offset > 0 )
        {
            // case 0: open curly started, show templates and all attribute types
            if ( filter.getStartToken() != null && filter.getFilterComponent() == null )
            {
                if ( sourceViewer != null )
                {
                    ICompletionProposal[] templateProposals = super.computeCompletionProposals( sourceViewer, offset );
                    if ( templateProposals != null )
                    {
                        proposalList.addAll( Arrays.asList( templateProposals ) );
                    }
                }
                addPossibleAttributeTypes( proposalList, "", offset ); //$NON-NLS-1$
            }

            // case A: simple filter
            if ( filter.getFilterComponent() instanceof LdapFilterItemComponent )
            {
                LdapFilterItemComponent fc = ( LdapFilterItemComponent ) filter.getFilterComponent();

                // case A1: editing attribute type: show matching attribute types
                if ( fc.getStartToken().getOffset() <= offset
                    && offset <= fc.getStartToken().getOffset() + fc.getStartToken().getLength() )
                {
                    addPossibleAttributeTypes( proposalList, fc.getAttributeToken().getValue(), fc.getAttributeToken()
                        .getOffset() );
                }

                String attributeType = null;
                if ( schema != null && schema.hasAttributeTypeDescription( fc.getAttributeToken().getValue() ) )
                {
                    attributeType = fc.getAttributeToken().getValue();
                }

                // case A2: after attribte type: show possible filter types and extensible match options
                if ( attributeType != null )
                {
                    if ( ( fc.getAttributeToken().getOffset() <= offset || fc.getFilterToken() != null )
                        && offset <= fc.getAttributeToken().getOffset() + fc.getAttributeToken().getLength()
                            + ( fc.getFilterToken() != null ? fc.getFilterToken().getLength() : 0 ) )
                    {
                        //String attributeType = fc.getAttributeToken().getValue();
                        String filterType = fc.getFilterToken() != null ? fc.getFilterToken().getValue() : ""; //$NON-NLS-1$
                        int filterTypeOffset = fc.getAttributeToken().getOffset() + fc.getAttributeToken().getLength();
                        addPossibleFilterTypes( proposalList, attributeType, filterType, filterTypeOffset );
                    }
                }

                // case A3: editing objectClass attribute: show matching object classes
                if ( attributeType != null && SchemaConstants.OBJECT_CLASS_AT.equalsIgnoreCase( attributeType ) )
                {
                    if ( ( fc.getValueToken() != null && fc.getValueToken().getOffset() <= offset || fc
                        .getFilterToken() != null )
                        && offset <= fc.getAttributeToken().getOffset() + fc.getAttributeToken().getLength()
                            + ( fc.getFilterToken() != null ? fc.getFilterToken().getLength() : 0 )
                            + ( fc.getValueToken() != null ? fc.getValueToken().getLength() : 0 ) )
                    {
                        addPossibleObjectClasses( proposalList, fc.getValueToken() == null ? "" : fc.getValueToken() //$NON-NLS-1$
                            .getValue(), fc.getValueToken() == null ? offset : fc.getValueToken().getOffset() );
                    }
                }
            }

            // case B: extensible filter
            if ( filter.getFilterComponent() instanceof LdapFilterExtensibleComponent )
            {
                LdapFilterExtensibleComponent fc = ( LdapFilterExtensibleComponent ) filter.getFilterComponent();

                // case B1: editing extensible attribute type: show matching attribute types
                if ( fc.getAttributeToken() != null && fc.getAttributeToken().getOffset() <= offset
                    && offset <= fc.getAttributeToken().getOffset() + fc.getAttributeToken().getLength() )
                {
                    addPossibleAttributeTypes( proposalList, fc.getAttributeToken().getValue(), fc.getAttributeToken()
                        .getOffset() );
                }

                // case B2: editing dn
                if ( fc.getDnAttrToken() != null && fc.getDnAttrToken().getOffset() <= offset
                    && offset <= fc.getDnAttrToken().getOffset() + fc.getDnAttrToken().getLength() )
                {
                    addDnAttr( proposalList, fc.getDnAttrToken().getValue(), fc.getDnAttrToken().getOffset() );
                }

                // case B3: editing matching rule
                if ( fc.getMatchingRuleColonToken() != null
                    && fc.getMatchingRuleToken() == null
                    && fc.getMatchingRuleColonToken().getOffset() <= offset
                    && offset <= fc.getMatchingRuleColonToken().getOffset()
                        + fc.getMatchingRuleColonToken().getLength() )
                {
                    if ( fc.getDnAttrColonToken() == null )
                    {
                        addDnAttr( proposalList, "", offset ); //$NON-NLS-1$
                    }
                    addPossibleMatchingRules( proposalList, "", offset, fc.getEqualsColonToken(), fc.getEqualsToken() ); //$NON-NLS-1$
                }
                if ( fc.getMatchingRuleToken() != null && fc.getMatchingRuleToken().getOffset() <= offset
                    && offset <= fc.getMatchingRuleToken().getOffset() + fc.getMatchingRuleToken().getLength() )
                {
                    if ( fc.getDnAttrColonToken() == null )
                    {
                        addDnAttr( proposalList, fc.getMatchingRuleToken().getValue(), fc.getMatchingRuleToken()
                            .getOffset() );
                    }

                    String matchingRuleValue = fc.getMatchingRuleToken().getValue();
                    addPossibleMatchingRules( proposalList, matchingRuleValue, fc.getMatchingRuleToken().getOffset(),
                        fc.getEqualsColonToken(), fc.getEqualsToken() );
                }
            }
        }

        return proposalList.toArray( new ICompletionProposal[0] );
    }


    /**
     * Adds the possible attribute types to the proposal list.
     * 
     * @param proposalList the proposal list
     * @param attributeType the current attribute type
     * @param offset the offset
     */
    private void addPossibleAttributeTypes( List<ICompletionProposal> proposalList, String attributeType, int offset )
    {
        if ( schema != null )
        {
            for ( String possibleAttributeType : possibleAttributeTypes.keySet() )
            {
                AttributeType description = possibleAttributeTypes.get( possibleAttributeType );
                if ( possibleAttributeType.toUpperCase().startsWith( attributeType.toUpperCase() ) )
                {
                    String replacementString = possibleAttributeType;
                    String displayString = possibleAttributeType;
                    if ( displayString.equals( description.getOid() ) )
                    {
                        displayString += " (" + SchemaUtils.toString( description ) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
                    }
                    else
                    {
                        displayString += " (" + description.getOid() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
                    }
                    String info = SchemaUtils.getLdifLine( description );
                    ICompletionProposal proposal = new CompletionProposal( replacementString, offset, attributeType
                        .length(), replacementString.length(), getAttributeTypeImage(), displayString, null, info );
                    proposalList.add( proposal );
                }
            }
        }
    }


    /**
     * Adds the possible attribute types to the proposal list.
     * 
     * @param proposalList the proposal list
     * @param attributeType the current attribute type
     * @param offset the offset
     */
    private void addPossibleFilterTypes( List<ICompletionProposal> proposalList, String attributeType,
        String filterType, int offset )
    {
        if ( schema != null )
        {
            Map<String, String> copy = new LinkedHashMap<String, String>( possibleFilterTypes );
            if ( SchemaUtils.getEqualityMatchingRuleNameOrNumericOidTransitive( schema
                .getAttributeTypeDescription( attributeType ), schema ) == null )
            {
                copy.remove( "=" ); //$NON-NLS-1$
                copy.remove( "~=" ); //$NON-NLS-1$
            }
            if ( SchemaUtils.getOrderingMatchingRuleNameOrNumericOidTransitive( schema
                .getAttributeTypeDescription( attributeType ), schema ) == null )
            {
                copy.remove( "<=" ); //$NON-NLS-1$
                copy.remove( ">=" ); //$NON-NLS-1$
            }

            for ( String possibleFilterType : copy.keySet() )
            {
                String replacementString = possibleFilterType;
                String displayString = copy.get( possibleFilterType );

                ICompletionProposal proposal = new CompletionProposal( replacementString, offset, filterType.length(),
                    possibleFilterType.length(), getFilterTypeImage(), displayString, null, null );
                proposalList.add( proposal );
            }
        }
    }


    /**
     * Adds the possible object classes to the proposal list.
     * 
     * @param proposalList the proposal list
     * @param objectClasses the object class
     * @param offset the offset
     */
    private void addPossibleObjectClasses( List<ICompletionProposal> proposalList, String objectClass, int offset )
    {
        if ( schema != null )
        {
            for ( String possibleObjectClass : possibleObjectClasses.keySet() )
            {
                ObjectClass description = possibleObjectClasses.get( possibleObjectClass );
                if ( possibleObjectClass.toUpperCase().startsWith( objectClass.toUpperCase() ) )
                {
                    String replacementString = possibleObjectClass;
                    String displayString = possibleObjectClass;
                    if ( displayString.equals( description.getOid() ) )
                    {
                        displayString += " (" + SchemaUtils.toString( description ) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
                    }
                    else
                    {
                        displayString += " (" + description.getOid() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
                    }

                    ICompletionProposal proposal = new CompletionProposal( replacementString, offset, objectClass
                        .length(), replacementString.length(), getObjectClassImage(), displayString, null, SchemaUtils
                        .getLdifLine( schema.getObjectClassDescription( possibleObjectClass ) ) );
                    proposalList.add( proposal );
                }
            }
        }
    }


    /**
     * Adds the possible matching rules (that fits to the given attribute type) to the proposal list.
     * 
     * @param proposalList the proposal list
     * @param matchingRule the matching rule
     * @param offset the offset
     */
    private void addPossibleMatchingRules( List<ICompletionProposal> proposalList, String matchingRule, int offset,
        LdapFilterToken equalsColonToken, LdapFilterToken equalsToken )
    {
        if ( schema != null )
        {
            for ( String possibleMatchingRule : possibleMatchingRules.keySet() )
            {
                if ( possibleMatchingRule.toUpperCase().startsWith( matchingRule.toUpperCase() ) )
                {
                    MatchingRule description = schema.getMatchingRuleDescription( possibleMatchingRule );
                    String replacementString = possibleMatchingRule;
                    if ( equalsColonToken == null )
                    {
                        replacementString += ":"; //$NON-NLS-1$
                    }
                    if ( equalsToken == null )
                    {
                        replacementString += "="; //$NON-NLS-1$
                    }
                    String displayString = possibleMatchingRule;
                    if ( displayString.equals( description.getOid() ) )
                    {
                        displayString += " (" + SchemaUtils.toString( description ) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
                    }
                    else
                    {
                        displayString += " (" + description.getOid() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
                    }
                    String info = SchemaUtils.getLdifLine( description );
                    ICompletionProposal proposal = new CompletionProposal( replacementString, offset, matchingRule
                        .length(), replacementString.length(), getMatchingRuleImage(), displayString, null, info );
                    proposalList.add( proposal );
                }
            }
        }
    }


    /**
     * Adds the dn: proposal to the proposal list.
     * 
     * @param proposalList the proposal list
     * @param dnAttr the dn attr
     * @param offset the offset
     */
    private void addDnAttr( List<ICompletionProposal> proposalList, String dnAttr, int offset )
    {
        if ( "dn".toUpperCase().startsWith( dnAttr.toUpperCase() ) ) //$NON-NLS-1$
        {
            String replacementString = "dn:"; //$NON-NLS-1$
            String displayString = "dn: ()"; //$NON-NLS-1$
            ICompletionProposal proposal = new CompletionProposal( replacementString, offset, dnAttr.length(),
                replacementString.length(), null, displayString, null, null );
            proposalList.add( proposal );
        }
    }


    /**
     * Gets the attribute type image.
     * 
     * @return the attribute type image
     */
    private Image getAttributeTypeImage()
    {
        return BrowserCommonActivator.getDefault().getImage( BrowserCommonConstants.IMG_ATD );
    }


    /**
     * Gets the filter type image.
     * 
     * @return the filter type image
     */
    private Image getFilterTypeImage()
    {
        return BrowserCommonActivator.getDefault().getImage( BrowserCommonConstants.IMG_FILTER_EDITOR );
    }


    /**
     * Gets the object class image.
     * 
     * @return the object class image
     */
    private Image getObjectClassImage()
    {
        return BrowserCommonActivator.getDefault().getImage( BrowserCommonConstants.IMG_OCD );
    }


    /**
     * Gets the matching rule image.
     * 
     * @return the matching rule image
     */
    private Image getMatchingRuleImage()
    {
        return BrowserCommonActivator.getDefault().getImage( BrowserCommonConstants.IMG_MRD );
    }


    /**
     * @see org.eclipse.jface.text.templates.TemplateCompletionProcessor#getTemplates(java.lang.String)
     */
    protected Template[] getTemplates( String contextTypeId )
    {
        Template[] templates = BrowserCommonActivator.getDefault().getFilterTemplateStore().getTemplates(
            BrowserCommonConstants.FILTER_TEMPLATE_ID );
        return templates;
    }


    /**
     * @see org.eclipse.jface.text.templates.TemplateCompletionProcessor#getContextType(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion)
     */
    protected TemplateContextType getContextType( ITextViewer viewer, IRegion region )
    {
        TemplateContextType contextType = BrowserCommonActivator.getDefault().getFilterTemplateContextTypeRegistry()
            .getContextType( BrowserCommonConstants.FILTER_TEMPLATE_ID );
        return contextType;
    }


    /**
     * @see org.eclipse.jface.text.templates.TemplateCompletionProcessor#getImage(org.eclipse.jface.text.templates.Template)
     */
    protected Image getImage( Template template )
    {
        return BrowserCommonActivator.getDefault().getImage( BrowserCommonConstants.IMG_TEMPLATE );
    }


    /**
     * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeContextInformation(org.eclipse.jface.text.ITextViewer, int)
     */
    public IContextInformation[] computeContextInformation( ITextViewer viewer, int documentOffset )
    {
        return null;
    }


    /**
     * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getContextInformationAutoActivationCharacters()
     */
    public char[] getContextInformationAutoActivationCharacters()
    {
        return null;
    }


    /**
     * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getErrorMessage()
     */
    public String getErrorMessage()
    {
        return null;
    }


    /**
     * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getContextInformationValidator()
     */
    public IContextInformationValidator getContextInformationValidator()
    {
        return null;
    }

}
