/// <summary>
		/// Constructs a instance of remote Closure Compiler
		/// </summary>
		/// <param name="closureCompilerServiceUrl">URL of Google Closure Compiler Service API</param>
		/// <param name="commonExternsDependencies">List of common JS-externs dependencies</param>
		/// <param name="defaultOptions">Default compilation options</param>
		public ClosureRemoteJsCompiler(string closureCompilerServiceUrl,
			DependencyCollection commonExternsDependencies,
			RemoteJsCompilationOptions defaultOptions)
			: base(commonExternsDependencies)
		{
			_closureCompilerServiceUrl = closureCompilerServiceUrl;
			_defaultOptions = defaultOptions;
			_defaultOptionsFormItems = (defaultOptions != null)
				? ConvertCompilationOptionsToFormItems(_defaultOptions) : new List<FormItem>();
		}
        /// <summary>
        /// Creates a compilation options
        /// </summary>
        /// <returns>Compilation options</returns>
        private RemoteJsCompilationOptions CreateCompilationOptions()
        {
            var options = new RemoteJsCompilationOptions
            {
                ExcludeDefaultExterns = ExcludeDefaultExterns,
                Language = Language
            };

            FillJsCompilationOptions(options);

            return(options);
        }
		/// <summary>
		/// "Compiles" a JS-code
		/// </summary>
		/// <param name="content">Text content written on JavaScript</param>
		/// <param name="path">Path to JS-file</param>
		/// <param name="externsDependencies">List of JS-externs dependencies</param>
		/// <param name="options">Compilation options</param>
		/// <returns>Compiled JS-code</returns>
		public string Compile(string content, string path, DependencyCollection externsDependencies,
			RemoteJsCompilationOptions options = null)
		{
			string newContent;
			DependencyCollection allExternsDependencies = new DependencyCollection();
			RemoteJsCompilationOptions currentOptions;
			IList<FormItem> currentOptionsFormItems;

			if (options != null)
			{
				currentOptions = options;
				currentOptionsFormItems = ConvertCompilationOptionsToFormItems(currentOptions);
			}
			else
			{
				currentOptions = _defaultOptions;
				currentOptionsFormItems = _defaultOptionsFormItems;
			}

			var formItems = new List<FormItem>();
			formItems.Add(new FormItem("js_code", content));
			if (currentOptions.CompilationLevel == CompilationLevel.Advanced
				&& (_commonExternsDependencies.Count > 0 || externsDependencies.Count > 0))
			{
				allExternsDependencies.AddRange(_commonExternsDependencies);

				foreach (Dependency externsDependency in externsDependencies)
				{
					if (!_commonExternsDependencies.ContainsUrl(externsDependency.Url))
					{
						allExternsDependencies.Add(externsDependency);
					}
				}

				foreach (Dependency externsDependency in allExternsDependencies)
				{
					formItems.Add(new FormItem("js_externs", externsDependency.Content));
				}
			}
			formItems.AddRange(currentOptionsFormItems);

			HttpContent httpContent = new CustomFormUrlEncodedContent(formItems);

			using (var client = new HttpClient())
			{
				HttpResponseMessage response;
				try
				{
					response = client
						.PostAsync(new Uri(_closureCompilerServiceUrl), httpContent)
						.Result
						;
				}
				catch (AggregateException e)
				{
					Exception innerException = e.InnerException;
					if (innerException != null)
					{
						if (innerException is HttpRequestException)
						{
							throw new Exception(
								string.Format(Strings.Minifiers_ClosureRemoteMinificationHttpRequestError,
									_closureCompilerServiceUrl),
								innerException);
						}

						throw innerException;
					}

					throw;
				}

				if (response.IsSuccessStatusCode)
				{
					var result = response.Content.ReadAsStringAsync().Result;
					var json = JObject.Parse(result);

					var serverErrors = json["serverErrors"] != null ? json["serverErrors"] as JArray : null;
					if (serverErrors != null && serverErrors.Count > 0)
					{
						throw new ClosureCompilingException(
							FormatErrorDetails(serverErrors[0], ErrorType.ServerError, path, allExternsDependencies)
						);
					}

					var errors = json["errors"] != null ? json["errors"] as JArray : null;
					if (errors != null && errors.Count > 0)
					{
						throw new ClosureCompilingException(
							FormatErrorDetails(errors[0], ErrorType.Error, path, allExternsDependencies)
						);
					}

					if (currentOptions.Severity > 0)
					{
						var warnings = json["warnings"] != null ? json["warnings"] as JArray : null;
						if (warnings != null && warnings.Count > 0)
						{
							throw new ClosureCompilingException(
								FormatErrorDetails(warnings[0], ErrorType.Warning, path, allExternsDependencies)
							);
						}
					}

					newContent = json.Value<string>("compiledCode");
				}
				else
				{
					throw new AssetMinificationException(
						string.Format(Strings.Minifiers_ClosureRemoteMinificationInvalidHttpStatus,
							response.StatusCode));
				}
			}

			return newContent;
		}
		/// <summary>
		/// Converts a compilation options to form items
		/// </summary>
		/// <param name="options">Compilation options</param>
		/// <returns>Form items</returns>
		private static IList<FormItem> ConvertCompilationOptionsToFormItems(RemoteJsCompilationOptions options)
		{
			int severity = options.Severity;

			var formItems = new List<FormItem>();
			formItems.Add(new FormItem("output_format", "json"));
			formItems.Add(new FormItem("output_info", "compiled_code"));
			formItems.Add(new FormItem("output_info", "errors"));
			if (!string.IsNullOrWhiteSpace(options.Charset))
			{
				formItems.Add(new FormItem("charset", options.Charset));
			}
			formItems.Add(new FormItem("compilation_level", ConvertCompilationLevelEnumValueToCode(options.CompilationLevel)));
			formItems.Add(new FormItem("exclude_default_externs", options.ExcludeDefaultExterns.ToString().ToLowerInvariant()));
			if (options.Language != LanguageSpec.None)
			{
				formItems.Add(new FormItem("language", ConvertLanguageSpecEnumValueToCode(options.Language)));
			}
			if (options.PrettyPrint)
			{
				formItems.Add(new FormItem("formatting", "PRETTY_PRINT"));
			}
			formItems.Add(new FormItem("use_types_for_optimization", options.UseTypesForOptimization.ToString().ToLowerInvariant()));
			if (severity > 0)
			{
				formItems.Add(new FormItem("output_info", "warnings"));

				switch (severity)
				{
					case 1:
						formItems.Add(new FormItem("warning_level", "QUIET"));
						break;
					case 2:
						formItems.Add(new FormItem("warning_level", "DEFAULT"));
						break;
					case 3:
						formItems.Add(new FormItem("warning_level", "VERBOSE"));
						break;
				}
			}

			return formItems;
		}
		/// <summary>
		/// Creates a compilation options
		/// </summary>
		/// <returns>Compilation options</returns>
		private RemoteJsCompilationOptions CreateCompilationOptions()
		{
			var options = new RemoteJsCompilationOptions
			{
				ExcludeDefaultExterns = ExcludeDefaultExterns,
				Language = Language
			};
			FillJsCompilationOptions(options);

			return options;
		}