/*
*/
using System;
using System.Windows;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.IO;
using System.Reflection;
using System.Linq;

namespace Hiyoko.Themes{
	public class ThemeManager : IDisposable{
		private ITheme currentTheme = null;
		private ITheme[] themes;
		public ResourceDictionary resources = new ResourceDictionary();
		private HashSet<ResourceDictionary> targets = new HashSet<ResourceDictionary>();
		
		public ThemeManager(){
		}
		
		public void Attach(ResourceDictionary target){
			target.MergedDictionaries.Add(this.resources);
			this.targets.Add(this.resources);
		}
		
		public void Detach(ResourceDictionary target){
			target.MergedDictionaries.Remove(this.resources);
			this.targets.Remove(this.resources);
		}
		
		public void LoadThemes(string dir){
			this.themes = new List<ITheme>(GetThemes(dir)).ToArray();
		}
		
		public static IEnumerable<ITheme> GetThemes(string dir){
			foreach(var asm in GetAssemblies(dir)){
				foreach(var type in GetThemeTypes(asm)){
					yield return (ITheme)Activator.CreateInstance(type);
				}
			}
		}
		
		private static IEnumerable<Assembly> GetAssemblies(string dir){
			yield return Assembly.GetExecutingAssembly();
			string[] files = null;
			try{
				files = Directory.GetFiles(dir, "*.dll");
			}catch{
			}
			if(files != null){
				foreach(string file in files){
					Assembly asm;
					try{
						asm = Assembly.LoadFile(file);
					}catch(FileLoadException){
						continue;
					}catch(BadImageFormatException){
						continue;
					}
					yield return asm;
				}
			}
		}
		
		private static IEnumerable<Type> GetThemeTypes(Assembly asm){
			Type[] types;
			try{
				types = asm.GetTypes();
			}catch(ReflectionTypeLoadException ex){
				types = ex.Types;
			}
			foreach(Type type in types){
				if(type != null){
					if(type.IsPublic && type.IsClass && !type.IsAbstract && (Array.IndexOf(type.GetInterfaces(), typeof(ITheme)) >= 0)){
						yield return type;
					}
				}
			}
		}
		
		public ITheme CurrentTheme{
			get{
				return this.currentTheme;
			}
			set{
				if(value == null){
					this.resources.MergedDictionaries.Clear();
					this.currentTheme = value;
				}else{
					var res = value.Resources;
					if(res != null){
						this.resources.MergedDictionaries.Clear();
						this.resources.MergedDictionaries.Add(res);
						this.currentTheme = value;
					}else{
						throw new InvalidOperationException();
					}
				}
			}
		}
		
		public IList<ITheme> Themes{
			get{
				return new List<ITheme>(this.themes);
			}
		}
		
		#region IDisposable
		
		public void Dispose(){
			try{
				this.Dispose(true);
			}finally{
				foreach(var target in this.targets){
					target.MergedDictionaries.Remove(this.resources);
				}
				GC.SuppressFinalize(this);
			}
		}
		
		protected virtual void Dispose(bool disposing){
		}
		
		~ThemeManager(){
			this.Dispose(false);
		}
		
		#endregion
	}
}