/*
 * 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.netbeans.modules.editor.java;

import com.sun.source.tree.Tree;

import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import javax.swing.text.JTextComponent;

import com.sun.source.tree.CaseTree;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.util.SourcePositions;
import org.netbeans.api.java.lexer.JavaTokenId;
import org.netbeans.api.java.source.CompilationController;
import org.netbeans.api.java.source.JavaSource.Phase;
import org.netbeans.api.java.source.SourceUtils;
import org.netbeans.api.java.source.TreeUtilities;
import org.netbeans.api.lexer.TokenSequence;
import org.netbeans.api.progress.ProgressUtils;
import org.netbeans.lib.editor.codetemplates.api.CodeTemplate;
import org.netbeans.lib.editor.codetemplates.spi.CodeTemplateFilter;
import org.netbeans.modules.parsing.api.ParserManager;
import org.netbeans.modules.parsing.api.ResultIterator;
import org.netbeans.modules.parsing.api.Source;
import org.netbeans.modules.parsing.api.UserTask;
import org.netbeans.modules.parsing.spi.ParseException;
import org.netbeans.modules.parsing.spi.Parser;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;

/**
 *
 * @author Dusan Balek
 */
public class JavaCodeTemplateFilter implements CodeTemplateFilter {
    
    private static final Logger LOG = Logger.getLogger(JavaCodeTemplateFilter.class.getName());
    private static final String EXPRESSION = "EXPRESSION"; //NOI18N
    private static final String CLASS_HEADER = "CLASS_HEADER"; //NOI18N
    
    private Tree.Kind treeKindCtx = null;
    private String stringCtx = null;
    
    private JavaCodeTemplateFilter(JTextComponent component, int offset) {
        if (Utilities.isJavaContext(component, offset, true)) {
            final int startOffset = offset;
            final int endOffset = component.getSelectionStart() == offset ? component.getSelectionEnd() : -1;
            final Source source = Source.create(component.getDocument());
            if (source != null) {
                final AtomicBoolean cancel = new AtomicBoolean();
                ProgressUtils.runOffEventDispatchThread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            ParserManager.parse(Collections.singleton(source), new UserTask() {
                                @Override
                                public void run(ResultIterator resultIterator) throws Exception {
                                    if (cancel.get()) {
                                        return;
                                    }
                                    Parser.Result result = resultIterator.getParserResult(startOffset);
                                    CompilationController controller = result != null ? CompilationController.get(result) : null;
                                    if (controller != null && Phase.PARSED.compareTo(controller.toPhase(Phase.PARSED)) <= 0) {
                                        TreeUtilities tu = controller.getTreeUtilities();
                                        int eo = endOffset;
                                        int so = startOffset;
                                        if (so >= 0) {
                                            so = result.getSnapshot().getEmbeddedOffset(startOffset);
                                        }
                                        if (endOffset >= 0) {
                                            eo = result.getSnapshot().getEmbeddedOffset(endOffset);
                                            TokenSequence<JavaTokenId> ts = SourceUtils.getJavaTokenSequence(controller.getTokenHierarchy(), so);
                                            int delta = ts.move(so);
                                            if (delta == 0 || ts.moveNext() && ts.token().id() == JavaTokenId.WHITESPACE) {
                                                delta = ts.move(eo);
                                                if (delta == 0 || ts.moveNext() && ts.token().id() == JavaTokenId.WHITESPACE) {
                                                    String selectedText = controller.getText().substring(so, eo).trim();
                                                    SourcePositions[] sp = new SourcePositions[1];
                                                    ExpressionTree expr = selectedText.length() > 0 ? tu.parseExpression(selectedText, sp) : null;
                                                    if (expr != null && expr.getKind() != Tree.Kind.IDENTIFIER && !Utilities.containErrors(expr) && sp[0].getEndPosition(null, expr) >= selectedText.length()) {
                                                        stringCtx = EXPRESSION;
                                                    }
                                                }
                                            }
                                        }
                                        Tree tree = tu.pathFor(so).getLeaf();
                                        if (eo >= 0 && so != eo) {
                                            if (tu.pathFor(eo).getLeaf() != tree) {
                                                return;
                                            }
                                        }
                                        treeKindCtx = tree.getKind();
                                        switch (treeKindCtx) {
                                            case CASE:
                                                if (so < controller.getTrees().getSourcePositions().getEndPosition(controller.getCompilationUnit(), ((CaseTree)tree).getExpression())) {
                                                    treeKindCtx = null;
                                                }
                                                break;
                                            case CLASS:
                                                SourcePositions sp = controller.getTrees().getSourcePositions();
                                                int startPos = (int)sp.getEndPosition(controller.getCompilationUnit(), ((ClassTree)tree).getModifiers());
                                                if (startPos <= 0) {
                                                    startPos = (int)sp.getStartPosition(controller.getCompilationUnit(), tree);
                                                }
                                                String headerText = controller.getText().substring(startPos, so);
                                                int idx = headerText.indexOf('{'); //NOI18N
                                                if (idx < 0) {
                                                    treeKindCtx = null;
                                                    stringCtx = CLASS_HEADER;
                                                }
                                                break;
                                            case FOR_LOOP:
                                            case ENHANCED_FOR_LOOP:
                                            case WHILE_LOOP:
                                                sp = controller.getTrees().getSourcePositions();
                                                startPos = (int)sp.getStartPosition(controller.getCompilationUnit(), tree);
                                                String text = controller.getText().substring(startPos, so);
                                                if (!text.trim().endsWith(")")) {
                                                    treeKindCtx = null;
                                                }
                                        }
                                    }
                                }
                            });
                        } catch (ParseException ex) {
                            Exceptions.printStackTrace(ex);
                        }
                    }
                }, NbBundle.getMessage(JavaCodeTemplateProcessor.class, "JCT-init"), cancel, false); //NOI18N
            }
        }
    }

    @Override
    public synchronized boolean accept(CodeTemplate template) {
        if (treeKindCtx == null && stringCtx == null) {
            return false;
        }
        EnumSet<Tree.Kind> treeKindContexts = EnumSet.noneOf(Tree.Kind.class);
        HashSet stringContexts = new HashSet();
        getTemplateContexts(template, treeKindContexts, stringContexts);
        return treeKindContexts.isEmpty() && stringContexts.isEmpty() && treeKindCtx != Tree.Kind.STRING_LITERAL || treeKindContexts.contains(treeKindCtx) || stringContexts.contains(stringCtx);
    }
    
    private void getTemplateContexts(CodeTemplate template, EnumSet<Tree.Kind> treeKindContexts, HashSet<String> stringContexts) {
        List<String> contexts = template.getContexts();
        if (contexts != null) {
            for(String context : contexts) {
                try {
                    treeKindContexts.add(Tree.Kind.valueOf(context));
                } catch (IllegalArgumentException iae) {
                    stringContexts.add(context);
                }
            }
        }
    }

    public static final class Factory implements CodeTemplateFilter.ContextBasedFactory {
        
        @Override
        public CodeTemplateFilter createFilter(JTextComponent component, int offset) {
            return new JavaCodeTemplateFilter(component, offset);
        }

        @Override
        public List<String> getSupportedContexts() {
            Tree.Kind[] values = Tree.Kind.values();
            List<String> contexts = new ArrayList<>(values.length + 1);
            for (Tree.Kind value : values) {
                contexts.add(value.name());
            }
            contexts.add(CLASS_HEADER);
            Collections.sort(contexts);
            return contexts;
        }
    }
}
