using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Windows;
using BeWo.Data;
using BeWo.Data.Access;
using BeWo.Data.Entities;

using BS.Shared.DataContracts;

namespace BeWo.Service.Security
{
    public class SecurityUtils
    {
        private static readonly byte[] _Rc2IV = { 35, 138, 177, 253, 227, 63, 2, 27 };

        private static readonly byte[] _Rc2Key = { 174, 130, 219, 185, 185, 221, 96, 50, 37, 212, 81, 121, 71, 206, 130, 153 };

        public static string EncryptString(string strToEncrypt)
        {
            var lRc2CSP = new RC2CryptoServiceProvider();
            var lEncryptor = lRc2CSP.CreateEncryptor(_Rc2Key, _Rc2IV);

            using (var msEncrypt = new MemoryStream())
            {
                using (var csEncrypt = new CryptoStream(msEncrypt, lEncryptor, CryptoStreamMode.Write))
                {
                    byte[] toEncrypt = Encoding.UTF8.GetBytes(strToEncrypt);

                    csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
                    csEncrypt.FlushFinalBlock();

                    byte[] encrypted = msEncrypt.ToArray();
                    return Convert.ToBase64String(encrypted);
                }
            }
        }

        public static string DecryptString(string strToDecrypt)
        {
            var lRc2CSP = new RC2CryptoServiceProvider();
            var lDecryptor = lRc2CSP.CreateDecryptor(_Rc2Key, _Rc2IV);

            strToDecrypt = strToDecrypt.Replace(' ', '+');
            strToDecrypt = strToDecrypt.Trim(',');

            using (var msDecrypt = new MemoryStream(Convert.FromBase64String(strToDecrypt)))
            {
                using (var csDecrypt = new CryptoStream(msDecrypt, lDecryptor, CryptoStreamMode.Read))
                {
                    var bytes = new List<byte>();
                    int b;
                    do
                    {
                        b = csDecrypt.ReadByte();
                        if (b != -1)
                            bytes.Add(Convert.ToByte(b));

                    } while (b != -1);
                    return Encoding.UTF8.GetString(bytes.ToArray());
                }
            }
        }

        internal static string CreateToken(bool ispermalink)
        {
            var guid = Guid.NewGuid();

            string tokendata = string.Format("expdate={0};guid={1};tenant={2};user={3};password={4};permalink={5}", DateTime.Now.AddMinutes(10), guid,
                                             MultitenancyOperationContextExt.Current.Tenant,
                                             LoggedInUserOperationContextExt.Current.User.LoginName,
                                             LoggedInUserOperationContextExt.Current.User.RC2EncryptedHash,
                                             ispermalink);

            return HttpUtility.UrlEncode(EncryptString(tokendata));
        }

        public static bool CheckToken(string token)
        {
            if (string.IsNullOrEmpty(token))
                return false;
            
            string decodedToken = DecryptString(token);
            
            string[] Params = decodedToken.Split(';');

            if (Boolean.Parse(Params[5].Split('=')[1]))
                return true;

            string date = Params[0].Split('=')[1];
            string[] expdatestrarr = date.Split(new[] { '.', ':', ' ' });

            var expdate = new DateTime(Convert.ToInt32(expdatestrarr[2]), Convert.ToInt32(expdatestrarr[1]),
                                       Convert.ToInt32(expdatestrarr[0]), Convert.ToInt32(expdatestrarr[3]),
                                       Convert.ToInt32(expdatestrarr[4]), Convert.ToInt32(expdatestrarr[5]));

            return expdate >= DateTime.Now;
        }

