using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace PXP.Crawler.API.Utils
{
    public sealed class Misc
    {

        public static Type GetEnumeratedType<T>( IEnumerable<T> _)
        {
            return typeof(T);
        }

        public static Type GetListType<T>(List<T> _)
        {
            return typeof(T);
        }

        public static Type[] GetNamespaceTypes(string nsFullName)
        {
            Type[] types = Assembly.GetExecutingAssembly().GetTypes();
            List<Type> myTypes = new List<Type>();
            foreach (Type t in types)
            {
                if (t.Namespace == nsFullName)
                    myTypes.Add(t);

            }
            return myTypes.ToArray();
        }


        public static XmlDocument XmlDocumentFromXmlString(string xml)
        {
            XmlDocument xDoc = new XmlDocument();
            using (StringReader sr = new StringReader(xml))
            {
                using (XmlReader xr = XmlReader.Create(sr, new XmlReaderSettings() {  }))
                {
                    xDoc.Load(xr);
                }
            }
            return xDoc;
        }

        public static string XmlDocumentToString(XmlDocument xDoc)
        {
            StringBuilder sb = new StringBuilder();
            using (StringWriter sw = new StringWriter(sb))
            {
                using (XmlWriter xtw = XmlTextWriter.Create(sw, new XmlWriterSettings(){ Encoding = Encoding.UTF8, Indent = true}))                
                {
                    xDoc.WriteTo(xtw);
                }
            }

            return sb.ToString();
        }

        public static Color InterpolateColor(float pos, Color c1, Color c2)
        {
            return Color.FromArgb(InterpolateValue(pos, c1.A, c2.A), InterpolateValue(pos, c1.R, c2.R),
                InterpolateValue(pos, c1.G, c2.G), InterpolateValue(pos, c1.B, c2.B));
        }

        public static int InterpolateValue(float pos, int from, int to)
        {
            pos = LimitValue(pos, 0, 1);
            return from + (int)((to - from) * pos);
        }

        public static IList CreateList(Type myType)
        {
            Type genericListType = typeof(List<>).MakeGenericType(myType);
            return (IList)Activator.CreateInstance(genericListType);
        }


        public static PointF BezierPoint(float t, Point p0, Point p1, Point p2, Point p3)
        {
            float cube = t * t * t;
            float square = t * t;
            float ax = 3 * (p1.X - p0.X);
            float ay = 3 * (p1.Y - p0.Y);
            float bx = 3 * (p2.X - p1.X) - ax;
            float by = 3 * (p2.Y - p1.Y) - ay;
            float cx = p3.X - p0.X - ax - bx;
            float cy = p3.Y - p0.Y - ay - by;
            float x = (cx * cube) + (bx * square) + (ax * t) + p0.X;
            float y = (cy * cube) + (by * square) + (ay * t) + p0.Y;
            return new PointF(x, y);
        }

        public static int LargetValue(int val1, int val2)
        {
            if (val1 > val2)
                return val1;
            return val2;
        }

        public static string GetChildElementXml(XmlNode parentNode, string elementName)
        {
            return GetChildElementXml(parentNode, elementName, "");
        }

        public static string GetChildElementXml(XmlNode parentNode, string elementName, string defaultValue)
        {
            XmlElement xEl = parentNode[elementName];
            if (xEl != null)
                return xEl.InnerXml;
            return defaultValue;
        }

        public static XmlElement CreateAppendXmlElement(XmlNode parentNode, string elementName, string elementXml = "")
        {
            XmlElement nEl = parentNode.OwnerDocument.CreateElement(elementName);
            if (elementXml.Length > 0)
                nEl.InnerXml = elementXml;
            parentNode.AppendChild(nEl);
            return nEl;
        }
        public static float LimitValue(float val, float min, float max)
        {
            if (val < min)
                return min;
            if (val > max)
                return max;
            return val;
        }

        public static int LimitValue(int val, int min, int max)
        {
            if (val < min)
                return min;
            if (val > max)
                return max;
            return val;
        }

        public static string GetStringFromValue(object val)
        {
            Type vType = val.GetType();
            string vs;
            switch (vType.Name)
            {
                case "Point":
                    Point tp = (Point)val;
                    vs = tp.X.ToString() + ";" + tp.Y.ToString();
                    break;
                case "Size":
                    Size ts = (Size)val;
                    vs = ts.Width.ToString() + ";" + ts.Height.ToString();
                    break;
                default:
                    vs = val.ToString();
                    break;
            }
            return vs;
        }

        public static object GetObjectFromData(byte[] valData, Type vType, object initObj)
        {
            string[] vs;
            switch (vType.Name)
            {
                case "Single":
                    return Conv.SingleFromData(valData);
                default:
                    Debug.WriteLine("Error creating type from data: " + vType.Name);
                    return null;
            }
        }

        public static object GetObjectFromString(string val, Type vType, object initObj)
        {
            string[] vs;
            switch (vType.Name)
            {
                case "Point":
                    vs = val.Split(';');
                    return new Point(Convert.ToInt32(vs[0]), Convert.ToInt32(vs[1]));
                case "Size":
                    vs = val.Split(';');
                    return new Size(Convert.ToInt32(vs[0]), Convert.ToInt32(vs[1]));
                case "FormWindowState":
                    return Enum.Parse(vType, val);
                case "Boolean":
                    return val == "True";
                case "String":
                    return (string)val;
                case "Int32":
                    return Convert.ToInt32(val);
                case "Int64":
                    return Convert.ToInt64(val);
                case "Color":
                    return Color.FromArgb(Convert.ToInt32(val));
                default:
                    return null;
            }
        }
    }
}
