content: /*******************************************************************************
   * Copyright (C) 2023, 1C-Soft LLC and others.
   *
   * This program and the accompanying materials are made
   * available under the terms of the Eclipse Public License 2.0
   * which is available at https://www.eclipse.org/legal/epl-2.0/
   *
   * SPDX-License-Identifier: EPL-2.0
   *
   * Contributors:
   *     1C-Soft LLC - initial API and implementation
   *******************************************************************************/
  package com.e1c.v8codestyle.internal.autosort.ui;
  
  import java.util.Map;
  import java.util.concurrent.ConcurrentHashMap;
  import java.util.concurrent.atomic.AtomicBoolean;
  
  import org.eclipse.core.resources.IProject;
  import org.eclipse.core.runtime.Assert;
  import org.eclipse.core.runtime.Status;
  import org.eclipse.core.runtime.jobs.Job;
  import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
  import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
  import org.eclipse.jface.dialogs.MessageDialog;
  import org.eclipse.swt.widgets.Display;
  import org.eclipse.swt.widgets.Shell;
  import org.eclipse.ui.IWorkbenchWindow;
  import org.eclipse.ui.PlatformUI;
  
  import com._1c.g5.v8.dt.core.lifecycle.ProjectContext;
  import com._1c.g5.v8.dt.core.platform.IConfigurationAware;
  import com._1c.g5.v8.dt.core.platform.IDtProject;
  import com._1c.g5.v8.dt.core.platform.IV8Project;
  import com._1c.g5.v8.dt.core.platform.IV8ProjectManager;
  import com._1c.g5.v8.dt.lifecycle.LifecycleParticipant;
  import com._1c.g5.v8.dt.lifecycle.LifecyclePhase;
  import com._1c.g5.v8.dt.lifecycle.LifecycleService;
  import com._1c.g5.v8.dt.md.sort.MdSortPreferences;
  import com.e1c.v8codestyle.autosort.AutoSortPreferences;
  import com.e1c.v8codestyle.autosort.ISortService;
  import com.google.inject.Inject;
  import com.google.inject.Singleton;
  
  /**
   * The notifier of changes in the metadata objects sort preferences to run metadata objects sorting if necessary.
   *
   * @author Almaz Nasibullin
   */
  @Singleton
  @LifecycleService(name = MdSortPreferenceChangeNotifier.SERVICE_NAME)
  public class MdSortPreferenceChangeNotifier
  {
      /**
       * The service name.
       */
      public static final String SERVICE_NAME = "MdSortPreferenceChangeNotifier"; //$NON-NLS-1$
  
      private final Map<IProject, MdSortPreferenceChangeListener> listeners = new ConcurrentHashMap<>();
  
      @Inject
      private ISortService sortService;
  
      @Inject
      private IV8ProjectManager v8ProjectManager;
  
      @LifecycleParticipant(phase = LifecyclePhase.RESOURCE_LOADING, dependsOn = { IV8ProjectManager.SERVICE_NAME })
      public void init(ProjectContext projectContext)
      {
          IDtProject dtProject = projectContext.getProject();
          if (dtProject.getType().equals(IDtProject.WORKSPACE_PROJECT_TYPE))
          {
              IV8Project v8Project = v8ProjectManager.getProject(dtProject);
              if (v8Project instanceof IConfigurationAware)
              {
                  IProject project = dtProject.getWorkspaceProject();
                  MdSortPreferenceChangeListener listener = new MdSortPreferenceChangeListener(project);
                  MdSortPreferences.getPreferences(project).addPreferenceChangeListener(listener);
                  listeners.put(project, listener);
              }
          }
      }
  
      @LifecycleParticipant(phase = LifecyclePhase.RESOURCE_UNLOADING)
      public void dispose(ProjectContext projectContext)
      {
          IDtProject dtProject = projectContext.getProject();
          if (dtProject.getType().equals(IDtProject.WORKSPACE_PROJECT_TYPE))
          {
              IProject project = dtProject.getWorkspaceProject();
              MdSortPreferenceChangeListener listener = listeners.remove(project);
              if (listener != null)
              {
                  MdSortPreferences.getPreferences(project).removePreferenceChangeListener(listener);
              }
          }
      }
  
      private final class MdSortPreferenceChangeListener
          implements IPreferenceChangeListener
      {
          private final IProject project;
          private final AtomicBoolean mdSortPreferenceChanged = new AtomicBoolean(false);
  
          private MdSortPreferenceChangeListener(IProject project)
          {
              this.project = project;
          }
  
          @Override
          public void preferenceChange(PreferenceChangeEvent event)
          {
              String key = event.getKey();
              if ((MdSortPreferences.ASCENDING_SORT.equals(key) || MdSortPreferences.NATURAL_SORT_ORDER.equals(key))
                  && AutoSortPreferences.isAutoSortEnabled(project))
              {
                  boolean askToSortMetadataObjects = mdSortPreferenceChanged.compareAndSet(false, true);
                  if (askToSortMetadataObjects)
                  {
                      Job job = Job.create(Messages.MdSortPreferenceChangeListener_Job_name, monitor -> {
                          Assert.isTrue(mdSortPreferenceChanged.compareAndSet(true, false));
                          startSortAllMetadataObjectsIfNecessary();
                          return Status.OK_STATUS;
                      });
                      // run job with delay if few settings have changed in one moment
                      job.schedule(500);
                  }
              }
          }
  
          private void startSortAllMetadataObjectsIfNecessary()
          {
              Display.getDefault().syncExec(() -> {
                  IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
                  Shell shell = activeWorkbenchWindow != null ? activeWorkbenchWindow.getShell() : null;
                  if (shell != null
                      && MessageDialog.openQuestion(shell, Messages.MdSortPreferenceChangeListener_Sort_question_title,
                          Messages.MdSortPreferenceChangeListener_Sort_question))
                  {
                      sortService.startSortAllMetadata(project);
                  }
              });
          }
      }
  }
  