/**

* @ngdoc object
* @name ui.router.util.$templateFactory
*
* @requires $http
* @requires $templateCache
* @requires $injector
*
* @description
* Service. Manages loading of templates.
*/

$TemplateFactory.$inject = [‘$http’, ‘$templateCache’, ‘$injector’]; function $TemplateFactory( $http, $templateCache, $injector) {

/**
 * @ngdoc function
 * @name ui.router.util.$templateFactory#fromConfig
 * @methodOf ui.router.util.$templateFactory
 *
 * @description
 * Creates a template from a configuration object. 
 *
 * @param {object} config Configuration object for which to load a template. 
 * The following properties are search in the specified order, and the first one 
 * that is defined is used to create the template:
 *
 * @param {string|object} config.template html string template or function to 
 * load via {@link ui.router.util.$templateFactory#fromString fromString}.
 * @param {string|object} config.templateUrl url to load or a function returning 
 * the url to load via {@link ui.router.util.$templateFactory#fromUrl fromUrl}.
 * @param {Function} config.templateProvider function to invoke via 
 * {@link ui.router.util.$templateFactory#fromProvider fromProvider}.
 * @param {object} params  Parameters to pass to the template function.
 * @param {object} locals Locals to pass to `invoke` if the template is loaded 
 * via a `templateProvider`. Defaults to `{ params: params }`.
 *
 * @return {string|object}  The template html as a string, or a promise for 
 * that string,or `null` if no template is configured.
 */
this.fromConfig = function (config, params, locals) {
  return (
    isDefined(config.template) ? this.fromString(config.template, params) :
    isDefined(config.templateUrl) ? this.fromUrl(config.templateUrl, params) :
    isDefined(config.templateProvider) ? this.fromProvider(config.templateProvider, params, locals) :
    null
  );
};

/**
 * @ngdoc function
 * @name ui.router.util.$templateFactory#fromString
 * @methodOf ui.router.util.$templateFactory
 *
 * @description
 * Creates a template from a string or a function returning a string.
 *
 * @param {string|object} template html template as a string or function that 
 * returns an html template as a string.
 * @param {object} params Parameters to pass to the template function.
 *
 * @return {string|object} The template html as a string, or a promise for that 
 * string.
 */
this.fromString = function (template, params) {
  return isFunction(template) ? template(params) : template;
};

/**
 * @ngdoc function
 * @name ui.router.util.$templateFactory#fromUrl
 * @methodOf ui.router.util.$templateFactory
 * 
 * @description
 * Loads a template from the a URL via `$http` and `$templateCache`.
 *
 * @param {string|Function} url url of the template to load, or a function 
 * that returns a url.
 * @param {Object} params Parameters to pass to the url function.
 * @return {string|Promise.<string>} The template html as a string, or a promise 
 * for that string.
 */
this.fromUrl = function (url, params) {
  if (isFunction(url)) url = url(params);
  if (url == null) return null;
  else return $http
      .get(url, { cache: $templateCache, headers: { Accept: 'text/html' }})
      .then(function(response) { return response.data; });
};

/**
 * @ngdoc function
 * @name ui.router.util.$templateFactory#fromProvider
 * @methodOf ui.router.util.$templateFactory
 *
 * @description
 * Creates a template by invoking an injectable provider function.
 *
 * @param {Function} provider Function to invoke via `$injector.invoke`
 * @param {Object} params Parameters for the template.
 * @param {Object} locals Locals to pass to `invoke`. Defaults to 
 * `{ params: params }`.
 * @return {string|Promise.<string>} The template html as a string, or a promise 
 * for that string.
 */
this.fromProvider = function (provider, params, locals) {
  return $injector.invoke(provider, null, locals || { params: params });
};

}

angular.module(‘ui.router.util’).service(‘$templateFactory’, $TemplateFactory);