/*
 * Copyright 2006 Sascha Weinreuter
 *
 * 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.intellij.lang.regexp.surroundWith;

import com.intellij.lang.ASTNode;
import com.intellij.lang.surroundWith.Surrounder;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileFactory;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.intellij.lang.regexp.RegExpFileType;
import org.intellij.lang.regexp.psi.RegExpAtom;
import org.intellij.lang.regexp.psi.RegExpPattern;
import org.intellij.lang.regexp.psi.impl.RegExpElementImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

class GroupSurrounder implements Surrounder {
    private final String myTitle;
    private final String myGroupStart;

    GroupSurrounder(String title, String groupStart) {
        myTitle = title;
        myGroupStart = groupStart;
    }

    @Override
    public String getTemplateDescription() {
        return myTitle;
    }

    @Override
    public boolean isApplicable(@NotNull PsiElement[] elements) {
        return elements.length == 1 || PsiTreeUtil.findCommonParent(elements) == elements[0].getParent();
    }

    @Override
    @Nullable
    public TextRange surroundElements(@NotNull Project project, @NotNull Editor editor, @NotNull PsiElement[] elements) throws IncorrectOperationException {
        assert elements.length == 1 || PsiTreeUtil.findCommonParent(elements) == elements[0].getParent();
        final PsiElement e = elements[0];
        final ASTNode node = e.getNode();
        assert node != null;

        final ASTNode parent = node.getTreeParent();

        final StringBuilder s = new StringBuilder();
        for (int i = 0; i < elements.length; i++) {
            final PsiElement element = elements[i];
            if (element instanceof RegExpElementImpl) {
                s.append(((RegExpElementImpl)element).getUnescapedText());
            } else {
                s.append(element.getText());
            }
            if (i > 0) {
                final ASTNode child = element.getNode();
                assert child != null;
                parent.removeChild(child);
            }
        }
        final PsiFileFactory factory = PsiFileFactory.getInstance(project);

        final PsiFile f = factory.createFileFromText("dummy.regexp", RegExpFileType.INSTANCE, makeReplacement(s));
        final RegExpPattern pattern = PsiTreeUtil.getChildOfType(f, RegExpPattern.class);
        assert pattern != null;

        final RegExpAtom element = pattern.getBranches()[0].getAtoms()[0];

        if (isInsideStringLiteral(e)) {
            final Document doc = editor.getDocument();
            PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(doc);
            final TextRange tr = e.getTextRange();
            doc.replaceString(tr.getStartOffset(), tr.getEndOffset(),
                    StringUtil.escapeStringCharacters(element.getText()));

            return TextRange.from(e.getTextRange().getEndOffset(), 0);
        } else {
            final PsiElement n = e.replace(element);
            return TextRange.from(n.getTextRange().getEndOffset(), 0);
        }
    }

    private static boolean isInsideStringLiteral(PsiElement context) {
      while (context != null) {
        if (RegExpElementImpl.isLiteralExpression(context)) {
          return true;
        }
        context = context.getContext();
      }
      return false;
    }

    protected String makeReplacement(StringBuilder s) {
        return myGroupStart + s + ")";
    }
}
