package com.intellij.codeInsight.daemon.impl;

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.ex.EditorMarkupModel;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.xml.XmlTag;

public class PsiChangeHandler extends PsiTreeChangeAdapter {
  private final Project myProject;
  private final DaemonCodeAnalyzerImpl myDaemonCodeAnalyzer;

  public PsiChangeHandler(Project project, DaemonCodeAnalyzerImpl daemonCodeAnalyzer) {
    myProject = project;
    myDaemonCodeAnalyzer = daemonCodeAnalyzer;
  }

  public void childAdded(PsiTreeChangeEvent event) {
    updateByChange(event.getParent());
  }

  public void childRemoved(PsiTreeChangeEvent event) {
    updateByChange(event.getParent());
  }

  public void childReplaced(PsiTreeChangeEvent event) {
    updateByChange(event.getNewChild());
  }

  public void childrenChanged(PsiTreeChangeEvent event) {
    updateByChange(event.getParent());
  }

  public void beforeChildMovement(PsiTreeChangeEvent event) {
    updateByChange(event.getOldParent());
    updateByChange(event.getNewParent());
  }

  public void propertyChanged(PsiTreeChangeEvent event) {
    String propertyName = event.getPropertyName();
    if (!propertyName.equals(PsiTreeChangeEvent.PROP_WRITABLE)){
      myDaemonCodeAnalyzer.getFileStatusMap().markAllFilesDirty();
      myDaemonCodeAnalyzer.stopProcess(true);
    }
  }

  private void updateByChange(PsiElement child) {
    final Editor editor = FileEditorManager.getInstance(myProject).getSelectedTextEditor();
    if (editor != null) {
      ApplicationManager.getApplication().invokeLater(new Runnable(){
        public void run() {
          EditorMarkupModel markupModel = (EditorMarkupModel) editor.getMarkupModel();
          markupModel.setErrorStripeRenderer(markupModel.getErrorStripeRenderer());
        }
      },ModalityState.stateForComponent(editor.getComponent()));
    }

    PsiFile file = child.getContainingFile();
    if (file == null) {
      myDaemonCodeAnalyzer.getFileStatusMap().markAllFilesDirty();
      return;
    }
    Document document = PsiDocumentManager.getInstance(myProject).getCachedDocument(file);
    if (document == null) return;

    // optimization:
    PsiElement parent = child;
    while (true) {
      if (parent instanceof PsiFile || parent instanceof PsiDirectory) {
        myDaemonCodeAnalyzer.getFileStatusMap().markAllFilesDirty();
        return;
      }
      PsiElement pparent = parent.getParent();
      if(parent instanceof XmlTag){
        //if(!XmlUtil.isInAntBuildFile((XmlFile)parent.getContainingFile())){
          myDaemonCodeAnalyzer.getFileStatusMap().markFileScopeDirty(document, pparent);
          return;
        //}
        //else{
        //  parent = parent.getContainingFile();
        //}
      }
      if (parent instanceof PsiCodeBlock
          && pparent instanceof PsiMethod
          && !((PsiMethod) pparent).isConstructor()
          && pparent.getParent() instanceof PsiClass
          && !(pparent.getParent() instanceof PsiAnonymousClass)) {
        // do not use this optimization for constructors and class initializers - to update non-initialized fields
        myDaemonCodeAnalyzer.getFileStatusMap().markFileScopeDirty(document, pparent);
        return;
      }
      parent = pparent;
    }
  }
}
@@ -403,16 +403,116 @@
 roject;%0A
+import com.intellij.openapi.fileTypes.FileType;%0Aimport com.intellij.openapi.fileTypes.StdFileTypes;%0A
 import c
@@ -2821,24 +2821,31 @@
 etParent();%0A
+      %0A
       if(par
@@ -2880,48 +2880,196 @@
     
-//if(!XmlUtil.isInAntBuildFile((XmlFile)
+PsiElement dirtyScope = pparent;%0A        %0A        if (pparent instanceof XmlTag &&%0A            %22head%22.equals(((XmlTag)pparent).getLocalName())) %7B %0A          final PsiFile containingFile = 
 pare
@@ -3090,19 +3090,17 @@
 ngFile()
-))%7B
+;
 %0A       
@@ -3106,104 +3106,247 @@
     
-myDaemonCodeAnalyzer.getFileStatusMap().markFileScopeDirty(document, pparent);%0A          return;
+final FileType fileType = (containingFile != null)? containingFile.getFileType() : null;%0A          %0A          if (fileType == StdFileTypes.JSP %7C%7C%0A              fileType == StdFileTypes.JSPX %7C%7C%0A              fileType == StdFileTypes.HTML %7C%7C
 %0A   
@@ -3354,74 +3354,312 @@
     
-//%7D%0A
       
-  //else%7B%0A        //  parent = parent.getContainingFile(
+fileType == StdFileTypes.XHTML%0A             ) %7B%0A            // change in head will result in changes for css/javascript code highlighting%0A            dirtyScope = containingFile;%0A          %7D%0A        %7D %0A        %0A        myDaemonCodeAnalyzer.getFileStatusMap().markFileScopeDirty(document, dirtyScope
 );%0A 
@@ -3669,11 +3669,15 @@
     
-//%7D
+return;
 %0A   
@@ -3677,24 +3677,31 @@
 rn;%0A      %7D%0A
+      %0A
       if (pa

change in head in html,jsp, etc marks all file dirty