/*
 * Copyright (c) 2000-2006 JetBrains s.r.o. All Rights Reserved.
                                                    */
package com.intellij.util.xml;

import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.impl.PsiManagerImpl;
import com.intellij.psi.impl.meta.MetaRegistry;
import com.intellij.psi.xml.XmlFile;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.util.ThrowableRunnable;
import com.intellij.xml.impl.dtd.XmlNSDescriptorImpl;
import org.jetbrains.annotations.NotNull;

import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.util.List;

/**
 * @author peter
 */
public class DomPerformanceTest extends DomHardCoreTestCase{

  public void testVisitorPerformance() throws Throwable {
    final MyElement element = createElement("<!DOCTYPE faces-config PUBLIC\n" +
                                            "  \"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN\"\n" +
                                            "  \"http://java.sun.com/dtd/web-facesconfig_1_1.dtd\">", MyElement.class);

    MetaRegistry.bindDataToElement(DomUtil.getFile(element).getDocument(), new XmlNSDescriptorImpl());

    final MyElement child = element.addChildElement();
    child.getAttr().setValue("239");
    child.getChild239().getAttr().setValue("42");
    child.getChild().getAttr().setValue("42xx");
    child.getChild2().getAttr().setValue("42yy");
    child.addChildElement().getChild().addFooChild().getAttr().setValue("xxx");
    child.addChildElement().addFooChild().getAttr().setValue("yyy");
    child.addChildElement().addFooChild().addBarChild().addBarChild().addChildElement().getChild().getAttr().setValue("xxx");
    child.addChildElement().addBarComposite().setValue("ssss");
    child.addBarChild().getChild2().getAttr().setValue("234178956023");

    long start = System.currentTimeMillis();
    for (int i = 0; i < 239; i++) {
      element.addChildElement().copyFrom(child);
    }
    IdeaTestUtil.assertTiming("", 30000, System.currentTimeMillis() - start);

    final MyElement newElement = createElement(DomUtil.getFile(element).getText(), MyElement.class);

    //ProfilingUtil.startCPUProfiling();
    PlatformTestUtil.startPerformanceTest(getTestName(false), 200, new ThrowableRunnable() {
      @Override
      public void run() throws Exception {
        newElement.acceptChildren(new DomElementVisitor() {
          @Override
          public void visitDomElement(DomElement element) {
            element.acceptChildren(this);
          }
        });
        /*
        try {
          ProfilingUtil.captureCPUSnapshot("aaa");
        }
        catch (Exception e) {
          e.printStackTrace();
        }
        */

      }
    }).cpuBound().assertTiming();
  }

  public void testShouldntParseNonDomFiles() throws Throwable {
    for (int i = 0; i < 420; i++) {
      getDomManager().registerFileDescription(new DomFileDescription(MyChildElement.class, "foo") {

        @Override
        public boolean isMyFile(@NotNull final XmlFile file, final Module module) {
          fail();
          return super.isMyFile(file, module);
        }
      }, getTestRootDisposable());
      getDomManager().registerFileDescription(new DomFileDescription(MyChildElement.class, "bar") {

        @Override
        public boolean isMyFile(@NotNull final XmlFile file, final Module module) {
          fail();
          return super.isMyFile(file, module);
        }
      }, getTestRootDisposable());
    }

    getDomManager().createMockElement(MyChildElement.class, null, true);

    @NotNull final VirtualFile virtualFile = createFile("a.xml", "").getVirtualFile();
    new WriteCommandAction(getProject()) {
      @Override
      protected void run(Result result) throws Throwable {

        final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(virtualFile.getOutputStream(this)));
        writer.write("<root>\n");
        for (int i = 0; i < 23942; i++) {
          writer.write("<bar/>\n");
        }
        writer.write("</root>");
        writer.close();
        virtualFile.refresh(false, false);
      }
    }.execute();

    ((PsiManagerImpl)getPsiManager()).getFileManager().cleanupForNextTest();
    final XmlFile file = (XmlFile)getPsiManager().findFile(virtualFile);
    assertFalse(file.getNode().isParsed());
    assertTrue(StringUtil.isNotEmpty(file.getText()));
    PlatformTestUtil.startPerformanceTest("", 100, new ThrowableRunnable() {
      @Override
      public void run() throws Exception {
        assertNull(getDomManager().getFileElement(file));
      }
    }).cpuBound().assertTiming();
    assertFalse(file.getNode().isParsed());
  }

  public void testDontParseNamespacedDomFiles() throws Exception {
    getDomManager().registerFileDescription(new DomFileDescription(MyNamespacedElement.class, "foo") {
      @Override
      protected void initializeFileDescription() {
        registerNamespacePolicy("project", "project");
      }
    }, getTestRootDisposable());

    XmlFile file = (XmlFile)createFile("a.xml", "<foo xmlns=\"project\"/>");
    assertFalse(file.getNode().isParsed());
    assertNotNull(DomManager.getDomManager(getProject()).getFileElement(file, MyNamespacedElement.class));
    assertFalse(file.getNode().isParsed());

    file = (XmlFile)createFile("a.xml", "<foo xmlns=\"project2\"/>");
    assertFalse(file.getNode().isParsed());
    assertNull(DomManager.getDomManager(getProject()).getFileElement(file, MyNamespacedElement.class));
    assertFalse(file.getNode().isParsed());
  }

  @Namespace("project")
  public interface MyNamespacedElement extends DomElement {

  }
  public interface MyChildElement extends DomElement {
    @Attribute
    @Required
    GenericAttributeValue<String> getAttr();

    List<MyFooConcreteElement> getFooChildren();

    MyFooConcreteElement addFooChild();
  }

  public interface MyElement extends DomElement {
    @Attribute
    @Required
    GenericAttributeValue<String> getAttr();

    String getValue();

    void setValue(String s);

    MyChildElement getChild();

    @SubTag(value = "child", index = 1)
    MyChildElement getChild2();

    MyChildElement getChild239();

    List<MyElement> getChildElements();

    MyElement addChildElement();

    List<MyAbstractElement> getAbstractElements();

    @SubTagList("abstract-element")
    MyBarConcreteElement addBarChild();

    @SubTagList("abstract-element")
    MyFooConcreteElement addFooChild();

    @SubTagsList({"child-element", "abstract-element"})
    List<MyElement> getCompositeList();

    @SubTagsList(value = {"child-element", "abstract-element"}, tagName = "abstract-element")
    MyBarConcreteElement addBarComposite();

  }

  public interface MyAbstractElement extends MyElement {
  }

  public interface MyFooConcreteElement extends MyAbstractElement {
  }

  public interface MyBarConcreteElement extends MyAbstractElement {
  }


}

@@ -4872,52 +4872,8 @@
 ();%0A
-    assertFalse(file.getNode().isParsed());%0A
   %7D%0A
@@ -5438,52 +5438,8 @@
 s));
-%0A    assertFalse(file.getNode().isParsed());
 %0A%0A  
@@ -5658,52 +5658,8 @@
 ));%0A
-    assertFalse(file.getNode().isParsed());%0A
   %7D%0A

test fixed