//==============================================================
//  版权所有：深圳杰文科技
//  文件名：DateSelector.cs
//  版本：V1.0  
//  创建者：Jay  ( QQ： 85363208 )
//  创建时间：2017-11-28 16:18
//  创建描述：
//  修改者：
//  修改时间：
//  修改说明： 
//==============================================================

using System;
using System.ComponentModel;
using System.Drawing;
using System.Text.RegularExpressions;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Controls;
using Infrastructure.Utilities;

namespace Infrastructure.Components
{
	public partial class DateSelector : ComboBoxEdit
	{
		private DateExpandForm expandForm;
		private Color focusColor = SystemColors.Info;
		private Color backColor;

		#region 构造函数

		public DateSelector()
		{
			InitializeComponent();
		}

		public DateSelector(IContainer container)
		{
			container.Add(this);
			InitializeComponent();
		}

		protected override void OnLoaded()
		{
			base.OnLoaded();
			if (ControlUtil.IsDesignMode(this))
			{
				return;
			}

			Init();
		}

		private void Init()
		{
			this.Properties.Buttons.Add(new EditorButton(ButtonPredefines.Delete, "清除日期"));
			this.ButtonClick += new ButtonPressedEventHandler(this.DateSelector_ButtonClick);
			this.Click += (s, e) => ShowExpandForm();

			this.Properties.Mask.AutoComplete = DevExpress.XtraEditors.Mask.AutoCompleteType.Optimistic;
			this.Properties.Mask.EditMask = "\\d{2}\\d{2}?年([1-9]|10|11|12)月(0?[1-9]|[12]\\d|30|31)日 — \\d{2}\\d{2}?年([1-9]|10|11|1" +
				"2)月(0?[1-9]|[12]\\d|30|31)日";
			this.Properties.Mask.MaskType = DevExpress.XtraEditors.Mask.MaskType.RegEx;
			this.Properties.Mask.UseMaskAsDisplayFormat = true;

			this.Properties.TextEditStyle = TextEditStyles.DisableTextEditor; //只读
			this.EnterMoveNextControl = false;
			backColor = this.BackColor;
		}

		#endregion

		#region 显示下拉窗体

		private void DateSelector_QueryPopUp(object sender, CancelEventArgs e)
		{
			e.Cancel = true;
		}

		private void DateSelector_ButtonClick(object sender, ButtonPressedEventArgs e)
		{
			if (e.Button.Index == 0)
			{
				ShowExpandForm();
			}
			else
			{
				this.DateSelectorType = DateSelectorType.All;
			}
		}

		private void ShowExpandForm()
		{
			if (expandForm == null || expandForm.IsDisposed)
			{
				expandForm = new DateExpandForm();
				expandForm.DateChanged += new DateChangedDelegate(expandForm_DateChanged);
			}
			expandForm.dtpBegin.Value = expandForm.dtpBegin.MinDate > StartDate ? expandForm.dtpBegin.MinDate : StartDate;
			expandForm.dtpEnd.Value = expandForm.dtpEnd.MaxDate < EndDate ? expandForm.dtpEnd.MaxDate : (expandForm.dtpBegin.MinDate > EndDate ? expandForm.dtpBegin.MinDate : EndDate);
			expandForm.Location = CalculateLocation(expandForm);
			expandForm.Show();
			expandForm.BringToFront();
		}

		void expandForm_DateChanged(object sender, DateSelectorType dateSelectorType, DateTime beginDate, DateTime endDate)
		{
			DateSelectorType = dateSelectorType;
			if (DateSelectorType == DateSelectorType.Custom)
			{
				this.StartDate = beginDate;
				this.EndDate = endDate;
			}
		}

		//计算DateExpandForm显示的位置
		private Point CalculateLocation(DateExpandForm expandForm)
		{
			Point p = this.PointToScreen(this.Location);
			p.X = p.X - this.Left;
			p.Y = p.Y - this.Top + this.Height;

			int w = System.Windows.Forms.Screen.GetWorkingArea(this).Right;
			if ((p.X + expandForm.Width) > w)
			{
				p.X = p.X - (p.X + expandForm.Width - w);
			}

			return p;
		}

