// Created with MonoDevelop
//
//    Copyright (C) 2017 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.Linq;

namespace Hiperscan.AnalysisModule.Identification
{
    public partial class IdentSubstance
    {
        private class JaroMetrics
        {
            public int NumberOfMatches { get; set; }
            public int Transpositions { get; set; }
        }

        public const double FUZZY_SCORE_THRESHOLD = 0.71;

        public void FindFuzzyParameters(string reference_substance_name)
        {
            this.fuzzy_score = 0;
            this.best_reference_name = String.Empty;
            this.FromUserSelected = false;

            foreach (string substance_name in this.AllSubstanceNames)
            {
                double score = this.CalcJaroScore(reference_substance_name, substance_name);

                if (score > this.fuzzy_score)
                {
                    this.fuzzy_score = score;
                    this.best_reference_name = substance_name;
                }
            }
        }

        private JaroMetrics JaroMatches(string s1, string s2)
        {
            string text;
            string text2;
            if (s1.Length > s2.Length)
            {
                text = s1;
                text2 = s2;
            }
            else
            {
                text = s2;
                text2 = s1;
            }
            int num = System.Math.Max(text.Length / 2 - 1, 0);
            int[] array = new int[text2.Length];
            int i;
            for (i = 0; i < array.Length; i++)
            {
                array[i] = -1;
            }
            bool[] array2 = new bool[text.Length];
            int num2 = 0;
            for (int j = 0; j < text2.Length; j++)
            {
                char c = text2[j];
                int k = System.Math.Max(j - num, 0);
                int num3 =  System.Math.Min(j + num + 1, text.Length);
                while (k < num3)
                {
                    if (!array2[k] && c == text[k])
                    {
                        array[j] = k;
                        array2[k] = true;
                        num2++;
                        break;
                    }
                    k++;
                }
            }
            char[] array3 = new char[num2];
            char[] ms2 = new char[num2];
            i = 0;
            int num4 = 0;
            while (i < text2.Length)
            {
                if (array[i] != -1)
                {
                    array3[num4] = text2[i];
                    num4++;
                }
                i++;
            }
            i = 0;
            num4 = 0;
            while (i < text.Length)
            {
                if (array2[i])
                {
                    ms2[num4] = text[i];
                    num4++;
                }
                i++;
            }
            int num5 = array3.Where((char t, int mi) => t != ms2[mi]).Count<char>();
            JaroMetrics result = new JaroMetrics();
            result.NumberOfMatches = num2;
            result.Transpositions = num5 / 2;
            return result;
        }

        private float CalcJaroScore(string s1, string s2)
        {
            JaroMetrics jaroMetrics = this.JaroMatches(s1, s2);
            float num = (float)jaroMetrics.NumberOfMatches;
            int transpositions = jaroMetrics.Transpositions;
            float result;
            if (num < 0.01f)
            {
                result = 0f;
            }
            else
            {
                float num2 = (num / (float)s1.Length + num / (float)s2.Length + (num - (float)transpositions) / num) / 3f;
                result = num2;
            }
            return result;
        }

        [NonSerialized] private double fuzzy_score = 0;
        public double FuzzyScore
        {
            get
            {
                return this.fuzzy_score;
            }
        }

        [NonSerialized] private string best_reference_name = String.Empty;
        public string BestReferenceName
        {
            get
            {
                return this.best_reference_name;
            }
        }
    }
}