        public static Dictionary<string,object> sliceToken(string token, string link)
        {
            string decodedToken;
            var result = new Dictionary<string, object>();
            var ParamsDic = new Dictionary<string, string>();

            try
            {
                decodedToken = DecryptString(HttpUtility.UrlDecode(token));
            }
            catch (Exception)
            {
                decodedToken = DecryptString(token);
            }
            
            string[] Params = decodedToken.Split(';');
            
            foreach (var splittedItem in Params.Select(item => new Regex(@"[\=]{1}").Split(item, 2)).Where(splittedItem => !ParamsDic.ContainsKey(splittedItem[0])))
            {
                ParamsDic.Add(splittedItem[0], splittedItem[1]);
            }

            string[] expdatestrarr = ParamsDic["expdate"].Split(new[] { '.', ':', ' ' });

            var expdate = new DateTime(Convert.ToInt32(expdatestrarr[2]), Convert.ToInt32(expdatestrarr[1]),
                                       Convert.ToInt32(expdatestrarr[0]), Convert.ToInt32(expdatestrarr[3]),
                                       Convert.ToInt32(expdatestrarr[4]), Convert.ToInt32(expdatestrarr[5]));

            result.Add("expdate", expdate);
            result.Add("guid", Guid.Parse(ParamsDic["guid"]));
            result.Add("tenant", ParamsDic["tenant"]);
            result.Add("user", ParamsDic["user"]);
            result.Add("password", ParamsDic["password"]);
            result.Add("ispermalink", ParamsDic["permalink"]);

            return result;
        }

		public static LicenseInfoDC GetLicenseInfo()
		{
			var info = new LicenseInfoDC();

#if DEBUG

			info.MaxLicenseCount = 9999;
			info.PercentFreeEmployee = 100;

			info.LicenseInUseCount = DAOFactory.GenericDAO.GetAllActive<ApplicationUser>().Count;
			info.EmployeeCount = DAOFactory.GenericDAO.GetAllActive<Employee>().Count;

			info.MaxEmployeeCount = (int)Math.Ceiling(1000000 * ((100 + 100m) / 100));
			return info;
#endif

			try
			{
				string url = ConfigurationManager.AppSettings.Get("LicenseInfoUrl");

				url = url.Replace("[TENANT]", MultitenancyOperationContextExt.Current.Tenant);
				//url = url.Replace("[TENANT]", "1441747891");

				using (WebClient client = new WebClient())
				{
					//MessageBox.Show(hostAddress);
					byte[] response = client.DownloadData(url);

					String result = System.Text.Encoding.ASCII.GetString(response);
					//if (MultitenancyOperationContextExt.Current.Tenant == "demo")
					//{
					//	result = "7;30";
					//}
					String[] resultArray = result.Split(';');

					int maxLicenses = 0;
					decimal percentFreeEmployees = 0;
					if (resultArray.Length > 0)
					{
						Int32.TryParse(resultArray[0], out maxLicenses);
						if (resultArray.Length > 1)
						{
							Decimal.TryParse(resultArray[1], out percentFreeEmployees);
						}
					}
					info.MaxLicenseCount = maxLicenses;
					info.PercentFreeEmployee = percentFreeEmployees;

					info.LicenseInUseCount = DAOFactory.GenericDAO.GetAllActive<ApplicationUser>().Count;
					info.EmployeeCount = DAOFactory.GenericDAO.GetAllActive<Employee>().Count;

					info.MaxEmployeeCount = (int)Math.Ceiling(maxLicenses * ((100 + percentFreeEmployees) / 100));
				}
			}
			catch (Exception)
			{
				//
			}
			return info;
		}

		public static string CreateRandomString(int size, bool capitals = false, bool small = false, bool numbers = true)
	    {
			var data = new byte[1];
			var crypto = new RNGCryptoServiceProvider();
			var result = new StringBuilder(size);

			const string numbersString = "0123456789";
			const string capitalsString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
			const string smallString = "abcdefghijklmnopqrstuvwxyz";

			var str = string.Empty;

			if (numbers)
				str += numbersString;
			if (capitals)
				str += capitalsString;
			if (small)
				str += smallString;

			if (str.Length == 0)
				str = numbersString;

			var chars = str.ToCharArray();

			crypto.GetBytes(data);
			data = new byte[size];
			crypto.GetBytes(data);

			foreach (byte b in data)
				result.Append(chars[b % (chars.Length)]);

			return result.ToString();
	    }
    }
}
