package org.editorconfig.configmanagement;

import com.intellij.openapi.diagnostic.Logger;
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 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 Logger LOG = Logger.getInstance("#org.editorconfig.codestylesettings.EncodingManager");
    private final Project project;

    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.project = 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;
        // 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(project);
        final String charset = Utils.configValueForKey(outPairs, charsetKey);
        if (!charset.isEmpty()) {
            if (encodingMap.containsKey(charset)) {
                encodingProjectManager.setEncoding(file, encodingMap.get(charset));
                LOG.debug(Utils.appliedConfigMessage(charset, charsetKey, filePath));
            } else {
                LOG.warn(Utils.invalidConfigMessage(charset, charsetKey, filePath));
            }
        }
        isApplyingSettings = false;
    }
}