/**
 * Copyright (c) 2005-2013 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Eclipse Public License (EPL).
 * Please see the license.txt included with this distribution for details.
 * Any modifications to this file must keep this entire header intact.
 */
/*
 * Created on Mar 9, 2005
 *
 * @author Fabio Zadrozny
 */
package org.python.pydev.editor.codecompletion;

import java.io.File;

import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.python.pydev.core.ICompletionRequest;
import org.python.pydev.core.IModule;
import org.python.pydev.core.IPythonNature;
import org.python.pydev.core.ITokenCompletionRequest;
import org.python.pydev.core.MisconfigurationException;
import org.python.pydev.core.docutils.PySelection;
import org.python.pydev.core.docutils.PySelection.ActivationTokenAndQual;
import org.python.pydev.editor.codecompletion.revisited.AbstractASTManager;
import org.python.pydev.shared_core.string.FastStringBuffer;

/**
 * This class defines the information used for a code completion request.
 * 
 * @author Fabio Zadrozny
 */
public final class CompletionRequest implements ICompletionRequest, ITokenCompletionRequest {

    /**
     * This is used on the AssistOverride: the activationToken is pre-specified
     * for some reason
     */
    public CompletionRequest(File editorFile, IPythonNature nature, IDocument doc, String activationToken,
            int documentOffset, int qlen, IPyCodeCompletion codeCompletion, String qualifier,
            boolean useSubstringMatchInCodeCompletion) {

        this.editorFile = editorFile;
        this.nature = nature;
        this.doc = doc;
        this.activationToken = activationToken;
        this.documentOffset = documentOffset;
        this.qlen = qlen;
        this.codeCompletion = codeCompletion;
        this.qualifier = qualifier;

        // the full qualifier is not set here
        this.fullQualifier = null;

        this.calltipOffset = 0;
        this.alreadyHasParams = false;
        this.offsetForKeywordParam = 0;
        this.useSubstringMatchInCodeCompletion = useSubstringMatchInCodeCompletion;
    }

    /**
     * This is the constructor that should be usually used. It will set the
     * activation token and the qualifier based on the document and its offset
     * 
     * @param editorFile
     * @param nature
     * @param doc
     * @param documentOffset
     * @param codeCompletion
     */
    public CompletionRequest(File editorFile, IPythonNature nature, IDocument doc, int documentOffset,
            IPyCodeCompletion codeCompletion, boolean useSubstringMatchInCodeCompletion) {
        //we need those set before requesting a py selection
        this.doc = doc;
        this.documentOffset = documentOffset;

        ActivationTokenAndQual act = getPySelection().getActivationTokenAndQual(false, true);
        this.activationToken = act.activationToken;
        this.qualifier = act.qualifier;
        this.isInCalltip = act.changedForCalltip;
        this.isInMethodKeywordParam = act.isInMethodKeywordParam;
        this.offsetForKeywordParam = act.offsetForKeywordParam;
        this.alreadyHasParams = act.alreadyHasParams;
        this.calltipOffset = act.calltipOffset;

        int qlen = qualifier.length();

        this.editorFile = editorFile;
        this.nature = nature;
        this.qlen = qlen;
        this.codeCompletion = codeCompletion;

        this.fullQualifier = getPySelection().getActivationTokenAndQual(true)[1];
        this.useSubstringMatchInCodeCompletion = useSubstringMatchInCodeCompletion;
    }

    public CompletionRequest createCopyForKeywordParamRequest() {
        CompletionRequest request = new CompletionRequest(editorFile, nature, doc, this.offsetForKeywordParam,
                codeCompletion, this.useSubstringMatchInCodeCompletion);
        request.isInMethodKeywordParam = false; //Just making sure it will not be another request for keyword params
        return request;
    }

    /**
     * This is the file where the request was created. Note that it might be
     * null (especially during the tests). It should be available at runtime and
     * may be used to resolve some path.
     */
    public File editorFile;

    @Override
    public File getEditorFile() {
        return editorFile;
    }

