using Earthblend.Nts.Common.Interfaces;
//using Earthblend.Nts.Common.Members;
//using Earthblend.Nts.Common.MeshGenerators;
//using Earthblend.Nts.Common.Shapes;
using System;
using System.ComponentModel;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Xml.Serialization;

namespace Earthblend.Nts.Common
{
    [Serializable]
    public abstract class CustomBindableBase : DependencyObject, INotifyPropertyChanged, ICustomBindableBase
    {
        #region Private Variables

        //private Type[] _loadSaveTypes = new Type[]
        //{
        //     typeof(VirtualCanvasPluginDataItem)
        //    ,typeof(VirtualWorld3DPluginDataItem)
        //    ,typeof(ArrowMeshGenerator)
        //    ,typeof(BoxMeshGenerator)
        //    ,typeof(ConeMeshGenerator)
        //    ,typeof(CylinderMeshGenerator)
        //    ,typeof(DodecahedronMeshGenerator)
        //    ,typeof(EllipsoidMeshGenerator)
        //    ,typeof(HollowCylinderMeshGenerator)
        //    ,typeof(IcosahedronMeshGenerator)
        //    ,typeof(OctahedronMeshGenerator)
        //    ,typeof(PlanarTextMeshGenerator)
        //    ,typeof(RibbonTextMeshGenerator)
        //    ,typeof(SolidTextMeshGenerator)
        //    ,typeof(SphereMeshGenerator)
        //    ,typeof(TetrahedronMeshGenerator)
        //    ,typeof(TorusMeshGenerator)
        //    ,typeof(TubeMeshGenerator)
        //};

        #endregion

        private Guid _id = Guid.NewGuid();
        public Guid Id { get { return _id; } set { SetProperty(ref _id, value); } }

        #region Protected Constructor(s)

        protected CustomBindableBase()
        {

        }

        protected CustomBindableBase(String pluginName)
        {

        }

        #endregion

        public void SetFieldValue(String fieldName, Object classObj, Double value)
        {
            PropertyInfo propertyInfo = classObj.GetType().GetProperty(fieldName);
            propertyInfo.SetValue(classObj, value);
        }

        public void SetFieldValue(String fieldName, Object classObj, String value)
        {
            PropertyInfo propertyInfo = classObj.GetType().GetProperty(fieldName);
            propertyInfo.SetValue(classObj, value);
        }

        #region Virtual Functions

        //public virtual PluginHostRegion PluginLocation(String pluginName, PluginIdentityType identityType = PluginIdentityType.DisplayName) { Busy(); return PluginHostRegion.Main; }
        //public T LoadProjectFile<T>(DataModelItem dataModelItem, Type[] types = null) where T : class
        //{
        //    Busy();
        //    if (dataModelItem == null) return null;
        //    Object data = null;
        //    String xml = String.Empty;
        //    String path = String.Empty;
        //    try
        //    {
        //        path = dataModelItem.FullName;
        //        xml = path.ReadFile();

        //        XmlSerializer deSerializer = new XmlSerializer(typeof(T), types);

        //        StringReader reader = new StringReader(xml);
        //        data = (T)deSerializer.Deserialize(reader);
        //        reader.Close(); reader.Dispose(); reader = null;
        //    }
        //    catch (Exception ex)
        //    {
        //        var msg = String.Empty;
        //        if (String.IsNullOrEmpty(xml))
        //            msg += "Xml is empty from file: " + path;
        //        msg += "  " + ex.Message;
        //        ShellViewModel?.SendMessage(VirtualSystemUtil.Log(MethodBase.GetCurrentMethod()), msg, VirtualSystemUtil.Messages, CurrentPluginName, MessageType.Error);
        //    }

        //    return data as T;
        //}
        //public virtual Object RequestPluginViewModel(String pluginViewModel) { return null; }
        //public virtual int PluginLocationCount(String displayName) { return 0; }

        #endregion

        #region Public Clr Properties

        //[XmlIgnore] public Type[] LoadSaveTypes { get { return _loadSaveTypes; } set { SetProperty(ref _loadSaveTypes, value); } }
        //[XmlIgnore] public String ContextMenuFilter { get { return _contextMenuFilter; } set { SetProperty(ref _contextMenuFilter, value); NotifyPropertyChanged("FilteredContextMenuItems"); } }

        #endregion

        #region Reflection

        public Object GetThisPropertyValue(String propertyName)
        {
            return this[propertyName];
        }

        public void SetThisPropertyValue(String propertyName, Object value)
        {
            this[propertyName] = value;
        }

        [XmlIgnore]
        public Object this[String propertyName]
        {
            get { return this.GetType().GetProperty(propertyName).GetValue(this, null); }
            set { this.GetType().GetProperty(propertyName).SetValue(this, value, null); }
        }

        #endregion

        #region Public Events

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region Protected Property Setter

        public Boolean SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
        {
            try
            {
                if (Equals(storage, value)) return false;

                storage = value;
                if (propertyName != null) OnPropertyChanged(propertyName);
            }
            catch (Exception ex)
            {
                String msg = ex.Message;
            }

            return true;
        }

        #endregion

        #region Public Methods

        public void OnPropertyChanged([CallerMemberName] String propertyName = null)
        {
            try { var eventHandler = PropertyChanged; eventHandler?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }
            catch (Exception ex)
            {
                String msg = ex.Message;
            }
        }

        public void NotifyPropertyChanged(String propertyName)
        {
            try { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }
            catch (Exception ex)
            {
                String msg = ex.Message;
            }
        }

        #endregion
    }
}
