using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using dataladder.Data;
using dataladder.Licensing;
using dataladder.Matching;
using DataMatching.Matching;
using dataladder.XtraGridHelper;

namespace MatchEngineSample
{
    class Program
    {
        static void Main(string[] args)
        {
            TestMatchManager();

            Console.WriteLine("Press any key to continue . . .");
            Console.ReadKey();
        }

        public static void TestMatchManager()
        {
            Console.WriteLine("Initializing registration module...");

            RegistrationWrapper registration = new RegistrationWrapper();
            registration.CustomPathForRegistrationFile = @"D:\API\Test\License";
            DateTime expirationDate = RegistrationWrapper.ExpirationDate;

            Console.WriteLine("Initialized Successfully");
            Console.WriteLine("Key expiration date: {0}", expirationDate);
            Console.WriteLine();
            Console.WriteLine("Initializing matching settings...");

            // Create Match Settings
            MatchSettings matchSettings = new MatchSettings();
            matchSettings.DataPath = @"D:\API\Test";
            matchSettings.TempPath = @"D:\API\Test\Temp";
            matchSettings.Name = "TestEngine";

            Console.WriteLine("Data Path: \t\t {0}", matchSettings.DataPath);
            Console.WriteLine("Temp Path: \t\t {0}", matchSettings.TempPath);
            Console.WriteLine("Project Name: \t\t {0}", matchSettings.Name);
            Console.WriteLine();

            // 1. Init Data Source
            Console.WriteLine("Creating source table: {0}", "Source1");

            String tableFullPath = Path.Combine(matchSettings.DataPath, matchSettings.Name);
            OnDriveTable onDriveTable = new OnDriveTable(tableFullPath, "Source1");
            onDriveTable.AddField("FirstName", typeof(String));
            onDriveTable.AddField("LastName", typeof(String));
            onDriveTable.SetData("John", 0, 0);
            onDriveTable.SetData("Smith", 0, 1);
            onDriveTable.SetData("Joan", 1, 0);
            onDriveTable.SetData("Smit", 1, 1);

            PrintTable(onDriveTable, 20);

            // 2. Init Match Definition Manager
            Console.WriteLine("Creating match definitions...");

            MultipleMatchDefinitionsManager matchDefinitionManager = new MultipleMatchDefinitionsManager();

            MatchCriteriaList matchCriteriaList = new MatchCriteriaList(0);
            MatchCriteria firstNameCriteria = new MatchCriteria()
            {
                Fuzzy = true,
                AddWeightToFirstLetter = false,
                Exact = false,
                Numeric = false,
                UseMetaphone = false,
                IgnoreCase = true,
                Level = 0.7f,
                GroupLevel = 0.0f,
                MinAllowedLevelInGroup = 0.0f,
                GroupId = -1,
                CrossColumnGroupId = -1,
                Weight = 100.0f,
                MatchingIndex = 0,
                AbsoluteMatchingIndex = 0
            };

            Console.WriteLine("Mathc Type: \t\t {1}{0}Fuzzy Level: \t\t {2}", System.Environment.NewLine, "Fuzzy", firstNameCriteria.Level);

            firstNameCriteria.MapField("Source1", "FirstName");

            matchCriteriaList.Add(firstNameCriteria);
            matchCriteriaList.MarkTheFirstFieldInEveryGroup();

            matchDefinitionManager.Add(matchCriteriaList);
            //matchDefinitionManager.SetAbsoluteIndices();

            AvailableFieldsFromOneTable fieldsFromTable = new AvailableFieldsFromOneTable();
            fieldsFromTable.Table = onDriveTable;

            FieldMapInfo fmiFirstName = new FieldMapInfo(0);
            fmiFirstName.FieldName = "FirstName";
            fmiFirstName.TableName = "Source1";
            fmiFirstName.ColumnTransformation = null;
            fmiFirstName.FieldIndex = 0;
            fieldsFromTable.Add(fmiFirstName);

            FieldMapInfo fmiLastName = new FieldMapInfo(0);
            fmiLastName.FieldName = "LastName";
            fmiLastName.TableName = "Source1";
            fmiLastName.ColumnTransformation = null;
            fmiLastName.FieldIndex = 1;
            fieldsFromTable.Add(fmiLastName);

            matchDefinitionManager.AvailableFields = new AvailableFields();


            matchDefinitionManager.AvailableFields.TableList.Add(fieldsFromTable);

            MappedFieldsRow mfrFirstName = new MappedFieldsRow();
            mfrFirstName["Source1"] = fmiFirstName;
            matchDefinitionManager.AvailableFields.MappedFieldsRowList.Add(mfrFirstName);

            MappedFieldsRow mfrLastName = new MappedFieldsRow();
            mfrLastName["Source1"] = fmiLastName;
            matchDefinitionManager.AvailableFields.MappedFieldsRowList.Add(mfrLastName);

            matchDefinitionManager.SetAbsoluteIndices();

            // Finish init settings
            matchSettings.MatchDefinitionManager = matchDefinitionManager;
            matchSettings.Tables.Add(onDriveTable);
            matchSettings.SourcePairs.Add(new MatchEngine.DataSourceIndexPair(0, 0));

            Console.WriteLine();
            Console.WriteLine("Creating Matching Manager...");
            MatchManager matchManager = new MatchManager(matchSettings);

            Console.WriteLine("Matching...");
            Console.WriteLine();
            matchManager.FindMatches();

            OnDriveTable groupsTable = matchSettings.FinalScoresGroupsTable;
            OnDriveTable pairsTable = matchSettings.PairsScoresTable;

            Console.WriteLine("Pairs Table:");
            PrintTable(pairsTable, 10);

            Console.WriteLine("Groups Table:");
            PrintTable(groupsTable, 10);

            onDriveTable.ToDeleteFilesAfterClosing = true;
            onDriveTable.Dispose();
            onDriveTable = null;
        }

        private static void PrintTable(IContainer2CoordsMapper mapper, Int32 width)
        {
            String line = "+" +  new String('-', mapper.ColumnCount * (width + 1) - 1) + "+";
            Console.WriteLine(line);

            for (Int32 i = 0; i < mapper.ColumnCount; i++)
            {
                String columnName = mapper.GetColumnName(i);
                if (columnName.Length > width - 2)
                {
                    columnName = columnName.Substring(0, width - 2) + (Char)(0x2026);
                }
                Console.Write("|");
                Console.Write($"{{0,-{width}}}", columnName);
            }

            Console.WriteLine("|");
            Console.WriteLine(line);

            for (Int32 j = 0; j < mapper.RecordCount; j++)
            {
                for (Int32 i = 0; i < mapper.ColumnCount; i++)
                {
                    Object cellValue = mapper.GetData(j, i);
                    Double? doubleValue = cellValue as Double?;

                    String cellValueString;

                    if (doubleValue.HasValue)
                    {
                        cellValueString = doubleValue.Value.ToString("n2");
                    }
                    else
                    {
                        cellValueString = cellValue?.ToString() ?? String.Empty;
                    }
                    
                    if (cellValueString.Length > width - 2)
                    {
                        cellValueString = cellValueString.Substring(0, width - 2);
                    }
                    Console.Write("|");
                    Console.Write($"{{0,-{width}}}", cellValueString);
                }

                Console.WriteLine("|");
            }

            Console.WriteLine(line);
            Console.WriteLine();
        }
    }
}