    /**
     * Used when a completion is requested for an editor
     */
    public IPythonNature nature;

    @Override
    public IPythonNature getNature() {
        return nature;
    }

    public final IDocument doc;

    /**
     * The activation token of this request.
     * 
     * If it is requested at "m1.m2", the activationToken should be "m1" and the
     * qualifier should be "m2"
     * 
     * If requested at "m3", the activationToken should be empty and the
     * qualifier should be "m3"
     */
    public String activationToken;

    /**
     * The qualifier found to the cursor (will be used to filter the found
     * completions)
     */
    public final String qualifier;

    /**
     * The full qualifier found (this is the complete token over where we have
     * the cursor). May be null.
     */
    public final String fullQualifier;

    /**
     * The offset in the document where this request was asked
     */
    public final int documentOffset;

    /**
     * The lenght of the qualifier (== qualifier.length())
     */
    public final int qlen;

    /**
     * The engine for doing the code-completion
     */
    public final IPyCodeCompletion codeCompletion;

    /**
     * Defines if we're getting the completions for a calltip
     * This happens when we're after a '(' or ',' in a method call. 
     */
    public boolean isInCalltip;

    /**
     * Defines if we're in a method call.
     */
    public boolean isInMethodKeywordParam;

    /**
     * Only really valid when isInMethodKeywordParam == true. Defines the offset of the method call.
     */
    public final int offsetForKeywordParam;

    /**
     * Offset of the parens in a calltip.
     */
    public final int calltipOffset;

    /**
     * Useful only if we're in a calltip
     */
    public final boolean alreadyHasParams;

    /**
     * A selection object (cache) -- initialized on request
     */
    private PySelection ps;

    /**
     * This is a field that is filled in the code-completion engine indicating whether templates should be shown or not.
     */
    public boolean showTemplates = true;

    @Override
    public String toString() {
        FastStringBuffer buffer = new FastStringBuffer();
        buffer.append("CompletionRequest[");
        buffer.append(" editorFile:");
        buffer.appendObject(editorFile);
        buffer.append(" activationToken:");
        buffer.append(activationToken);
        buffer.append(" qualifier:");
        buffer.append(qualifier);
        buffer.append(" isInCalltip:");
        buffer.append(isInCalltip);
        buffer.append(" alreadyHasParams:");
        buffer.append(alreadyHasParams);
        buffer.append("]");
        return buffer.toString();
    }

    /**
     * @return a PySelection that represents the current request. If it doesn't exist, create it and cache
     * for other requests.
     */
    public PySelection getPySelection() {
        if (this.ps == null) {
            this.ps = new PySelection(this.doc, this.documentOffset);
        }
        return this.ps;
    }

    /**
     * Cache for the module name
     */
    private String initialModule;

    /**
     * Cache for the source module created.
     */
    private IModule module;

    public final boolean useSubstringMatchInCodeCompletion;

    /**
     * @return the module name where the completion request took place (may be null if there is no editor file associated)
     * @throws MisconfigurationException 
     */
    public String resolveModule() throws MisconfigurationException {
        if (initialModule == null && editorFile != null) {
            initialModule = nature.resolveModule(editorFile);
        }
        return initialModule;
    }

    /**
     * @param state 
     * @param astManager 
     * @return
     * @throws MisconfigurationException 
     */
    @Override
    public IModule getModule() throws MisconfigurationException {
        if (module == null) {
            module = AbstractASTManager.createModule(this.editorFile, this.doc, this.nature);
        }
        return module;
    }

    @Override
    public String getActivationToken() {
        return this.activationToken;
    }

    @Override
    public void setActivationToken(String activationToken) {
        this.activationToken = activationToken;
    }

    @Override
    public String getQualifier() {
        return qualifier;
    }

    @Override
    public int getLine() throws BadLocationException {
        return doc.getLineOfOffset(documentOffset);
    }

    @Override
    public int getCol() throws BadLocationException {
        IRegion region = doc.getLineInformationOfOffset(documentOffset);
        int col = documentOffset - region.getOffset();
        return col;
    }

}