/*
 * Copyright 2000-2009 JetBrains s.r.o.
 *
 * 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 com.intellij.xml.actions;

import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.lang.xhtml.XHTMLLanguage;
import com.intellij.lang.xml.XMLLanguage;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileFactory;
import com.intellij.psi.html.HtmlTag;
import com.intellij.psi.xml.*;
import com.intellij.util.IncorrectOperationException;
import com.intellij.xml.XmlBundle;
import com.intellij.xml.util.HtmlUtil;
import org.jetbrains.annotations.NotNull;

/**
 * @author spleaner
 */
public class XmlSplitTagAction implements IntentionAction {

  @Override
  @NotNull
  public String getText() {
    return XmlBundle.message("xml.split.tag.intention.action");
  }

  @Override
  @NotNull
  public String getFamilyName() {
    return XmlBundle.message("xml.split.tag.intention.action");
  }

  @Override
  public boolean isAvailable(@NotNull final Project project, final Editor editor, final PsiFile file) {
    if (file instanceof XmlFile) {
      if (editor != null) {
        final int offset = editor.getCaretModel().getOffset();
        final PsiElement psiElement = file.findElementAt(offset);
        if (psiElement != null) {
          final PsiElement parent = psiElement.getParent();
          if (parent != null && parent instanceof XmlText && parent.getText().trim().length() > 0) {
            final PsiElement grandParent = parent.getParent();
            if (grandParent != null && !isInsideUnsplittableElement(grandParent)) {
              return true;
            }
          }
        }
      }
    }

    return false;
  }

  private static boolean isInsideUnsplittableElement(final PsiElement grandParent) {
    if (!(grandParent instanceof HtmlTag) && grandParent.getContainingFile().getLanguage() != XHTMLLanguage.INSTANCE) {
      return false;
    }

    final String name = ((XmlTag)grandParent).getName();
    return "html".equals(name) || "body".equals(name) || "title".equals(name);
  }

  @Override
  public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException {
    if (editor != null) {
      final int offset = editor.getCaretModel().getOffset();
      final PsiElement psiElement = file.findElementAt(offset);
      if (psiElement != null) {
        final PsiElement xmlText = psiElement.getParent();
        final TextRange textRange = xmlText.getTextRange();
        final int offsetInElement = offset - textRange.getStartOffset();

        final PsiElement containingTag = xmlText.getParent();
        if (containingTag instanceof XmlTag) {
          final XmlTag xmlTag = (XmlTag)containingTag;

          final String s = xmlText.getText();
          String first = s.substring(0, offsetInElement);
          String second = s.substring(offsetInElement);

          if (xmlText instanceof XmlTagChild) {
            XmlTagChild prev = ((XmlTagChild)xmlText).getPrevSiblingInTag();
            while(prev != null) {
              first = prev.getText() + first;
              prev = prev.getPrevSiblingInTag();
            }

            XmlTagChild next = ((XmlTagChild)xmlText).getNextSiblingInTag();
            while(next != null) {
              second += next.getText();
              next = next.getNextSiblingInTag();
            }
          }

          final String filetext = buildNewText(xmlTag, first, second);

          final XmlFile xmlFile = (XmlFile)PsiFileFactory.getInstance(project).createFileFromText("dummy.xml", XMLLanguage.INSTANCE,
                                                                                               filetext);
          final PsiElement parent2 = containingTag.getParent();
          final XmlTag tag = xmlFile.getDocument().getRootTag();
          XmlTag last = null;
          final PsiElement[] children = tag.getChildren();
          for (int i = children.length - 1; i >= 0; i--) {
            PsiElement element = children[i];
            if (element instanceof XmlTag) {
              final XmlTag tag1 = (XmlTag)parent2.addAfter(element, containingTag);

              if (last == null) {
                last = tag1;
              }
            }
          }

          containingTag.delete();
          editor.getCaretModel().moveToOffset(last.getValue().getTextRange().getStartOffset());
        }
      }
    }
  }

  private static String buildNewText(final XmlTag xmlTag, final String first, final String second) {
    final StringBuilder attrs = new StringBuilder();
    final StringBuilder attrsWoId = new StringBuilder();
    for (XmlAttribute attribute : xmlTag.getAttributes()) {
      if (!HtmlUtil.ID_ATTRIBUTE_NAME.equals(attribute.getName())) {
        attrs.append(attribute.getName()).append("=\"").append(attribute.getValue()).append("\" ");
        attrsWoId.append(attribute.getName()).append("=\"").append(attribute.getValue()).append("\" ");
      } else {
        attrs.append(attribute.getName()).append("=\"").append(attribute.getValue()).append("\" ");
      }

    }

    final StringBuilder sb = new StringBuilder();
    final String name = xmlTag.getName();
    sb.append("<root><").append(name);
    if (attrs.length() > 0) {
      sb.append(' ').append(attrs);
    }
    sb.append('>');
    sb.append(first);
    sb.append("</").append(name).append("><").append(name);
    if (attrsWoId.length() > 0) {
      sb.append(' ').append(attrsWoId);
    }
    sb.append('>');
    sb.append(second).append("</").append(name).append("></root>");

    return sb.toString();
  }

  @Override
  public boolean startInWriteAction() {
    return true;
  }
}

@@ -738,50 +738,8 @@
 ge;%0A
-import com.intellij.lang.xml.XMLLanguage;%0A
 impo
@@ -4202,28 +4202,28 @@
 l%22, 
-XMLLanguage.INSTANCE
+xmlTag.getLanguage()
 ,%0A  

use tag language (WEB-27728)