package org.editorconfig.configmanagement;

import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileDocumentManagerAdapter;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.encoding.EncodingProjectManager;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import org.editorconfig.Utils;
import org.editorconfig.core.EditorConfig.OutPair;
import org.editorconfig.plugincomponents.SettingsProviderComponent;
import org.jetbrains.annotations.NotNull;

import java.nio.charset.Charset;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class EncodingManager extends FileDocumentManagerAdapter {
  // Handles the following EditorConfig settings:
  private static final String charsetKey = "charset";

  private final Project myProject;

  private static final Map<String, Charset> encodingMap;

  static {
    Map<String, Charset> map = new HashMap<String, Charset>();
    map.put("latin1", Charset.forName("ISO-8859-1"));
    map.put("utf-8", Charset.forName("UTF-8"));
    map.put("utf-16be", Charset.forName("UTF-16BE"));
    map.put("utf-16le", Charset.forName("UTF-16LE"));
    encodingMap = Collections.unmodifiableMap(map);
  }

  private boolean isApplyingSettings;

  public EncodingManager(Project project) {
    this.myProject = project;
    isApplyingSettings = false;
  }

  @Override
  public void beforeDocumentSaving(@NotNull Document document) {
    final VirtualFile file = FileDocumentManager.getInstance().getFile(document);
    if (!isApplyingSettings) {
      applySettings(file);
    }
  }

  private void applySettings(VirtualFile file) {
    if (file == null || !file.isInLocalFileSystem()) return;
    if (!Utils.isEnabled(CodeStyleSettingsManager.getInstance(myProject).getCurrentSettings())) return;

    // Prevent "setEncoding" calling "saveAll" from causing an endless loop
    isApplyingSettings = true;
    final String filePath = file.getCanonicalPath();
    final List<OutPair> outPairs = SettingsProviderComponent.getInstance().getOutPairs(filePath);
    final EncodingProjectManager encodingProjectManager = EncodingProjectManager.getInstance(myProject);
    final String charset = Utils.configValueForKey(outPairs, charsetKey);
    if (!charset.isEmpty()) {
      if (encodingMap.containsKey(charset)) {
        encodingProjectManager.setEncoding(file, encodingMap.get(charset));
        Utils.appliedConfigMessage(myProject, charset, charsetKey, filePath);
      }
      else {
        Utils.invalidConfigMessage(myProject, charset, charsetKey, filePath);
      }
    }
    isApplyingSettings = false;
  }
}

@@ -2058,16 +2058,28 @@
 = true;%0A
+    try %7B%0A  
     fina
@@ -2119,24 +2119,26 @@
 icalPath();%0A
+  
     final Li
@@ -2219,24 +2219,26 @@
 (filePath);%0A
+  
     final En
@@ -2330,24 +2330,26 @@
 oject);%0A    
+  
 final String
@@ -2406,16 +2406,18 @@
 etKey);%0A
+  
     if (
@@ -2440,24 +2440,26 @@
 ()) %7B%0A      
+  
 if (encoding
@@ -2482,24 +2482,26 @@
 charset)) %7B%0A
+  
         enco
@@ -2568,24 +2568,26 @@
 ));%0A        
+  
 Utils.applie
@@ -2651,26 +2651,22 @@
 %0A   
-   %7D%0A
      
+%7D
  else %7B%0A
     
@@ -2661,16 +2661,18 @@
  else %7B%0A
+  
         
@@ -2751,16 +2751,38 @@
     
-%7D%0A
+  %7D%0A  
     %7D%0A
+    %7D finally %7B%0A  
     
@@ -2805,18 +2805,24 @@
 gs = false;%0A
+    %7D%0A
   %7D%0A%7D%0A

make sure that applySettings flag doesn't get stuck