package com.intellij.openapi.components.impl.stores;


import com.intellij.openapi.components.PathMacroSubstitutor;
import com.intellij.openapi.components.StateStorage;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.vfs.VirtualFile;
import static com.intellij.util.io.fs.FileSystem.FILE_SYSTEM;
import com.intellij.util.io.fs.IFile;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jetbrains.annotations.Nullable;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class FileBasedStorage extends XmlElementStorage {
  private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.components.impl.stores.FileBasedStorage");

  private final String myFilePath;
  private final IFile myFile;
  protected final String myRootElementName;

  public FileBasedStorage(@Nullable PathMacroSubstitutor pathMacroManager, final String filePath, String rootElementName) {
    super(pathMacroManager);
    myRootElementName = rootElementName;
    myFilePath = filePath;
    myFile = FILE_SYSTEM.createFile(myFilePath);
  }

  public void doSave() throws StateStorage.StateStorageException {
    final byte[] text = StorageUtil.printDocument(getDocument());

    StorageUtil.save(myFile, text);
  }

  public boolean needsSave() throws StateStorage.StateStorageException {
    sort();
    try {
      if (!myFile.exists()) return true;

      final byte[] text = StorageUtil.printDocument(getDocument());

      if (Arrays.equals(myFile.loadBytes(), text)) return false;

      return true;
    }
    catch (IOException e) {
      LOG.debug(e);
      return true;
    }
  }

  public List<VirtualFile> getAllStorageFiles() {
    final VirtualFile virtualFile = StorageUtil.getVirtualFile(myFile);
    if (virtualFile != null) return Collections.singletonList(virtualFile);
    return Collections.emptyList();
  }

  @Nullable
  public VirtualFile getVirtualFile() {
    return StorageUtil.getVirtualFile(myFile);
  }


  public IFile getFile() {
    return myFile;
  }

  @Nullable
  protected Document loadDocument() throws StateStorage.StateStorageException {
    try {
      if (!myFile.exists() || myFile.length() == 0) {
        return new Document(new Element(myRootElementName));
      }
      else {
        return JDOMUtil.loadDocument(myFile);
      }
    }
    catch (JDOMException e) {
      throw new StateStorage.StateStorageException(e);
    }
    catch (IOException e) {
      throw new StateStorage.StateStorageException(e);
    }
  }

  public String getFileName() {
    return myFile.getName();
  }

  public String getFilePath() {
    return myFilePath;
  }

  public void setDefaultState(final Element element) {
    element.setName(myRootElementName);
    super.setDefaultState(element);
  }
}

@@ -918,16 +918,54 @@
 entName;
+%0A  private Integer myUpToDateTreeHash;
 %0A%0A  publ
@@ -1296,24 +1296,144 @@
 Exception %7B%0A
+    final Document document = getDocument();%0A%0A    myUpToDateTreeHash = JDOMUtil.getTreeHash(document.getRootElement());%0A
     final by
@@ -1466,37 +1466,32 @@
 intDocument(
-getD
+d
 ocument
-()
 );%0A%0A    Stor
@@ -1607,16 +1607,228 @@
  sort();
+%0A%0A    final Document document = getDocument();%0A    if (myUpToDateTreeHash != null && JDOMUtil.getTreeHash(document.getRootElement()) == myUpToDateTreeHash.intValue()) return false;%0A%0A    myUpToDateTreeHash = null;
 %0A    try
@@ -1924,29 +1924,24 @@
 ocument(
-getD
+d
 ocument
-()
 );%0A%0A    
@@ -1986,16 +1986,104 @@
 , text))
+ %7B%0A        myUpToDateTreeHash = JDOMUtil.getTreeHash(document.getRootElement());%0A       
  return 
@@ -2084,24 +2084,32 @@
 eturn false;
+%0A      %7D
 %0A%0A      retu

save optimization