﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace Pamya
{
    public class Word
    {
        public static double DEFAULT_EF = 2.5;
        public static double DEFAULT_I = 1;
        public static int DEFAULT_N = 1;


        public List<string> Translations { get; set; }
        public string Target { get; set; }
        public List<string> Examples { get; set; }
        public string XMLDescription { get; set; }
        public double EF { get; set; }
        public double I { get; set; }
        public int n { get; set; }
        public bool bStudied { get; set; }
        public int TimeDue { get; set; }

        public int Id { get; set; }

        public int OrderId { get; set; }
        public string sGuid { get; set; }
        public string SoundFileLocation { get; set; }
        public string ImageFileLocation { get; set; }

        public const float OPTIMAL_GAME_MULTIPLIER = 4.5f;

        public Word()
        {
            Translations = new List<string>();
            Target = "Vorto";
            EF = DEFAULT_EF;
            I = DEFAULT_I;
            n = DEFAULT_N;
            bStudied = false;
            TimeDue = 0;

            Id = 0;
            OrderId = 0;
            SoundFileLocation = "";
            Examples = new List<string>();
            sGuid = Guid.NewGuid().ToString();
            ImageFileLocation = "";
        }
        public Word(string Translation, string Target)
            : this()
        {
            Translations.Add(Translation);
            this.Target = Target;
        }

        public Word Clone()
        {
            return new Word
            {
                Translations = new List<string>(this.Translations),
                Target = this.Target,
                EF = this.EF,
                I = this.I,
                n = this.n,
                bStudied = this.bStudied,
                TimeDue = this.TimeDue,
                SoundFileLocation = this.SoundFileLocation,
                Examples = this.Examples,
                XMLDescription = this.XMLDescription,
                sGuid = this.sGuid,
                ImageFileLocation = this.ImageFileLocation,
                Id = this.Id,
                OrderId = this.OrderId,
            };
        }

        private uint EditDistance(string s, string t)
        {
            s = s.ToLower().Trim();
            t = t.ToLower().Trim();
            int m = s.Length;
            int n = t.Length;
            uint[,] d = new uint[m + 1, n + 1];
            for (int i = 0; i <= m; i++)
            {
                d[i, 0] = (uint)i;
            }
            for (int j = 0; j <= n; j++)
            {
                d[0, j] = (uint)j;
            }

            for (int j = 1; j <= n; j++)
            {
                for (int i = 1; i <= m; i++)
                {
                    if (s[i - 1] == t[j - 1])
                    {
                        d[i, j] = d[i - 1, j - 1];
                    }
                    else
                    {
                        d[i, j] = Math.Min(d[i - 1, j] + 1, Math.Min(d[i, j - 1] + 1, d[i - 1, j - 1] + 1));
                    }
                }
            }
            return d[m, n];
        }

        private void EFchange(double q)
        {
            //This is the SM2 algorithm
            var multiplier = PamyaDeck.Instance.CurrentGame.GameStudyMultiplier() / OPTIMAL_GAME_MULTIPLIER;

            var change = (0.1 - (5 - q) * (0.08 + (5 - q) * 0.2));

            if (change > 0)
                change *= multiplier;

            EF = EF + change;
            if (EF < 1.3) { EF = 1.3; }
        }

        private double Ifactor(int nnn)
        {
            if (nnn <= 3)
            {
                return 1d;
            }
            else if (nnn == 4)
            {
                return 6d;
            }
            else
            {
                return Ifactor(nnn - 1) * EF;
            }
        }

        public bool Answered(string attempt)
        {
            uint dist = EditDistance(Target, attempt);
            int q = 5 - ((int)dist);
            if (attempt.Length == 0)
            {
                q = 0;
            }
            if (q < 0) { q = 0; }

            if (q < 4)
            {
                EFchange(q);
                I = 1d;
                n = 1;
            }
            else if (q == 5)
            {
                if (n > 3)
                    EFchange(q);

                n += 1;
                I = Ifactor(n);
            }
            else if (q == 4)
            {
                if (n > 3)
                    EFchange(q);

                n -= 3;
                if (n < 1) { n = 1; }
                I = Ifactor(n);
            }

            SetNextDueDate();
            bStudied = true;

            if (q == 5) { return true; } else { return false; }
        }

        public void SetNextDueDate()
        {
            int secondsSinceEpoch = EpochTime.GetAsInt();
            TimeDue = secondsSinceEpoch + Convert.ToInt32(I * 60 * PamyaDeck.Instance.CurrentGame.GameStudyMultiplier()); //4.5 Typing Game
        }

        public void MarkAsEasy()
        {
            EF = (EF > 3.0) ? EF : 3.0;
            n = (n > 8) ? n : 8;
            I = Ifactor(n);
            SetNextDueDate();
        }

        public void MarkAsHard()
        {
            EF = 1.3;
            n = 1;
            I = Ifactor(n);
            SetNextDueDate();
        }

        public override string ToString()
        {
            return Translations.ToString() + "|" + Target + "|" + EF.ToString() + "|" + I.ToString() + "|" + n.ToString() + "|" + bStudied.ToString() + "|" + TimeDue.ToString();
        }
    }
}
