// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.openapi.editor.colors.impl;

import com.intellij.ide.ui.UISettings;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.editor.colors.EditorFontCache;
import com.intellij.openapi.editor.colors.FontPreferences;
import com.intellij.openapi.editor.colors.ModifiableFontPreferences;
import com.intellij.openapi.util.NlsSafe;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.util.SystemProperties;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.List;

@State(name = "DefaultFont", storages = @Storage("editor.xml"))
public final class AppEditorFontOptions implements PersistentStateComponent<AppEditorFontOptions.PersistentFontPreferences> {
  private final FontPreferencesImpl myFontPreferences = new FontPreferencesImpl();

  public AppEditorFontOptions() {
    if (!ApplicationManager.getApplication().isHeadlessEnvironment() || ApplicationManager.getApplication().isUnitTestMode()) {
      myFontPreferences.register(FontPreferences.DEFAULT_FONT_NAME, UISettings.restoreFontSize(FontPreferences.DEFAULT_FONT_SIZE, 1.0f));
    }
  }

  public static class PersistentFontPreferences {
    public int FONT_SIZE = FontPreferences.DEFAULT_FONT_SIZE;
    public @NlsSafe @NotNull String FONT_FAMILY = FontPreferences.DEFAULT_FONT_NAME;
    public @NlsSafe @Nullable String FONT_REGULAR_SUB_FAMILY;
    public @NlsSafe @Nullable String FONT_BOLD_SUB_FAMILY;
    public float FONT_SCALE = 1.0f;
    public float LINE_SPACING = FontPreferences.DEFAULT_LINE_SPACING;
    public boolean USE_LIGATURES = false;
    public @NlsSafe @Nullable String SECONDARY_FONT_FAMILY;

    /**
     * Serialization constructor.
     */
    private PersistentFontPreferences() {
    }

    public PersistentFontPreferences(FontPreferences fontPreferences) {
      FONT_FAMILY = fontPreferences.getFontFamily();
      FONT_REGULAR_SUB_FAMILY = fontPreferences.getRegularSubFamily();
      FONT_BOLD_SUB_FAMILY = fontPreferences.getBoldSubFamily();
      FONT_SIZE = fontPreferences.getSize(FONT_FAMILY);
      FONT_SCALE = UISettings.getDefFontScale();
      LINE_SPACING = fontPreferences.getLineSpacing();
      USE_LIGATURES = fontPreferences.useLigatures();
      List<String> fontFamilies = fontPreferences.getEffectiveFontFamilies();
      if (fontFamilies.size() > 1) {
        SECONDARY_FONT_FAMILY = fontFamilies.get(1);
      }
    }

    private static PersistentFontPreferences getDefaultState() {
      return new PersistentFontPreferences();
    }
  }


  public static AppEditorFontOptions getInstance() {
    return ApplicationManager.getApplication().getService(AppEditorFontOptions.class);
  }

  @Override
  public @NotNull PersistentFontPreferences getState() {
    return new PersistentFontPreferences(myFontPreferences);
  }

  @Override
  public void loadState(@NotNull PersistentFontPreferences state) {
    copyState(state, myFontPreferences);
    myFontPreferences.setChangeListener(() -> EditorFontCache.getInstance().reset());
  }

  private static void copyState(PersistentFontPreferences state, @NotNull ModifiableFontPreferences fontPreferences) {
    fontPreferences.clear();
    int fontSize = UISettings.restoreFontSize(state.FONT_SIZE, state.FONT_SCALE);
    String[] names = migrateFamilyNameIfNeeded(state.FONT_FAMILY, state.FONT_REGULAR_SUB_FAMILY, state.FONT_BOLD_SUB_FAMILY);
    fontPreferences.register(names[0], fontSize);
    fontPreferences.setRegularSubFamily(names[1]);
    fontPreferences.setBoldSubFamily(names[2]);
    fontPreferences.setLineSpacing(state.LINE_SPACING);
    fontPreferences.setUseLigatures(state.USE_LIGATURES);
    if (state.SECONDARY_FONT_FAMILY != null) {
      fontPreferences.register(state.SECONDARY_FONT_FAMILY, fontSize);
    }
  }

  private static String[] migrateFamilyNameIfNeeded(String family, String regularSubFamily, String boldSubFamily) {
    if (SystemInfo.isJetBrainsJvm && SystemProperties.is("new.editor.font.selector")) {
      switch (family) {
        case "Fira Code Light": return new String[] {"Fira Code", "Light", null};
        case "Fira Code Medium": return new String[] {"Fira Code", "Medium", null};
        case "Fira Code Retina": return new String[] {"Fira Code", "Retina", null};
      }
    }
    return new String[] {family, regularSubFamily, boldSubFamily};
  }

  public static void initDefaults(@NotNull ModifiableFontPreferences fontPreferences) {
    copyState(PersistentFontPreferences.getDefaultState(), fontPreferences);
  }

  public @NotNull FontPreferences getFontPreferences() {
    return myFontPreferences;
  }
}

@@ -621,32 +621,91 @@
 ontPreferences;%0A
+import com.intellij.openapi.editor.impl.FontFamilyService;%0A
 import com.intel
@@ -926,16 +926,38 @@
 il.List;
+%0Aimport java.util.Map;
 %0A%0A@State
@@ -4178,24 +4178,409 @@
 %0A    %7D%0A  %7D%0A%0A
+  // Fira Code requires specific migration due to naming workaround in JBR used earlier%0A  private static final Map%3CString, String%5B%5D%3E FIRA_CODE_MIGRATION_MAP = Map.of(%0A    %22Fira Code Light%22, new String%5B%5D %7B%22Fira Code%22, %22Light%22, %22Light%22%7D,%0A    %22Fira Code Medium%22, new String%5B%5D %7B%22Fira Code%22, %22Medium%22, %22Medium%22%7D,%0A    %22Fira Code Retina%22, new String%5B%5D %7B%22Fira Code%22, %22Retina%22, %22Retina%22%7D%0A  );%0A%0A
   private st
@@ -4719,16 +4719,24 @@
 nsJvm &&
+%0A       
  SystemP
@@ -4779,117 +4779,80 @@
 or%22)
-) %7B
+ &&
 %0A      
-switch (family) %7B%0A        case %22Fira Code Light%22: return new String%5B%5D %7B%22Fira Code%22, %22Light%22,
+  regularSubFamily == null &&%0A        boldSubFamily ==
  null
-%7D;
+ &&
 %0A   
@@ -4860,175 +4860,174 @@
     
-case %22Fira Code Medium%22: return new String%5B%5D %7B%22Fira Code%22, %22Medium%22, null%7D;%0A        case %22Fira Code Retina%22: return new String%5B%5D %7B%22Fira Code%22, %22Retina%22, null%7D;%0A      %7D
+FIRA_CODE_MIGRATION_MAP.containsKey(family) &&%0A        !FontFamilyService.getAvailableFamilies().contains(family)) %7B%0A      return FIRA_CODE_MIGRATION_MAP.get(family);
 %0A   

improve font settings migration for Fira Code case (for IDEA-92825)