		#endregion

		#region 开始日期和结束日期属性

		public event Action<DateTime, DateTime> DateChanged;

		private void RaiseDateChanged()
		{
			if (DateChanged != null)
			{
				DateChanged(this.StartDate, this.EndDate);
			}
		}

		private DateTime _StartDate = DateTimeUtil.DefaultMinDate;
		[Browsable(true)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		[Bindable(true)]
		public DateTime StartDate
		{
			get
			{
				return _StartDate;
			}
			private set
			{
				_StartDate = value;
				SetText();
			}
		}

		private DateTime _EndDate = DateTimeUtil.DefaultMaxDate;
		[Browsable(true)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		[Bindable(true)]
		public DateTime EndDate
		{
			get
			{
				return _EndDate;
			}
			private set
			{
				if (value > DateTimeUtil.DefaultMinDate &&
					value.Hour == 0 && value.Minute == 0 && value.Second == 0)
				{
					value = value.AddDays(1).AddSeconds(-1);
				}
				_EndDate = value;
				SetText();
			}
		}

		#endregion

		private void SetText()
		{
			if (StartDate == DateTimeUtil.DefaultMinDate && EndDate >= DateTimeUtil.DefaultMaxDate.AddDays(-1))
			{
				this.Text = "";
			}
			else
			{
				this.Text = StartDate.ToString("yyyy年MM月dd日") + " — " + EndDate.ToString("yyyy年MM月dd日");
			}
			RaiseDateChanged();
		}

		#region - 验证日期 -

		//校验输入的日期文本是否正确
		private bool ValidInputDate(string text, out DateTime beginDate, out DateTime endDate, out string error)
		{
			string mask = @"\d{2}\d{2}?年([1-9]|10|11|12)月(0?[1-9]|[12]\d|30|31)日";

			beginDate = DateTime.Now.Date;
			endDate = DateTime.Now.Date;
			error = "";

			if (string.IsNullOrEmpty(text))
			{
				beginDate = DateTimeUtil.DefaultMinDate;
				endDate = DateTimeUtil.DefaultMaxDate;
				return true;
			}

			MatchCollection matchList = Regex.Matches(text, mask);
			if (matchList.Count == 1) //如果只输入了其中一个日期，那么认为用户是想输入当天的日期
			{
				beginDate = DateTime.Parse(matchList[0].Value).Date;
				endDate = beginDate;
				return true;
			}
			else if (matchList.Count != 2)
			{
				return false;
			}

			try
			{
				beginDate = DateTime.Parse(matchList[0].Value).Date;
				endDate = DateTime.Parse(matchList[1].Value).Date;

				if (beginDate > endDate)
				{
					error = "开始日期不能大于结束日期";
					return false;
				}

				return true;
			}
			catch (Exception ex)
			{
#if DEBUG
				error = "日期格式错误：" + ex.Message;
#endif
				return false;
			}
		}

		private void DateSelector_Validating(object sender, CancelEventArgs e)
		{
			//DateTime beginDate;
			//DateTime endDate;
			//string errorMsg;
			//if (ValidInputDate(this.Text, out beginDate, out endDate, out errorMsg))
			//{
			//    this.StartDate = beginDate.Date;
			//    this.EndDate = endDate.Date;
			//    SetText();
			//    e.Cancel = false;
			//}
			//else
			//{
			//    this.ErrorText = errorMsg;
			//    e.Cancel = true;
			//}
		}

		#endregion

		private DateSelectorType _DateSelectorType = DateSelectorType.All;
		public DateSelectorType DateSelectorType
		{
			get
			{
				return _DateSelectorType;
			}
			set
			{
				_DateSelectorType = value;
				SetDateSelectorType(_DateSelectorType);
			}
		}

		private void SetDateSelectorType(DateSelectorType dateSelectorType)
		{
			switch (dateSelectorType)
			{
				case DateSelectorType.Custom:
					break;

				case Components.DateSelectorType.ThreeDays:
					this.StartDate = DateTime.Today.AddDays(-1);
					this.EndDate = DateTime.Today.AddDays(1);
					break;

				case DateSelectorType.LastTwoDays:
					this.StartDate = DateTime.Today.AddDays(-1);
					this.EndDate = DateTime.Today;
					break;

				case DateSelectorType.Yesterday:
					this.StartDate = DateTime.Today.AddDays(-1);
					this.EndDate = DateTime.Today.AddDays(-1);
					break;

				case DateSelectorType.BeforeYesterday:
					this.StartDate = DateTime.Today.AddDays(-2);
					this.EndDate = DateTime.Today.AddDays(-2);
					break;

				case DateSelectorType.All:
					this.StartDate = DateTimeUtil.DefaultMinDate;
					this.EndDate = DateTimeUtil.DefaultMaxDate;
					break;

				case DateSelectorType.CurrentYear:
					this.StartDate = new DateTime(DateTime.Today.Year, 1, 1);
					this.EndDate = new DateTime(DateTime.Today.Year, 12, 31);
					break;

				case DateSelectorType.FirstHalfYear:
					this.StartDate = new DateTime(DateTime.Today.Year, 1, 1);
					this.EndDate = new DateTime(DateTime.Today.Year, 6, 30);
					break;

				case DateSelectorType.NextHalfYear:
					this.StartDate = new DateTime(DateTime.Today.Year, 7, 1);
					this.EndDate = new DateTime(DateTime.Today.Year, 12, 31);
					break;

				case DateSelectorType.CurrentSeason:

					break;

				case DateSelectorType.CurrentMonth:
					this.StartDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
					this.EndDate = DateTimeUtil.GetLastDate(DateTime.Today);
					break;

				case DateSelectorType.RecentMonth1:
					this.StartDate = DateTime.Today.AddMonths(-1);
					this.EndDate = DateTime.Today;
					break;

				case DateSelectorType.RecentMonth2:
					this.StartDate = DateTime.Today.AddMonths(-2);
					this.EndDate = DateTime.Today;
					break;

				case DateSelectorType.RecentMonth3:
					this.StartDate = DateTime.Today.AddMonths(-3);
					this.EndDate = DateTime.Today;
					break;

				case DateSelectorType.RecentHalfYear:
					this.StartDate = DateTime.Today.AddMonths(-6);
					this.EndDate = DateTime.Today;
					break;

				case DateSelectorType.CurrentTenDays:

					int day = DateTime.Today.Day;
					if (day >= 1 && day <= 10) //上旬
					{
						this.StartDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
						this.EndDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 10);
					}
					else if (day >= 11 && day <= 20) //中旬
					{
						this.StartDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 11);
						this.EndDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 20);
					}
					else if (day >= 21) //下旬
					{
						this.StartDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 21);
						this.EndDate = DateTimeUtil.GetLastDate(DateTime.Today);
					}
					break;

