﻿#region License
/*****************************************************************************
 *
 *Copyright 2016 cathy33
 *
 *Licensed under the Apache License, Version 2.0 (the "License");
 *you may not use this file except in compliance with the License.
 *You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *Unless required by applicable law or agreed to in writing, software
 *distributed under the License is distributed on an "AS IS" BASIS,
 *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *See the License for the specific language governing permissions and
 *limitations under the License.
 *
 *****************************************************************************/
#endregion

using Infinity.Core.Data;
using Infinity.Core.Interface;
using Infinity.Core.Variant;
using System;
using System.Collections.Generic;
using System.Text;

namespace Infinity.Core.Event
{
    public delegate void DataEventHandler(IKernel kernel, PersistID self, string name, VariantList args);

    internal class DataEventManager<Enum>
    {
        private Dictionary<KeyValuePair<string, int>, HashSet<DataEventHandler>> _EventHandlers;

        internal DataEventManager()
        {
            _EventHandlers = new Dictionary<KeyValuePair<string, int>, HashSet<DataEventHandler>>();
        }

        internal void CallHandler<T>(T event_enum, IKernel kernel, PersistID self, string name, VariantList args)
        {
            int event_id = (int)Convert.ChangeType(event_enum, TypeCode.Int32);

            HashSet<DataEventHandler> found = null;
            KeyValuePair<string, int> pair
                = new KeyValuePair<string, int>(name, event_id);

            if (!_EventHandlers.TryGetValue(pair, out found))
            {
                return;
            }

            foreach (DataEventHandler event_handler in found)
            {
                event_handler(kernel, self, name, new VariantList(args));
            }
        }

        internal void AddEvent<T>(string name, T event_enum, DataEventHandler event_handler) where T : Enum
        {
            int event_id = (int)Convert.ChangeType(event_enum, TypeCode.Int32);

            HashSet<DataEventHandler> found = null;
            KeyValuePair<string, int> pair
                = new KeyValuePair<string, int>(name, event_id);

            if (!_EventHandlers.TryGetValue(pair, out found))
            {
                found = new HashSet<DataEventHandler>();
                _EventHandlers.Add(pair, found);
            }

            try
            {
                if (found.Contains(event_handler))
                {
                    StringBuilder sb = new StringBuilder();
                    sb.AppendFormat("Cant Add Event Because {0} Has Exist in Event {1}",
                        event_handler.Method.Name, event_enum.ToString());

                    throw new EventException(sb.ToString());
                }
                else
                {
                    found.Add(event_handler);
                }
            }
            catch (Exception ex)
            {
                throw new EventException("EventExpection ", ex);
            }
        }

        internal void DelEvent<T>(string name, T event_enum, DataEventHandler event_handler) where T : Enum
        {
            int event_id = (int)Convert.ChangeType(event_enum, TypeCode.Int32);

            HashSet<DataEventHandler> found = null;
            KeyValuePair<string, int> pair
                = new KeyValuePair<string, int>(name, event_id);

            try
            {
                if (!_EventHandlers.TryGetValue(pair, out found))
                {
                    StringBuilder sb = new StringBuilder();
                    sb.AppendFormat("Cant Del Event Because Event {0} Not Register", event_enum.ToString());
                    throw new EventException(sb.ToString());
                }
                else
                {
                    if (!found.Contains(event_handler))
                    {
                        StringBuilder sb = new StringBuilder();
                        sb.AppendFormat("Cant Add Event Because {0} Not Exist in Event {1}",
                            event_handler.Method.Name, event_enum.ToString());
                        throw new EventException(sb.ToString());
                    }
                    else
                    {
                        found.Remove(event_handler);
                    }
                }
            }
            catch (Exception ex)
            {
                throw new EventException("EventExpection ", ex);
            }
        }
    }
}
