/// <summary>
		/// Constructs a instance of LESS-import
		/// </summary>
		/// <param name="url">URL of imported stylesheet file</param>
		/// <param name="importOptions">Import options</param>
		public LessImport(string url, LessImportOptions importOptions)
		{
			Url = url;
			ImportOptions = importOptions;
		}
		/// <summary>
		/// Process a LESS <code>@import</code> rule
		/// </summary>
		/// <param name="parentAssetUrl">URL of parent LESS-asset file</param>
		/// <param name="assetUrl">URL of LESS-asset file</param>
		/// <param name="assetImportTypes">List of import types</param>
		/// <param name="quote">Quote</param>
		/// <param name="processedImport">Processed LESS-import</param>
		/// <returns>Processed LESS <code>@import</code> rule</returns>
		private string ProcessImportRule(string parentAssetUrl, string assetUrl,
			IEnumerable<string> assetImportTypes, string quote, out LessImport processedImport)
		{
			string result;
			processedImport = null;
			string extension = Path.GetExtension(assetUrl);

			if (UrlHelpers.StartsWithDataUriScheme(assetUrl))
			{
				result = string.Format(IMPORT_RULE_FORMAT, string.Empty, quote, assetUrl);

				return result;
			}

			if (UrlHelpers.StartsWithProtocol(assetUrl))
			{
				result = string.Format(IMPORT_RULE_FORMAT, string.Empty, quote, assetUrl);
				processedImport = new LessImport(assetUrl, new LessImportOptions(extension));

				return result;
			}

			var importOptions = new LessImportOptions(extension);
			var importTypes = new List<string>();

			foreach (string importType in assetImportTypes)
			{
				switch (importType)
				{
					case Constants.ImportType.Less:
						importOptions.Less = true;
						break;
					case Constants.ImportType.Css:
						importOptions.Less = false;
						break;
					case Constants.ImportType.Multiple:
						importOptions.Multiple = true;
						break;
					case Constants.ImportType.Once:
						importOptions.Multiple = false;
						break;
					case Constants.ImportType.Inline:
						importOptions.Inline = true;
						break;
					case Constants.ImportType.Reference:
						importOptions.Reference = true;
						break;
					case Constants.ImportType.Optional:
						importOptions.Optional = true;
						break;
				}

				importTypes.Add(importType);
			}

			string absoluteUrl = _relativePathResolver.ResolveRelativePath(parentAssetUrl, assetUrl);

			if (!LessFileExtensionHelpers.IsLess(extension)
				&& !CoreFileExtensionHelpers.IsCss(extension))
			{
				string newExtension;
				if (importOptions.Less)
				{
					newExtension = Constants.FileExtension.Less;
				}
				else
				{
					newExtension = Core.Constants.FileExtension.Css;
					importTypes.Remove(newExtension);
				}

				absoluteUrl += newExtension;
			}

			string typeList = (importTypes.Count > 0) ?
				string.Format("({0}) ", string.Join(", ", importTypes)) : string.Empty;

			result = string.Format(IMPORT_RULE_FORMAT, typeList, quote, absoluteUrl);
			processedImport = new LessImport(absoluteUrl, importOptions);

			return result;
		}
		/// <summary>
		/// Gets a LESS-stylesheet by URL
		/// </summary>
		/// <param name="assetUrl">URL to asset file</param>
		/// <param name="assetImportOptions">Import options</param>
		/// <returns>LESS-stylesheet</returns>
		private LessStylesheet GetLessStylesheet(string assetUrl,
			LessImportOptions assetImportOptions)
		{
			string key = GenerateLessStylesheetCacheItemKey(assetUrl);
			LessStylesheet stylesheet;

			if (_lessStylesheetCache.ContainsKey(key))
			{
				stylesheet = _lessStylesheetCache[key];
			}
			else
			{
				string assetContent = _virtualFileSystemWrapper.GetFileTextContent(assetUrl);
				stylesheet = PreprocessStylesheet(assetContent, assetUrl, assetImportOptions);

				_lessStylesheetCache.Add(key, stylesheet);
			}

			return stylesheet;
		}
		/// <summary>
		/// Preprocess a stylesheet content
		/// </summary>
		/// <param name="assetContent">Text content of LESS-asset</param>
		/// <param name="assetUrl">URL of LESS-asset file</param>
		/// <param name="assetImportOptions">Import options</param>
		/// <returns>Preprocessed text content of LESS-asset</returns>
		public LessStylesheet PreprocessStylesheet(string assetContent, string assetUrl,
			LessImportOptions assetImportOptions)
		{
			var stylesheet = new LessStylesheet(assetUrl, assetContent);

			int contentLength = assetContent.Length;
			if (contentLength == 0)
			{
				return stylesheet;
			}

			MatchCollection importRuleMatches = _lessImportRuleRegex.Matches(assetContent);
			MatchCollection dataUriFunctionMatches = _dataUriFunctionRegex.Matches(assetContent);
			MatchCollection urlRuleMatches = null;
			if (assetImportOptions.Inline)
			{
				urlRuleMatches = CommonRegExps.CssUrlRuleRegex.Matches(assetContent);
			}

			if (importRuleMatches.Count == 0 && dataUriFunctionMatches.Count == 0
				&& (urlRuleMatches == null || urlRuleMatches.Count == 0))
			{
				return stylesheet;
			}

			var nodeMatches = new List<LessNodeMatch>();

			foreach (Match importRuleMatch in importRuleMatches)
			{
				var nodeMatch = new LessNodeMatch(importRuleMatch.Index,
					importRuleMatch.Length,
					LessNodeType.ImportRule,
					importRuleMatch);
				nodeMatches.Add(nodeMatch);
			}

			foreach (Match dataUriFunctionMatch in dataUriFunctionMatches)
			{
				var nodeMatch = new LessNodeMatch(dataUriFunctionMatch.Index,
					dataUriFunctionMatch.Length,
					LessNodeType.DataUriFunction,
					dataUriFunctionMatch);
				nodeMatches.Add(nodeMatch);
			}

			if (urlRuleMatches != null)
			{
				foreach (Match urlRuleMatch in urlRuleMatches)
				{
					var nodeMatch = new LessNodeMatch(urlRuleMatch.Index,
						urlRuleMatch.Length,
						LessNodeType.UrlRule,
						urlRuleMatch);
					nodeMatches.Add(nodeMatch);
				}
			}

			MatchCollection multilineCommentMatches;
			if (assetImportOptions.Less)
			{
				multilineCommentMatches = CommonRegExps.CStyleMultilineCommentRegex.Matches(assetContent);
			}
			else
			{
				multilineCommentMatches = CommonRegExps.CssMultilineCommentRegex.Matches(assetContent);
			}

			foreach (Match multilineCommentMatch in multilineCommentMatches)
			{
				var nodeMatch = new LessNodeMatch(multilineCommentMatch.Index,
					multilineCommentMatch.Length,
					LessNodeType.MultilineComment,
					multilineCommentMatch);
				nodeMatches.Add(nodeMatch);
			}

			nodeMatches = nodeMatches
				.OrderBy(n => n.Position)
				.ThenByDescending(n => n.Length)
				.ToList()
				;

			var contentBuilder = new StringBuilder();
			int endPosition = contentLength - 1;
			int currentPosition = 0;

			foreach (LessNodeMatch nodeMatch in nodeMatches)
			{
				LessNodeType nodeType = nodeMatch.NodeType;
				int nodePosition = nodeMatch.Position;
				Match match = nodeMatch.Match;

				if (nodePosition < currentPosition)
				{
					continue;
				}

				if (nodeType == LessNodeType.ImportRule || nodeType == LessNodeType.DataUriFunction
					|| nodeType == LessNodeType.UrlRule)
				{
					ProcessOtherContent(contentBuilder, assetContent,
						ref currentPosition, nodePosition);

					int startLinePosition;
					int endLinePosition;
					string currentLine = SourceCodeNavigator.GetCurrentLine(assetContent, nodePosition,
						out startLinePosition, out endLinePosition);
					int localNodePosition = nodePosition - startLinePosition;

					if (StylesheetHelpers.IncludedInSinglelineComment(currentLine, localNodePosition))
					{
						int nextPosition = (endLinePosition < endPosition) ? endLinePosition + 1 : endPosition;

						ProcessOtherContent(contentBuilder, assetContent,
							ref currentPosition, nextPosition);
						continue;
					}

					if (nodeType == LessNodeType.ImportRule)
					{
						GroupCollection importRuleGroups = match.Groups;

						string url = importRuleGroups["url"].Value.Trim();
						string quote = importRuleGroups["quote"].Success ?
							importRuleGroups["quote"].Value : @"""";
						string typeList = importRuleGroups["typeList"].Value;
						IList<string> types = Utils.ConvertToStringCollection(typeList, ',',
							trimItemValues: true, removeEmptyItems: true);
						LessImport processedImport;

						string importRule = match.Value;
						string processedImportRule = ProcessImportRule(assetUrl, url, types, quote,
							out processedImport);

						if (processedImport != null)
						{
							var imports = stylesheet.Imports;
							LessImportOptions importOptions = processedImport.ImportOptions;
							string urlInUpperCase = processedImport.Url.ToUpperInvariant();

							if (imports.Count(i => i.Url.ToUpperInvariant() == urlInUpperCase
								&& i.ImportOptions == importOptions) == 0)
							{
								imports.Add(processedImport);
							}
						}

						contentBuilder.Append(processedImportRule);
						currentPosition += importRule.Length;
					}
					else if (nodeType == LessNodeType.DataUriFunction)
					{
						GroupCollection dataUriFunctionGroups = match.Groups;

						string url = dataUriFunctionGroups["url"].Value.Trim();
						string mimeType = dataUriFunctionGroups["mimeType"].Value;
						string processedDataUriFunctionAssetUrl;

						string dataUriFunction = match.Value;
						string processedDataUriFunction = ProcessDataUriFunction(assetUrl, url, mimeType,
							out processedDataUriFunctionAssetUrl);

						if (!string.IsNullOrWhiteSpace(processedDataUriFunctionAssetUrl))
						{
							var dataUriFunctionAssetUrls = stylesheet.DataUriFunctionAssetUrls;
							string urlInUpperCase = processedDataUriFunctionAssetUrl.ToUpperInvariant();

							if (dataUriFunctionAssetUrls.Count(u => u.ToUpperInvariant() == urlInUpperCase) == 0)
							{
								dataUriFunctionAssetUrls.Add(processedDataUriFunctionAssetUrl);
							}
						}

						contentBuilder.Append(processedDataUriFunction);
						currentPosition += dataUriFunction.Length;
					}
					else if (nodeType == LessNodeType.UrlRule)
					{
						GroupCollection urlRuleGroups = match.Groups;

						string url = urlRuleGroups["url"].Value.Trim();
						string quote = urlRuleGroups["quote"].Success ?
							urlRuleGroups["quote"].Value : string.Empty;

						string urlRule = match.Value;
						string processedUrlRule = ProcessUrlRule(assetUrl, url, quote);

						contentBuilder.Append(processedUrlRule);
						currentPosition += urlRule.Length;
					}
				}
				else if (nodeType == LessNodeType.MultilineComment)
				{
					int nextPosition = nodePosition + match.Length;

					ProcessOtherContent(contentBuilder, assetContent,
						ref currentPosition, nextPosition);
				}
			}

			if (currentPosition > 0 && currentPosition <= endPosition)
			{
				ProcessOtherContent(contentBuilder, assetContent,
					ref currentPosition, endPosition + 1);
			}

			stylesheet.Content = contentBuilder.ToString();

			return stylesheet;
		}