using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Valg.EVA.Skanning.Resources;
using Valg.EVA.Skanning.Resources.Language;
using Valg.EVA.Skanning.Identity;
using Prism.Events;
using Valg.EVA.Skanning.UserInterfaceElements.Annotations;
using Valg.EVA.Skanning.UserInterfaceElements.Language;

namespace Valg.EVA.Skanning.UserInterfaceElements
{
    public abstract class ViewModelBase : IViewModelBase, INotifyPropertyChanged
    {
        private readonly List<KeyValuePair<EventBase, SubscriptionToken>> eventsAndSubscriptionTokens = new List<KeyValuePair<EventBase, SubscriptionToken>>();
        private IEventAggregator eventAggregator;

        public event PropertyChangedEventHandler PropertyChanged;

        public LanguageString LanguageString => LanguageResource.LanguageString;

        public ScanLanguageString ScanLanguageString => LanguageResource.ScanLanguageString;

        public VerifyLanguageString VerifyLanguageString => LanguageResource.VerifyLanguageString;

        public SampleLanguageString SampleLanguageString => LanguageResource.SampleLanguageString;

        public JobManagementLanguageString JobManagementLanguageString => LanguageResource.JobManagementLanguageString;

        
        
        
        public void SetupEventSubscriptions(IEventAggregator eventAgg)
        {
            if (eventAggregator != null)
            {
                throw new InvalidOperationException("EventAggregator in viewModel is already set.");
            }

            eventAggregator = eventAgg;

            SubscribeToEvent<LanguageChangedEvent, LanguageChangedEventArgs>(NotifyLanguageChanged);
            SubscribeToEvent<SecurityContextHasChangedEvent, System.EventArgs>(NotifySecurityContextHasChanged);

            SubscribeToViewModelSpecificEvents();
        }

        private void NotifyLanguageChanged(LanguageChangedEventArgs obj)
        {
            OnPropertyChanged(null);
        }

        private void NotifySecurityContextHasChanged(System.EventArgs obj)
        {
            OnPropertyChanged(null);
        }

        
        
        
        
        
        
        
        protected virtual void SubscribeToViewModelSpecificEvents()
        {
            
        }

        protected void SubscribeToEvent<EventType, ArgsType>(Action<ArgsType> action) where EventType : PubSubEvent<ArgsType>, new()
        {
            var eventType = eventAggregator.GetEvent<EventType>();
            var token = eventType.Subscribe(action);
            eventsAndSubscriptionTokens.Add(new KeyValuePair<EventBase, SubscriptionToken>(eventType, token));
        }

        protected void SubscribeToEvent<EventType>(Action action) where EventType : PubSubEvent, new()
        {
            var eventType = eventAggregator.GetEvent<EventType>();
            var token = eventType.Subscribe(action);
            eventsAndSubscriptionTokens.Add(new KeyValuePair<EventBase, SubscriptionToken>(eventType, token));
        }

        protected void PublishEvent<EventType, ArgsType>(ArgsType action) where EventType : PubSubEvent<ArgsType>, new()
        {
            var eventType = eventAggregator.GetEvent<EventType>();
            eventType.Publish(action);
        }

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        
        
        
        
        public void Dispose()
        {
            foreach (var keyValuePair in eventsAndSubscriptionTokens)
            {
                var eventBase = keyValuePair.Key;
                var token = keyValuePair.Value;
                eventBase.Unsubscribe(token);
            }
        }
    }
}
