/*
 * Copyright 2003-2016 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jetbrains.mps.smodel;

import jetbrains.mps.project.ModuleId;
import jetbrains.mps.project.structure.modules.ModuleReference;
import jetbrains.mps.smodel.SModel.ImportElement;
import jetbrains.mps.smodel.adapter.MetaAdapterByDeclaration;
import jetbrains.mps.smodel.adapter.ids.MetaIdHelper;
import jetbrains.mps.smodel.adapter.ids.SLanguageId;
import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.mps.openapi.language.SLanguage;
import org.jetbrains.mps.openapi.module.SModule;
import org.jetbrains.mps.openapi.module.SModuleReference;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * Auxiliary methods that used to constitute API of smodel.SModel and we no longer want to be there.
 * There's no need to keep old code along with the new one in smodel.SModel as it makes the class way too complicated and hard to maintain.
 * Hence, all the stuff deemed legacy moves here, and uses of that API simply get changed to wrap contemporary model with <code>SModelLegacy</code>
 * instance:
 * <pre>
 *   SModel m = ...;
 *   SModuleReference r = ...;
 *   m.addLanguage(r)  -->  new SModelLegacy(m).addLanguage(r);
 * </pre>
 * Note, use of SModelLegacy is just a quick migration step, it's advised to replace legacy calls with modern alternatives.
 *
 * @author Artem Tikhomirov
 */
public final class SModelLegacy {
  private final SModel myModel;

  public SModelLegacy(@NotNull SModel model) {
    myModel = model;
  }

  public void addLanguage(SModuleReference ref) {
    myModel.addLanguage(MetaAdapterFactory.getLanguage(ref));
  }

  public void addLanguage(Language language) {
    myModel.addLanguage(MetaAdapterByDeclaration.getLanguage(language));
  }

  public void addModelImport(org.jetbrains.mps.openapi.model.SModelReference ref, boolean firstVersion) {
    ImportElement importElement = getImportElement(ref);
    if (importElement != null) {
      return;
    }
    int usedVersion = -1;
    importElement = new ImportElement(ref, -1, firstVersion ? -1 : usedVersion);

    myModel.addModelImport(importElement);
  }

  public List<SModuleReference> importedLanguages() {
    final Collection<SLanguage> usedLanguages = myModel.usedLanguages();
    ArrayList<SModuleReference> rv = new ArrayList<SModuleReference>(usedLanguages.size());
    for (SLanguage l : usedLanguages) {
      final SModule sourceModule = l.getSourceModule();
      if (sourceModule != null) {
        rv.add(sourceModule.getModuleReference());
      }
    }
    return rv;
  }

  public List<SModuleReference> engagedOnGenerationLanguages() {
    final Collection<SLanguage> langs = myModel.getLanguagesEngagedOnGeneration();
    ArrayList<SModuleReference> rv = new ArrayList<>(langs.size());
    for (SLanguage l : langs) {
      rv.add(moduleRefForLanguage(l));
    }
    return rv;
  }


  public void addEngagedOnGenerationLanguage(SModuleReference ref) {
    myModel.addEngagedOnGenerationLanguage(MetaAdapterFactory.getLanguage(ref));
  }

  public void removeEngagedOnGenerationLanguage(SModuleReference ref) {
    myModel.removeEngagedOnGenerationLanguage(MetaAdapterFactory.getLanguage(ref));
  }

  private static SModuleReference moduleRefForLanguage(SLanguage lang) {
    String name = lang.getQualifiedName();
    //todo: this is used in changing "engaged on generation" languages. This should be at least be replaced with
    //"engaged" generators set, so I don't rewrite this code to use SLanguages as it will also be not correct
    //   [artem] I have no idea what the comment above is talking about (comes from 6ccc1cf020c2ee9e093f25ae2e83d977a9410799),
    //   engaged languages would rather cease altogether than got replaced with generators.
    SLanguageId id = MetaIdHelper.getLanguage(lang);
    ModuleId moduleId = ModuleId.regular(id.getIdValue());
    return new ModuleReference(name, moduleId);
  }

  @Nullable
  private ImportElement getImportElement(@NotNull org.jetbrains.mps.openapi.model.SModelReference modelReference) {
    for (ImportElement importElement : myModel.importedModels()) {
      if (importElement.getModelReference().equals(modelReference)) {
        return importElement;
      }
    }
    return null;
  }

}
