/*
 * Copyright 2003-2012 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 org.jetbrains.mps.openapi.module;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
 * A storage for modules. One might think of it as an actual mapping between {@link SModuleId} module ids (which act as keys in the mapping) and {@link SModule}
 * modules themselves.
 *
 * <code>SRepository</code> gains a special access class which gives out a read/write locks to the repository objects.
 * @see #getModelAccess()
 *
 * <p/>
 * REPOSITORY STRUCTURE
 * There can be multiple repositories available. Given a repository, references to modules/models/nodes can be resolved.
 * There's no need in making ids unique globally as each subsystem knows, which exact repository it needs to use at any moment.
 * (e.g. the type-system knows where it stores its type-nodes, so it will not try to resolve references to them )
 * <p/>
 * A repository contains modules, modules have model roots, each model root can load models.
 * Also module can be a models container itself (without model root).
 * A model is then a set of "root" nodes.
 * Each "root" node is a root of a tree of nodes. So that overall, repository is a tree structure.
 * <pre>
 * repository
 *    -module1
 *        model root 1
 *            model1
 *              root_node_1
 *                child_node_1
 *                  child_node_1_1
 *                child_node2
 *        model root 2
 * </pre>
 *
 * Relations between different repositories is in a 'work-in-progress' state at the moment.
 */
public interface SRepository {
  @Deprecated
  // There's no parent repos now, we don't expect them in future.
  // The code written is not supposed to work with multiple repos, there's no code using this method
  SRepository getParent();

  /**
   * @return the module which id is equal to the given module id.
   * A repository is able to have only one module for a given module id.
   * <code>null</code> is returned iff there is no such module in the repository
   */
  @Nullable SModule getModule(@NotNull SModuleId moduleId);

  /**
   * Returns an unmodifiable collection of modules.
   */
  @NotNull Iterable<SModule> getModules();

  /**
   * @return a special class which yields a control to the objects which comprise the repository.
   * These are namely modules, models, model roots, nodes.
   */
  @NotNull ModelAccess getModelAccess();

  @Deprecated
  RepositoryAccess getRepositoryAccess();

  void saveAll();

  /**
   * Register a listener for the repository.
   * If a listener is {@link org.jetbrains.mps.openapi.module.SRepositoryAttachListener}, it gets additionally
   * notified and can perform own initialization (e.g. handle modules already in the repository)
   */
  void addRepositoryListener(@NotNull SRepositoryListener listener);

  /**
   * Remove a listener.
   * If a listener is {@link org.jetbrains.mps.openapi.module.SRepositoryAttachListener}, it is notified of detach event.
   */
  void removeRepositoryListener(@NotNull SRepositoryListener listener);
}
