/**
 * Copyright (c) 2005-2011 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.
 */
package org.python.pydev.editor.codecompletion;

import java.io.IOException;

import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.python.pydev.core.IGrammarVersionProvider;
import org.python.pydev.core.IIndentPrefs;
import org.python.pydev.core.MisconfigurationException;
import org.python.pydev.core.docutils.PySelection;
import org.python.pydev.core.docutils.StringUtils;
import org.python.pydev.core.log.Log;
import org.python.pydev.editor.PyEdit;
import org.python.pydev.editor.autoedit.DefaultIndentPrefs;
import org.python.pydev.editor.codefolding.PySourceViewer;
import org.python.pydev.parser.jython.SimpleNode;
import org.python.pydev.parser.jython.ast.FunctionDef;
import org.python.pydev.parser.jython.ast.NameTok;
import org.python.pydev.parser.jython.ast.Pass;
import org.python.pydev.parser.jython.ast.stmtType;
import org.python.pydev.parser.jython.ast.factory.AdapterPrefs;
import org.python.pydev.parser.jython.ast.factory.PyAstFactory;
import org.python.pydev.parser.prettyprinterv2.MakeAstValidForPrettyPrintingVisitor;
import org.python.pydev.parser.prettyprinterv2.PrettyPrinterPrefsV2;
import org.python.pydev.parser.prettyprinterv2.PrettyPrinterV2;


/**
 * @author fabioz
 *
 */
public class OverrideMethodCompletionProposal extends AbstractPyCompletionProposalExtension2 {

    private final FunctionDef functionDef;
    private final String parentClassName;
    private String currentClassName;

    public OverrideMethodCompletionProposal(int replacementOffset, int replacementLength, int cursorPosition,
            Image image, FunctionDef functionDef, String parentClassName, String currentClassName) {
        super("", replacementOffset, replacementLength, cursorPosition, IPyCompletionProposal.PRIORITY_CREATE);
        this.fImage = image;
        this.functionDef = functionDef;
        this.fDisplayString = ((NameTok) functionDef.name).id + " (Override method in " + parentClassName + ")";
        this.parentClassName = parentClassName;
        this.currentClassName = currentClassName;
    }

    /* (non-Javadoc)
     * @see org.python.pydev.editor.codecompletion.PyCompletionProposal#apply(org.eclipse.jface.text.IDocument)
     */
    @Override
    public void apply(IDocument document) {
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#apply(org.eclipse.jface.text.ITextViewer, char, int, int)
     */
    public void apply(ITextViewer viewer, char trigger, int stateMask, int offset) {
        IDocument document = viewer.getDocument();
        int finalOffset = applyOnDocument(viewer, document, trigger, stateMask, offset);
        if (finalOffset >= 0) {
            try {
                PySelection ps = new PySelection(document, finalOffset);
                int firstCharPosition = PySelection.getFirstCharPosition(ps.getLine());
                int lineOffset = ps.getLineOffset();
                int location = lineOffset + firstCharPosition;
                int len = finalOffset - location;
                fCursorPosition = location;
                fReplacementLength = len;

            } catch (Exception e) {
                Log.log(e);
            }

        }
    }

    public int applyOnDocument(ITextViewer viewer, IDocument document, char trigger, int stateMask, int offset) {
        IGrammarVersionProvider versionProvider = null;
        PyEdit edit = null;
        if (viewer instanceof PySourceViewer) {
            PySourceViewer pySourceViewer = (PySourceViewer) viewer;
            versionProvider = edit = pySourceViewer.getEdit();
        } else {
            versionProvider = new IGrammarVersionProvider() {

                public int getGrammarVersion() throws MisconfigurationException {
                    return IGrammarVersionProvider.LATEST_GRAMMAR_VERSION;
                }
            };
        }
        String delimiter = PySelection.getDelimiter(document);

        PyAstFactory factory = new PyAstFactory(new AdapterPrefs(delimiter, versionProvider));
        stmtType overrideBody = factory.createOverrideBody(this.functionDef, parentClassName, currentClassName); //Note that the copy won't have a parent.

        FunctionDef functionDef = this.functionDef.createCopy(false);
        functionDef.body = new stmtType[] { overrideBody != null ? overrideBody : new Pass() };

        try {
            MakeAstValidForPrettyPrintingVisitor.makeValid(functionDef);
        } catch (Exception e) {
            Log.log(e);
        }
        String printed = printAst(edit, functionDef, delimiter);
        PySelection ps = new PySelection(document, offset);
        try {
            String lineContentsToCursor = ps.getLineContentsToCursor();
            int defIndex = lineContentsToCursor.indexOf("def");
            int defOffset = ps.getLineOffset() + defIndex;
            printed = StringUtils.indentTo(printed, lineContentsToCursor.substring(0, defIndex), false);
            printed = StringUtils.rightTrim(printed);

            this.fLen += offset - defOffset;

            document.replace(defOffset, this.fLen, printed);
            return defOffset + printed.length();
        } catch (BadLocationException x) {
            // ignore
        }
        return -1;
    }

    public static String printAst(PyEdit edit, SimpleNode astToPrint, String lineDelimiter) {
        String str = null;
        if (astToPrint != null) {
            IIndentPrefs indentPrefs;
            if (edit != null) {
                indentPrefs = edit.getIndentPrefs();
            } else {
                indentPrefs = DefaultIndentPrefs.get();
            }

            PrettyPrinterPrefsV2 prefsV2 = PrettyPrinterV2.createDefaultPrefs(edit, indentPrefs, lineDelimiter);

            PrettyPrinterV2 prettyPrinterV2 = new PrettyPrinterV2(prefsV2);
            try {

                str = prettyPrinterV2.print(astToPrint);
            } catch (IOException e) {
                Log.log(e);
            }
        }
        return str;
    }

    /* (non-Javadoc)
     * @see org.python.pydev.editor.codecompletion.AbstractPyCompletionProposalExtension2#getTriggerCharacters()
     */
    @Override
    public char[] getTriggerCharacters() {
        return null;
    }

    @Override
    public Point getSelection(IDocument document) {
        return new Point(fCursorPosition, fReplacementLength);
    }

}
