﻿using System;
using System.Threading;
using ZKWebStandard.Collections;
using ZKWebStandard.Web.Mock;

namespace ZKWebStandard.Web {
	/// <summary>
	/// Http manager<br/>
	/// Http管理器<br/>
	/// </summary>
	public static class HttpManager {
		/// <summary>
		/// Get using http context<br/>
		/// Throw exception if not exist<br/>
		/// 获取当前的Http上下文<br/>
		/// 如果不存在则抛出例外<br/>
		/// </summary>
		/// <example>
		/// <code language="cs">
		/// var context = HttpManager.CurrentContext;
		/// </code>
		/// </example>
		public static IHttpContext CurrentContext {
			get {
				var context = currentContext.Value;
				if (context == null) {
#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one 
#pragma warning disable S2372 // Exceptions should not be thrown from property getters
					throw new ArgumentNullException("Context does not exists");
#pragma warning restore S2372 // Exceptions should not be thrown from property getters
#pragma warning restore S3928 // Parameter names used into ArgumentException constructors should match an existing one 
				}
				return context;
			}
		}
		private static ThreadLocal<IHttpContext> currentContext = new ThreadLocal<IHttpContext>();
		/// <summary>
		/// Determines if there a http context is using<br/>
		/// 检测当前是否有Http上下文<br/>
		/// </summary>
		public static bool CurrentContextExists { get { return currentContext.Value != null; } }

		/// <summary>
		/// Override using http context<br/>
		/// Restore to previous context after disposed<br/>
		/// 重载当前的Http上下文<br/>
		/// Dispose后恢复为原来的上下文<br/>
		/// </summary>
		/// <param name="context">Http context</param>
		/// <returns></returns>
		/// <example>
		/// <code language="cs">
		/// var context = new MyContext();
		/// using (HttpManager.OverrideContext(context)) {
		/// }
		/// </code>
		/// </example>
		public static IDisposable OverrideContext(IHttpContext context) {
			var original = currentContext.Value;
			currentContext.Value = context;
			return new SimpleDisposable(() => {
				// check again to avoid gc dispose
				if (currentContext.Value == context) {
					currentContext.Value = original;
				}
			});
		}

		/// <summary>
		/// Override using http context<br/>
		/// Restore to previous context after disposed<br/>
		/// 重载当前的Http上下文<br/>
		/// Dispose后恢复为原来的上下文<br/>
		/// </summary>
		/// <param name="pathAndQuery">Path and query, "/" will be automatic added to front if needed</param>
		/// <param name="method">Method, GET or POST</param>
		/// <returns></returns>
		/// <example>
		/// <code language="cs">
		/// using (HttpManager.OverrideContext("abc", "GET")) {
		/// }
		/// </code>
		/// </example>
		public static IDisposable OverrideContext(string pathAndQuery, string method) {
			return OverrideContext(new HttpContextMock(pathAndQuery, method));
		}
	}
}
