var providers = {};

/**
 * Central instance managing all services and providers
 */
(function(p) {


  // Point to public container
  var $this = $(this);
  /* Map of services and providers
  
     Example:
     providers = {
       "service1": {
         "provider1": [active, overridden1, ...]
       }
     }
  */
  var providers = {};
  
  /*
   * Retrieves all providers for a service
   */
  this.getProviders = function(serviceName) {
  
    var serviceProviders = {};
  
    if (serviceName in providers) {
    
      for (var providerName in providers[serviceName]) {
      
        // Only return the most recently added provider
        serviceProviders[providerName] = providers[serviceName][providerName][0];
      }
    }
    
    return serviceProviders;
  };
  
  /*
   * Retrieves a single provider for a service
   */
  this.getProvider = function(serviceName, providerName) {
  
    try { return providers[serviceName][providerName][0]; }
    catch (e) { return null; }
  };
  
  /*
   * Adds a new provider for a service
   * 
   * Existing providers with the same name for the same service will be
   * overriden and can be restored by removing the most recently added provider
   */
  this.addProvider = function(serviceName, providerName, provider) {
  
    // Create service container if necessary
    if (!(serviceName in providers)) {
    
      providers[serviceName] = {};
      //$this.trigger("serviceAdded", [serviceName]);
    }
    
    // Create provider list if necessary
    if (!(providerName in providers[serviceName])) {
    
      providers[serviceName][providerName] = [];
    }
    
    providers[serviceName][providerName].unshift(provider);

    var providerAddedEvent = new jQuery.Event("providerAdded");
    providerAddedEvent.serviceName = serviceName;
    providerAddedEvent.providerName = providerName;
    providerAddedEvent.provider = provider;

    $this.trigger(providerAddedEvent);
  };
  
  /*
   * Removes a provider from a service
   */
  this.removeProvider = function(serviceName, providerName, provider) {
  
    // Do nothing if there is no such service or provider name
    if (!(serviceName in providers) ||
        !(providerName in providers[serviceName])) {
    
      return;
    }
    
    // Find the requested provider
    var i = providers[serviceName][providerName].indexOf(provider);
    
    if (i > -1) {
    
      providers[serviceName][providerName].splice(i, 1);

      var providerRemovedEvent = new jQuery.Event("providerRemoved");
      providerRemovedEvent.serviceName = serviceName;
      providerRemovedEvent.providerName = providerName;
      providerRemovedEvent.provider = provider;

      $this.trigger(providerRemovedEvent);
    
      // Clean up if possible
      if (providers[serviceName][providerName].length == 0) {
      
        delete providers[serviceName][providerName];
      }
      
      if (Object.keys(providers[serviceName]).length == 0) {
      
        delete providers[serviceName];
      }
    }
  };
  
  this.toString = function() {
  
    return "[object ProviderManager]";
  };
}).call(providers);