				case DateSelectorType.CurrentWeek:
					int week = (int)DateTime.Today.DayOfWeek; //星期天是0，星期一是1，......，星期六是6
					if (week == 0)
					{
						week = 7; //把星期天转为7
					}
					this.StartDate = DateTime.Today.AddDays((week - 1) * -1);
					this.EndDate = DateTime.Today.AddDays((7 - week));
					break;

				case DateSelectorType.Today:
					this.StartDate = DateTime.Today;
					this.EndDate = DateTime.Today;
					break;

				case Components.DateSelectorType.LastTenDays:
					this.StartDate = DateTime.Today.AddDays(-10);
					this.EndDate = DateTime.Today;
					break;

				case Components.DateSelectorType.Tomorrow:
					this.StartDate = DateTime.Today.AddDays(1);
					this.EndDate = DateTime.Today.AddDays(1);
					break;

				case Components.DateSelectorType.AfterTomorrow:
					this.StartDate = DateTime.Today.AddDays(2);
					this.EndDate = DateTime.Today.AddDays(2);
					break;

				case Components.DateSelectorType.LastMonth:
					this.StartDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1).AddMonths(-1);
					this.EndDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1).AddDays(-1);
					break;
			}
		}

		public void ResetControl()
		{
			this.DateSelectorType = DateSelectorType.All;
		}

	}

}
