package jetbrains.mps.lang.structure.pluginSolution.plugin;

/*Generated by MPS */

import jetbrains.mps.refactoring.participant.RefactoringParticipantBase;
import jetbrains.mps.baseLanguage.tuples.runtime.Tuples;
import org.jetbrains.mps.openapi.model.SNodeReference;
import org.jetbrains.mps.openapi.model.SNode;
import jetbrains.mps.refactoring.participant.MoveNodeRefactoringParticipant;
import jetbrains.mps.smodel.structure.Extension;
import org.jetbrains.mps.openapi.language.SAbstractConcept;
import org.jetbrains.mps.openapi.language.SProperty;
import org.jetbrains.mps.openapi.language.SContainmentLink;
import org.jetbrains.mps.openapi.language.SReferenceLink;
import java.util.List;
import jetbrains.mps.refactoring.participant.RefactoringParticipant;
import org.jetbrains.mps.openapi.module.SRepository;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import java.util.ArrayList;
import org.jetbrains.mps.openapi.module.SearchScope;
import java.util.Collection;
import jetbrains.mps.internal.collections.runtime.CollectionSequence;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations;
import jetbrains.mps.ide.findusages.model.SearchResults;
import jetbrains.mps.ide.findusages.model.SearchResult;
import jetbrains.mps.refactoring.participant.RefactoringSession;
import jetbrains.mps.refactoring.participant.NodeCopyTracker;
import jetbrains.mps.internal.collections.runtime.MapSequence;

public class UpdateLocalInstancesParticipant<I, F> extends RefactoringParticipantBase<Tuples._2<I, SNodeReference>, Tuples._2<F, SNodeReference>, SNode, SNode> implements MoveNodeRefactoringParticipant<Tuples._2<I, SNodeReference>, Tuples._2<F, SNodeReference>> {

  private StructureSpecialization<I, F> myStructureSpecialization;
  public UpdateLocalInstancesParticipant(StructureSpecialization<I, F> structureSpecialization) {
    myStructureSpecialization = structureSpecialization;
  }

  public static class UpdateConceptInstances_extension extends Extension.Default<MoveNodeRefactoringParticipant<?, ?>> {
    public UpdateConceptInstances_extension() {
      super("jetbrains.mps.refactoring.participant.MoveNodeParticipantEP");
    }
    public MoveNodeRefactoringParticipant<?, ?> get() {
      return new UpdateLocalInstancesParticipant<SAbstractConcept, SAbstractConcept>(new MoveAbstractConceptSpecialization());
    }
  }
  public static class UpdatePropertyInstances_extension extends Extension.Default<MoveNodeRefactoringParticipant<?, ?>> {
    public UpdatePropertyInstances_extension() {
      super("jetbrains.mps.refactoring.participant.MoveNodeParticipantEP");
    }
    public MoveNodeRefactoringParticipant<?, ?> get() {
      return new UpdateLocalInstancesParticipant<SProperty, SProperty>(new MovePropertySpecialization());
    }
  }
  public static class UpdateContainmentLinkInstances_extension extends Extension.Default<MoveNodeRefactoringParticipant<?, ?>> {
    public UpdateContainmentLinkInstances_extension() {
      super("jetbrains.mps.refactoring.participant.MoveNodeParticipantEP");
    }
    public MoveNodeRefactoringParticipant<?, ?> get() {
      return new UpdateLocalInstancesParticipant<SContainmentLink, SContainmentLink>(new MoveContainmentLinkSpecialization());
    }
  }
  public static class UpdateReferenceLinkInstances_extension extends Extension.Default<MoveNodeRefactoringParticipant<?, ?>> {
    public UpdateReferenceLinkInstances_extension() {
      super("jetbrains.mps.refactoring.participant.MoveNodeParticipantEP");
    }
    public MoveNodeRefactoringParticipant<?, ?> get() {
      return new UpdateLocalInstancesParticipant<SReferenceLink, SReferenceLink>(new MoveReferenceLinkSpecialization());
    }
  }

  public MoveNodeRefactoringParticipant.MoveNodeRefactoringDataCollector<Tuples._2<I, SNodeReference>, Tuples._2<F, SNodeReference>> getDataCollector() {
    return myStructureSpecialization.getLocalInstancesDataCollector();
  }

  public List<RefactoringParticipant.Option> getAvailableOptions(Tuples._2<I, SNodeReference> initialState, SRepository repository) {
    if (initialState != null) {
      return ListSequence.fromListAndArray(new ArrayList<RefactoringParticipant.Option>(), OPTION);
    } else {
      return ListSequence.fromList(new ArrayList<RefactoringParticipant.Option>());
    }
  }
  public static final RefactoringParticipant.Option OPTION = new RefactoringParticipant.Option("moveNode.options.updateLocalInstances", "Update instances in current project");

  public List<RefactoringParticipant.Change<Tuples._2<I, SNodeReference>, Tuples._2<F, SNodeReference>>> getChanges(final Tuples._2<I, SNodeReference> initialState, SRepository repository, List<RefactoringParticipant.Option> selectedOptions, SearchScope searchScope) {
    if (initialState == null || !(ListSequence.fromList(selectedOptions).contains(OPTION))) {
      return ListSequence.fromList(new ArrayList<RefactoringParticipant.Change<Tuples._2<I, SNodeReference>, Tuples._2<F, SNodeReference>>>());
    }
    Collection<SNode> instances = myStructureSpecialization.findInstances(initialState._0(), searchScope);

    return CollectionSequence.fromCollection(instances).select((instance) -> {
      final SNodeReference nodeRef = SNodeOperations.getPointer(instance);
      final SearchResults searchResults = SearchResults.singleton(new SearchResult<SNode>(instance, "instance"));
      RefactoringParticipant.Change<Tuples._2<I, SNodeReference>, Tuples._2<F, SNodeReference>> change = new MoveNodeRefactoringParticipant.ChangeBase<Tuples._2<I, SNodeReference>, Tuples._2<F, SNodeReference>>() {
        public MoveNodeRefactoringParticipant<Tuples._2<I, SNodeReference>, Tuples._2<F, SNodeReference>> getParticipant() {
          return UpdateLocalInstancesParticipant.this;
        }
        public SearchResults getSearchResults() {
          return searchResults;
        }
        public void confirm(final Tuples._2<F, SNodeReference> finalState, final SRepository repository, final RefactoringSession refactoringSession) {
          refactoringSession.registerChange(() -> {
            SNode node = nodeRef.resolve(repository);
            NodeCopyTracker copyMap = NodeCopyTracker.get(refactoringSession);
            if (node == null || MapSequence.fromMap(copyMap.getCopyMap()).containsKey(node)) {
              myStructureSpecialization.doReplaceInstance(MapSequence.fromMap(copyMap.getCopyMap()).get(node), initialState._0(), finalState._0());
            }
            myStructureSpecialization.doReplaceInstance(node, initialState._0(), finalState._0());
          });
        }
      };
      return change;
    }).toList();
  }

}
