// Created with MonoDevelop
//
//    Copyright (C) 2022 Hiperscan GmbH Dresden, Germany
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;

namespace Hiperscan.Common
{
    [AttributeUsage(AttributeTargets.Property)]
    public class ParserAttribute : Attribute, IEquatable<ParserAttribute>
    {
        public const string NO_NAME = "NO_NAME";



        public static string GetParserName(string name)
        {
            bool is_upper = false;
            string corrected_name = String.Empty;

            for (int i = 0; i < name.Length; i++)
            {
                string c = name[i].ToString();
                if (c == c.ToUpper())
                {
                    if (String.IsNullOrEmpty(corrected_name) == false && is_upper ==false)
                        corrected_name += "_";

                    is_upper = true;
                }
                else
                {
                    is_upper = false;
                }

                corrected_name += c.ToUpper();
            }

            return corrected_name;
        }

        public bool Equals(ParserAttribute other)
        {
            return this.Guid == other.Guid;
        }

        public static Dictionary<ParserAttribute, PropertyInfo> GetWritableProperties(object instance)
        {
            return ParserAttribute.GeProperties(instance, false);
        }

        public static Dictionary<ParserAttribute, PropertyInfo> GetReadableProperties(object instance)
        {
            return ParserAttribute.GeProperties(instance, true);
        }

        private static Dictionary<ParserAttribute, PropertyInfo> GeProperties(object instance, bool get_readable)
        {
            List<Tuple<ParserAttribute, PropertyInfo>> tupels = new List<Tuple<ParserAttribute, PropertyInfo>>();

            foreach (PropertyInfo property in instance.GetType().GetProperties())
            {
                ParserAttribute attr = (ParserAttribute)property.GetCustomAttribute(typeof(ParserAttribute));
                if (attr == null)
                    continue;

                if (attr.Name == ParserAttribute.NO_NAME)
                    attr.Name = ParserAttribute.GetParserName(property.Name);

                Tuple<ParserAttribute, PropertyInfo> tupel = new Tuple<ParserAttribute, PropertyInfo>(attr, property);
                tupels.Add(tupel);
            }



            return tupels.Where(t => t.Item1.Readable == get_readable || get_readable == false).
                         OrderBy(t => t.Item1.Order).
                         ToDictionary(t => t.Item1, t => t.Item2);
        }



        public string Name { get; set; } = ParserAttribute.NO_NAME;
        public int Order { get; set; } = Int32.MaxValue;
        public bool Readable { get; set; } = true;

        private Guid Guid { get; set; } = Guid.NewGuid();

    } 
}
