/*
	$Id: WpfComponents.cs 14 2010-01-06 17:27:40Z catwalk $
*/
using System;
using System.Linq;
using System.Globalization;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Threading;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Net.Cache;
using Hiyoko.Net;
using Hiyoko.Utilities;

namespace Hiyoko.Forms{
	#region コンバーター
	
	/// <summary>
	/// Int32のRGB値からその色のSolidColorBrushへ変換するクラス。
	/// </summary>
	public class Int32ToSolidColorBrushConverter : IValueConverter{
		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){
			int n = (int)value;
			byte r = (byte)((n >> 16) & 0xff);
			byte g = (byte)((n >>  8) & 0xff);
			byte b = (byte)( n		& 0xff);
			return new SolidColorBrush(Color.FromRgb(r, g, b));
		}
		
		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){
			throw new NotImplementedException();
		}
	}
	
	public class DateTimeToStringConverter : IValueConverter{
		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){
			DateTime dt = (DateTime)value;
			return dt.ToString(Program.Settings.DateTimeFormat);
		}
		
		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){
			throw new NotImplementedException();
		}
	}
	
	public class RemoveHtmlTagsConverter : IValueConverter{
		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){
			return Regex.Replace((string)value, @"<.+?>", "");
		}
		
		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){
			throw new NotImplementedException();
		}
	}
	
	public class ExtractUriConverter : IValueConverter{
		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){
			string[] urls = ((string)value).ExtractUrls();
			return (urls.Length > 0) ? urls[0] : "";
		}
		
		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){
			throw new NotImplementedException();
		}
	}
	
	public class StringIsNullOrEmptyConverter : IValueConverter{
		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){
			MessageBox.Show((String)value);
			return String.IsNullOrEmpty((string)value);
		}
		
		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){
			throw new NotImplementedException();
		}
	}
	
	public class UrlToImageSourceConverter : IValueConverter{
		private static readonly HttpRequestCachePolicy policy = new HttpRequestCachePolicy(HttpRequestCacheLevel.CacheIfAvailable);
		
		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){
			string url = (string)value;
			BitmapImage bmp = new BitmapImage();
			bmp.BeginInit();
			bmp.UriCachePolicy = policy;
			bmp.UriSource = new Uri(url, UriKind.RelativeOrAbsolute);
			bmp.EndInit();
			return bmp;
		}
		
		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){
			throw new NotImplementedException();
		}
	}
	
	public class TextToMarkupTextConverter : IValueConverter{
		private static readonly HttpRequestCachePolicy policy = new HttpRequestCachePolicy(HttpRequestCacheLevel.CacheIfAvailable);
		
		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){
			string text = (string)value;
			WrapPanel panel = new WrapPanel();
			{
				Match match = StringEx.UrlRegex.Match(text);
				int last = 0;
				while(match.Success){
					string left = text.Substring(last, match.Index);
					string uri = text.Substring(last, match.Index);
					if(!String.IsNullOrEmpty(left)){
						panel.Children.Add(new TextBlock(){Text=left});
					}
					panel.Children.Add(new LinkText(){Text=uri, OpenUri=uri});
					last = match.Index + match.Length;
					match = match.NextMatch();
				}
				string right = text.Substring(last);
				if(!String.IsNullOrEmpty(right)){
					panel.Children.Add(new TextBlock(){Text=right});
				}
			}
			return panel;
		}
		
		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){
			throw new NotImplementedException();
		}
	}
	
	public class CommandToInputGestureTextConverter : IValueConverter{
		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){
			UIElement elm = Application.Current.MainWindow;
			ICommand cmd = (ICommand)value;
			InputBindingCollection bindings = elm.InputBindings;
			return String.Join(", ", bindings.OfType<KeyBinding>()
			                                 .Where(bin => (bin.Command == cmd))
			                                 .Select(bin => bin.Gesture)
			                                 .Cast<KeyGesture>()
			                                 .Where(ges => !String.IsNullOrEmpty(ges.DisplayString))
			                                 .Select(ges => ges.DisplayString).ToArray());
		}
		
		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){
			throw new NotImplementedException();
		}
	}
	
	public class ExpandUrlsConverter : IValueConverter{
		public UrlShorter UrlShorter{get; set;}
		
		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){
			if(this.UrlShorter != null){
				return this.UrlShorter.ExpandUrlsInText((string)value);
			}else{
				return value;
			}
		}
		
		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){
			if(this.UrlShorter != null){
				return this.UrlShorter.ShortenUrlsInText((string)value);
			}else{
				return value;
			}
		}
	}

	
	#endregion
	
	#region ValidationRule
	
	public class Int32RangeRule : ValidationRule{
		public int Min{get; set;}
		public int Max{get; set;}
		
		public Int32RangeRule(){
			this.Min = Int32.MinValue;
			this.Max = Int32.MaxValue;
		}
		
		public override ValidationResult Validate(object value, CultureInfo cultureInfo){
			int n;
			if(Int32.TryParse((string)value, out n)){
				if((this.Min <= n) && (n <= this.Max)){
					return new ValidationResult(true, null);
				}else{
					return new ValidationResult(false, String.Format("{0} から {1} の数値の範囲で入力してください。", this.Min, this.Max));
				}
			}else{
				return new ValidationResult(false, "数値を入力してください。");
			}
		}
	}
	
	public class IsEmptyStringValidationRule : ValidationRule{
		public IsEmptyStringValidationRule(){
		}
		
		public override ValidationResult Validate(object value, CultureInfo cultureInfo){
			string s = (string)value;
			if(String.IsNullOrEmpty(s)){
				return new ValidationResult(false, "空の文字列は入力できません。");
			}else{
				return new ValidationResult(true, null);
			}
		}
	}
	
	#endregion
	
	#region Behaviour
	
	public static class TextBoxBehaviors{
		public static readonly DependencyProperty IsSelectAllOnFocusProperty =
			DependencyProperty.RegisterAttached("IsSelectAllOnFocus", typeof(bool), typeof(TextBoxBehaviors), new UIPropertyMetadata(false, IsSelectAllOnFocusChanged));
		
		[AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
		public static bool GetIsSelectAllOnFocus(DependencyObject obj){
			return (bool)obj.GetValue(IsSelectAllOnFocusProperty);
		}
		
		[AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
		public static void SetIsSelectAllOnFocus(DependencyObject obj, bool value){
			obj.SetValue(IsSelectAllOnFocusProperty, value);
		}
		
		private static void IsSelectAllOnFocusChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e){
			TextBoxBase textBox = (TextBoxBase)sender;
			
			bool newValue = (bool)e.NewValue;
			bool oldValue = (bool)e.OldValue;
			if(oldValue){
				textBox.GotFocus -= TextBox_GotFocus;
			}
			if(newValue){
				textBox.GotFocus += TextBox_GotFocus;
			}
		}
		
		private static void TextBox_GotFocus(object sender, RoutedEventArgs e){
			TextBoxBase textBox = (TextBoxBase)sender;
			textBox.Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(delegate{
				textBox.SelectAll();
			}));
		}
	}
	
	public class ButtonBehaviors{
		public static readonly DependencyProperty DropDownMenuProperty =
			DependencyProperty.RegisterAttached("DropDownMenu", typeof(ContextMenu), typeof(ButtonBehaviors), new UIPropertyMetadata(null, DropDownMenuChanged));
		
		[AttachedPropertyBrowsableForType(typeof(ButtonBase))]
		public static ContextMenu GetDropDownMenu(DependencyObject obj){
			return (ContextMenu)obj.GetValue(DropDownMenuProperty);
		}
		
		[AttachedPropertyBrowsableForType(typeof(ButtonBase))]
		public static void SetDropDownMenu(DependencyObject obj, bool value){
			if(GetDropDownMenu(obj) == null){
				ButtonBase button = (ButtonBase)obj;
				button.Click += Button_Click;
			}
			obj.SetValue(DropDownMenuProperty, value);
		}
		
		private static void DropDownMenuChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e){
			ButtonBase button = (ButtonBase)sender;
			
			if(e.OldValue == null){
				button.Click += Button_Click;
			}
		}
		
		private static void Button_Click(object sender, RoutedEventArgs e){
			ButtonBase button = (ButtonBase)sender;
			ContextMenu menu = GetDropDownMenu(button);
			if(menu != null){
				menu.PlacementTarget = button;
				menu.Placement = PlacementMode.Bottom; 
				menu.IsOpen = true;
			}
		}
	}
	
	#endregion
}