/*
 * Copyright 2000-2014 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.util.xml;

import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInspection.InspectionManager;
import com.intellij.codeInspection.InspectionProfile;
import com.intellij.codeInspection.InspectionToolProvider;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ex.InspectionToolRegistrar;
import com.intellij.codeInspection.ex.LocalInspectionToolWrapper;
import com.intellij.lang.annotation.Annotation;
import com.intellij.mock.MockInspectionProfile;
import com.intellij.profile.codeInspection.InspectionProfileManager;
import com.intellij.profile.codeInspection.InspectionProfileManagerImpl;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiType;
import com.intellij.psi.xml.XmlElement;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.testFramework.MockSchemesManagerFactory;
import com.intellij.util.xml.highlighting.*;
import com.intellij.util.xml.impl.DefaultDomAnnotator;
import com.intellij.util.xml.impl.DomTestCase;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.Type;
import java.util.ArrayList;

/**
 * @author peter
 */
public class DomHighlightingLiteTest extends DomTestCase {
  private DomElementAnnotationsManagerImpl myAnnotationsManager;
  private MockDomFileElement myElement;
  private MockInspectionProfile myInspectionProfile;

  @Override
  protected void setUp() throws Exception {
    super.setUp();

    final InspectionToolRegistrar registrar = new InspectionToolRegistrar();
    registrar.registerTools(new InspectionToolProvider[0]);
    final InspectionProfileManager inspectionProfileManager = new InspectionProfileManagerImpl(registrar, new MockSchemesManagerFactory());
    myInspectionProfile = new MockInspectionProfile();
    myAnnotationsManager = new DomElementAnnotationsManagerImpl(getProject()) {

      @Override
      protected InspectionProfile getInspectionProfile(final DomFileElement fileElement) {

        return myInspectionProfile;
      }
    };

    final XmlFile file = createXmlFile("<a/>");
    final MockDomElement rootElement = new MockDomElement() {
      @Override
      @Nullable
      public XmlElement getXmlElement() {
        return getXmlTag();
      }

      @Override
      public XmlTag getXmlTag() {
        return file.getRootTag();
      }

      @NotNull
      @Override
      public Type getDomElementType() {
        return DomElement.class;
      }
    };

    myElement = new MockDomFileElement() {
      @Override
      @Nullable
      public XmlElement getXmlElement() {
        return file;
      }

      @Override
      @NotNull
      public XmlFile getFile() {
        return file;
      }

      @Override
      public DomElement getParent() {
        return null;
      }

      @Override
      @NotNull
      public DomElement getRootElement() {
        return rootElement;
      }

      @NotNull
      @Override
      public Class getRootElementClass() {
        return DomElement.class;
      }

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

  @Override
  public void tearDown() throws Exception {
    myAnnotationsManager = null;
    myElement = null;
    myInspectionProfile = null;

    super.tearDown();
  }

  public void testEmptyProblemDescriptorInTheBeginning() throws Throwable {
    assertEmptyHolder(myAnnotationsManager.getProblemHolder(myElement));
  }

  private static void assertEmptyHolder(final DomElementsProblemsHolder holder) {
    assertFalse(holder instanceof DomElementsProblemsHolderImpl);
    assertEmpty(holder.getAllProblems());
  }

  public void testProblemDescriptorIsCreated() throws Throwable {
    myAnnotationsManager.appendProblems(myElement, createHolder(), MyDomElementsInspection.class);
    final DomElementsProblemsHolderImpl holder = assertNotEmptyHolder(myAnnotationsManager.getProblemHolder(myElement));
    assertEmpty(holder.getAllProblems());
    assertEmpty(holder.getAllProblems(new MyDomElementsInspection()));
  }

  private static DomElementAnnotationHolderImpl createHolder() {
    return new DomElementAnnotationHolderImpl(true);
  }

  private static DomElementsProblemsHolderImpl assertNotEmptyHolder(final DomElementsProblemsHolder holder1) {
    return assertInstanceOf(holder1, DomElementsProblemsHolderImpl.class);
  }

  public void testInspectionMarkedAsPassedAfterAppend() throws Throwable {
    myAnnotationsManager.appendProblems(myElement, createHolder(), MyDomElementsInspection.class);
    final DomElementsProblemsHolderImpl holder = (DomElementsProblemsHolderImpl)myAnnotationsManager.getProblemHolder(myElement);
    assertTrue(holder.isInspectionCompleted(MyDomElementsInspection.class));
    assertFalse(holder.isInspectionCompleted(DomElementsInspection.class));
  }

  public void testHolderRecreationAfterChange() throws Throwable {
    myAnnotationsManager.appendProblems(myElement, createHolder(), MyDomElementsInspection.class);
    assertTrue(DomElementAnnotationsManagerImpl.isHolderUpToDate(myElement));
    final DomElementsProblemsHolder holder = myAnnotationsManager.getProblemHolder(myElement);

    myElement.incModificationCount();
    assertFalse(DomElementAnnotationsManagerImpl.isHolderUpToDate(myElement));
    assertSame(holder, myAnnotationsManager.getProblemHolder(myElement));

    myAnnotationsManager.appendProblems(myElement, createHolder(), MyDomElementsInspection.class);
    assertNotSame(holder, assertNotEmptyHolder(myAnnotationsManager.getProblemHolder(myElement)));
  }

  public void testMockDomInspection() throws Throwable {
    myElement.setFileDescription(new MyNonHighlightingDomFileDescription());
    assertInstanceOf(myAnnotationsManager.getMockInspection(myElement), MockDomInspection.class);
  }

  public void testMockAnnotatingDomInspection() throws Throwable {
    myElement.setFileDescription(new DomFileDescription<DomElement>(DomElement.class, "a"));
    assertInstanceOf(myAnnotationsManager.getMockInspection(myElement), MockAnnotatingDomInspection.class);
  }

  public void testNoMockInspection() throws Throwable {
    myElement.setFileDescription(new MyNonHighlightingDomFileDescription());
    myInspectionProfile.setInspectionTools(new LocalInspectionToolWrapper(new MyDomElementsInspection()));
    assertNull(myAnnotationsManager.getMockInspection(myElement));
  }

  public void testDefaultAnnotator() throws Throwable {
    final DefaultDomAnnotator annotator = new DefaultDomAnnotator() {
      @Override
      protected DomElementAnnotationsManagerImpl getAnnotationsManager(final DomElement element) {
        return myAnnotationsManager;
      }
    };
    final StringBuilder s = new StringBuilder();
    final ArrayList<Annotation> toFill = new ArrayList<Annotation>();
    final MyDomElementsInspection inspection = new MyDomElementsInspection() {

      @Override
      public void checkFileElement(final DomFileElement fileElement, final DomElementAnnotationHolder holder) {
        s.append("visited");
      }
    };
    annotator.runInspection(inspection, myElement, toFill);
    assertEquals("visited", s.toString());
    final DomElementsProblemsHolderImpl holder = assertNotEmptyHolder(myAnnotationsManager.getProblemHolder(myElement));
    assertEmpty(toFill);

    annotator.runInspection(inspection, myElement, toFill);
    assertEquals("visited", s.toString());
    assertSame(holder, assertNotEmptyHolder(myAnnotationsManager.getProblemHolder(myElement)));
    assertEmpty(toFill);
  }

  public void testHighlightStatus_MockDomInspection() throws Throwable {
    myElement.setFileDescription(new MyNonHighlightingDomFileDescription());
    assertEquals(DomHighlightStatus.NONE, myAnnotationsManager.getHighlightStatus(myElement));

    myAnnotationsManager.appendProblems(myElement, createHolder(), MockDomInspection.class);
    assertEquals(DomHighlightStatus.INSPECTIONS_FINISHED, myAnnotationsManager.getHighlightStatus(myElement));
  }
  public void testHighlightStatus_MockAnnotatingDomInspection() throws Throwable {
    myElement.setFileDescription(new DomFileDescription<DomElement>(DomElement.class, "a"));

    myAnnotationsManager.appendProblems(myElement, createHolder(), MockAnnotatingDomInspection.class);
    assertEquals(DomHighlightStatus.INSPECTIONS_FINISHED, myAnnotationsManager.getHighlightStatus(myElement));
  }

  public void testHighlightStatus_OtherInspections() throws Throwable {
    myElement.setFileDescription(new DomFileDescription<DomElement>(DomElement.class, "a"));
    final MyDomElementsInspection inspection = new MyDomElementsInspection() {

      @Override
      public ProblemDescriptor[] checkFile(@NotNull final PsiFile file, @NotNull final InspectionManager manager,
                                           final boolean isOnTheFly) {
        myAnnotationsManager.appendProblems(myElement, createHolder(), this.getClass());
        return new ProblemDescriptor[0];
      }

      @Override
      public void checkFileElement(final DomFileElement fileElement, final DomElementAnnotationHolder holder) {
      }
    };
    HighlightDisplayKey.register(inspection.getShortName());
    myInspectionProfile.setInspectionTools(new LocalInspectionToolWrapper(inspection));

    myAnnotationsManager.appendProblems(myElement, createHolder(), MockAnnotatingDomInspection.class);
    assertEquals(DomHighlightStatus.ANNOTATORS_FINISHED, myAnnotationsManager.getHighlightStatus(myElement));

    myAnnotationsManager.appendProblems(myElement, createHolder(), inspection.getClass());
    assertEquals(DomHighlightStatus.INSPECTIONS_FINISHED, myAnnotationsManager.getHighlightStatus(myElement));
  }

  public void testHighlightStatus_OtherInspections2() throws Throwable {
    myElement.setFileDescription(new DomFileDescription<DomElement>(DomElement.class, "a"));
    final MyDomElementsInspection inspection = new MyDomElementsInspection() {

      @Override
      public ProblemDescriptor[] checkFile(@NotNull final PsiFile file, @NotNull final InspectionManager manager,
                                           final boolean isOnTheFly) {
        myAnnotationsManager.appendProblems(myElement, createHolder(), this.getClass());
        return new ProblemDescriptor[0];
      }

      @Override
      public void checkFileElement(final DomFileElement fileElement, final DomElementAnnotationHolder holder) {
      }
    };
    HighlightDisplayKey.register(inspection.getShortName());
    LocalInspectionToolWrapper toolWrapper = new LocalInspectionToolWrapper(inspection);
    myInspectionProfile.setInspectionTools(toolWrapper);
    myInspectionProfile.setEnabled(toolWrapper, false);

    myAnnotationsManager.appendProblems(myElement, createHolder(), MockAnnotatingDomInspection.class);
    assertEquals(DomHighlightStatus.INSPECTIONS_FINISHED, myAnnotationsManager.getHighlightStatus(myElement));
  }

  public void testRequiredAttributeWithoutAttributeValue() throws Throwable {
    final MyElement element = createElement("<a id />", MyElement.class);
    new MyBasicDomElementsInspection().checkDomElement(element.getId(), createHolder(), DomHighlightingHelperImpl.INSTANCE);
  }

  private static class MyDomElementsInspection extends DomElementsInspection<DomElement> {
    public MyDomElementsInspection() {
      super(DomElement.class);
    }

    @Override
    @NotNull
    public String getGroupDisplayName() {
      throw new UnsupportedOperationException("Method getGroupDisplayName is not yet implemented in " + getClass().getName());
    }

    @Override
    @NotNull
    public String getDisplayName() {
      throw new UnsupportedOperationException("Method getDisplayName is not yet implemented in " + getClass().getName());
    }

    @Override
    @NotNull
    public String getShortName() {
      return "xxx";
    }
  }

  private static class MyBasicDomElementsInspection extends BasicDomElementsInspection<DomElement> {
    public MyBasicDomElementsInspection() {
      super(DomElement.class);
    }

    @Override
    @NotNull
    public String getGroupDisplayName() {
      throw new UnsupportedOperationException("Method getGroupDisplayName is not yet implemented in " + getClass().getName());
    }

    @Override
    @NotNull
    public String getDisplayName() {
      throw new UnsupportedOperationException("Method getDisplayName is not yet implemented in " + getClass().getName());
    }

    @Override
    protected void checkDomElement(final DomElement element, final DomElementAnnotationHolder holder, final DomHighlightingHelper helper) {
      super.checkDomElement(element, holder, helper);
    }

    @Override
    @NotNull
    public String getShortName() {
      return "xxx";
    }
  }


  private static class MyNonHighlightingDomFileDescription extends DomFileDescription<DomElement> {
    public MyNonHighlightingDomFileDescription() {
      super(DomElement.class, "a");
    }

    @Override
    public boolean isAutomaticHighlightingEnabled() {
      return false;
    }
  }

  public interface MyElement extends DomElement {
    @Convert(soft=true, value=JvmPsiTypeConverter.class)
    @Required GenericAttributeValue<PsiType> getId();
  }
}
