/** @module refer */

/**
 * Interface for a map that holds component references and passes them to components
 * to establish dependencies with each other.
 * 
 * Together with [[IReferenceable]] and [[IUnreferenceable]] interfaces it implements
 * a Locator pattern that is used by PipServices toolkit for Inversion of Control
 * to assign external dependencies to components. 
 * 
 * The IReferences object is a simple map, where keys are locators
 * and values are component references. It allows to add, remove and find components
 * by their locators. Locators can be any values like integers, strings or component types.
 * But most often PipServices toolkit uses [[Descriptor]] as locators that match
 * by 5 fields: group, type, kind, name and version.
 * 
 * @see [[Descriptor]]
 * @see [[References]]
 * 
 * ### Example ###
 * 
 *     export class MyController implements IReferenceable {
 *         public _persistence: IMyPersistence;
 *         ...    
 *         public setReferences(references: IReferences): void {
 *             this._persistence = references.getOneRequired<IMyPersistence>(
 *                 new Descriptor("mygroup", "persistence", "*", "*", "1.0")
 *             );
 *         }
 *         ...
 *     }
 *     
 *     let persistence = new MyMongoDbPersistence();
 *     
 *     let controller = new MyController();
 *     
 *     let references = References.fromTuples(
 *         new Descriptor("mygroup", "persistence", "mongodb", "default", "1.0"), persistence,
 *         new Descriptor("mygroup", "controller", "default", "default", "1.0"), controller
 *     );
 *     controller.setReferences(references);
 *     
 */
export interface IReferences {
    /**
     * Puts a new reference into this reference map.
     * 
     * @param locator     a locator to find the reference by.
     * @param component a component reference to be added.
     */
    put(locator: any, component: any);

    /**
     * Removes a previously added reference that matches specified locator.
     * If many references match the locator, it removes only the first one.
     * When all references shall be removed, use [[removeAll]] method instead.
     * 
     * @param locator     a locator to remove reference
     * @returns the removed component reference.
     * 
     * @see [[removeAll]]
     */
    remove(locator: any): any;    

    /**
     * Removes all component references that match the specified locator. 
     * 
     * @param locator     the locator to remove references by.
     * @returns a list, containing all removed references.
     */
    removeAll(locator: any): any[];    
    
    /**
     * Gets locators for all registered component references in this reference map.
     * 
     * @returns a list with component locators.
     */
    getAllLocators(): any[];    

    /**
     * Gets all component references registered in this reference map.
     *     
     * @returns a list with component references.
     */
    getAll(): any[];    
        
    /**
     * Gets all component references that match specified locator.
     * 
     * @param locator     the locator to find references by.     
     * @returns a list with matching component references or empty list if nothing was found.
     */
    getOptional<T>(locator: any): T[];

    /**
     * Gets all component references that match specified locator.
     * At least one component reference must be present.
     * If it doesn't the method throws an error.
     * 
     * @param locator     the locator to find references by.     
     * @returns a list with matching component references.
     * 
     * @throws a [[ReferenceException]] when no references found.
     */
    getRequired<T>(locator: any): T[];

    /**
     * Gets an optional component reference that matches specified locator.
     * 
     * @param locator     the locator to find references by.     
     * @returns a matching component reference or null if nothing was found.
     */
    getOneOptional<T>(locator: any): T;
    
    /**
     * Gets a required component reference that matches specified locator.
     * 
     * @param locator     the locator to find a reference by.     
     * @returns a matching component reference.
     * @throws a [[ReferenceException]] when no references found.
     */
    getOneRequired<T>(locator: any): T;

    /**
     * Gets all component references that match specified locator.
     * 
     * @param locator     the locator to find a reference by.
     * @param required     forces to raise an exception if no reference is found.
     * @returns a list with matching component references.
     * 
     * @throws a [[ReferenceException]] when required is set to true but no references found.
     */
    find<T>(locator: any, required: boolean): T[];
}
