using System.Data;
using System.Collections.Generic;
using System;
using System.Threading;
using System.IO;

using dataladder.Data;
using dataladder.Matching;
using dataladder.Matching.Indexing;
using dataladder.Licensing;
using dataladder.Matching.Project;
using dataladder.Data.DataTransformation;
using dataladder.XtraGridHelper;
using DataMatch.Data.Enums;

namespace SampleServiceNamespace
{
    public class SampleService : ISampleService
    {
        #region Fields

        private static Dictionary<string, EngineWrapper> startedEngines = new Dictionary<string, EngineWrapper>();

        #endregion

        #region Constructors

        public SampleService()
        {
        }

        #endregion

        #region ISampleService implementation

        public string[] GetMatches(string hash, string tableName, string[] values, int records)
        {
            EngineWrapper engineWrapper;
            string[] result = { "error" };
            string testHash = PortableHash.GetHash(tableName);
            if (hash == testHash)
            {
                if (startedEngines.TryGetValue(tableName.ToLower(), out engineWrapper))
                {
                    InMemoryTable resultTable = engineWrapper.FindMatches(tableName, values, records);
                    int staticFieldsCount = Enum.GetValues(typeof(PreviewFinalResultsStaticFields)).Length;
                    int notNeededFieldsCount = staticFieldsCount - 5;
                    int recordsToReturn = Math.Min(records, resultTable.RecordCount);
                    int fieldCountInOneRow = resultTable.ColumnCount - notNeededFieldsCount;
                    result = new string[fieldCountInOneRow * (recordsToReturn + 1) + 1]; // we put the number of the returned columns in the first cell and all column names after that
                    int index = 0;
                    result[index++] = fieldCountInOneRow.ToString();
                    for (int colIndex = 0; colIndex < resultTable.ColumnCount; colIndex++)
                    {
                        if (colIndex < staticFieldsCount)
                        {
                            if (!(((PreviewFinalResultsStaticFields)colIndex == PreviewFinalResultsStaticFields.DataSource) ||
                                  ((PreviewFinalResultsStaticFields)colIndex == PreviewFinalResultsStaticFields.MatchingRecord) ||
                                  ((PreviewFinalResultsStaticFields)colIndex == PreviewFinalResultsStaticFields.Record) ||
                                  ((PreviewFinalResultsStaticFields)colIndex == PreviewFinalResultsStaticFields.GroupId) ||
                                  ((PreviewFinalResultsStaticFields)colIndex == PreviewFinalResultsStaticFields.Score)))
                            {
                                continue;
                            }
                        }
                        result[index++] = resultTable.GetColumnName(colIndex);
                    }
                    for (int rowIndex = 0; rowIndex < recordsToReturn; rowIndex++)
                    {
                        for (int colIndex = 0; colIndex < resultTable.ColumnCount; colIndex++)
                        {
                            if (colIndex < staticFieldsCount)
                            {
                                if (!(((PreviewFinalResultsStaticFields)colIndex == PreviewFinalResultsStaticFields.DataSource) ||
                                      ((PreviewFinalResultsStaticFields)colIndex == PreviewFinalResultsStaticFields.MatchingRecord) ||
                                      ((PreviewFinalResultsStaticFields)colIndex == PreviewFinalResultsStaticFields.Record) ||
                                      ((PreviewFinalResultsStaticFields)colIndex == PreviewFinalResultsStaticFields.GroupId) ||
                                      ((PreviewFinalResultsStaticFields)colIndex == PreviewFinalResultsStaticFields.Score)))
                                {
                                    continue;
                                }
                            }
                            object obj = resultTable.GetData(rowIndex, colIndex);
                            if ((obj == null) || (obj == DBNull.Value))
                            {
                                obj = "";
                            }
                            result[index++] = obj.ToString();
                        }
                    }
                }
            }
            return result;
        }

        public string[] GetMatchingFields(string hash, string tableName)
        {
            string[] result = { "error" };
            string testHash = PortableHash.GetHash(tableName);
            if (hash == testHash)
            {
                EngineWrapper engineWrapper;
                if (startedEngines.TryGetValue(tableName.ToLower(), out engineWrapper))
                {
                    result = engineWrapper.MatchingFieldNames;
                }
            }
            return result;
        }

        public bool Init(string hash, string tableName, bool useLog = false, bool doTransformation = false)
        {
            bool result = false;
            lock (startedEngines)
            {
                string testHash = PortableHash.GetHash(tableName);
                if (hash == testHash)
                {
                    string projectName = tableName.ToLower();
                    if (startedEngines.Count == 0)
                    {
                        EngineWrapper.RemoveRemainedFiles();
                    }
                    if (!startedEngines.ContainsKey(projectName))
                    {
                        startedEngines.Add(projectName, new EngineWrapper(projectName, useLog, doTransformation)); // should be in lower case
                    }
                    result = true;
                }
            }
            return result;
        }

        public bool IsRunning(string hash, string tableName)
        {
            bool result = false;
            lock (startedEngines)
            {
                string testHash = PortableHash.GetHash(tableName);
                if (hash == testHash)
                {
                    string projectName = tableName.ToLower();
                    result = startedEngines.ContainsKey(projectName);
                }
            }
            return result;
        }

        public bool Unload(string hash, string tableName)
        {
            bool result = false;
            if (IsRunning(hash, tableName))
            {
                string projectName = tableName.ToLower();
                lock (startedEngines)
                {
                    EngineWrapper engineWrapper = startedEngines[projectName];
                    engineWrapper.Dispose();
                    startedEngines.Remove(projectName);
                    result = true;
                }
            }
            return result;
        }

        public bool InsertRecord(string hash, string tableName, string[] fields, string[] values, out string[] inserted, out string error)
        {
            bool result = false;
            inserted = null;
            error = "";
            lock (startedEngines)
            {
                string testHash = PortableHash.GetHash(tableName);
                if (hash == testHash)
                {
                    EngineWrapper engineWrapper;
                    if (startedEngines.TryGetValue(tableName.ToLower(), out engineWrapper))
                    {
                        DataTable table;
                        result = engineWrapper.InsertRecord( fields, values, out table, out error);

                        List<String> data = new List<string>();
                        int colCount = table.Columns.Count;
                        data.Add(colCount.ToString());
                        for (int i = 0; i < colCount; i++)
                        {
                            data.Add(table.Columns[i].ColumnName ?? "");
                        }

                        for (int i = 0; i < table.Rows.Count; i++)
                        {
                            var row = table.Rows[i];
                            for (int ii = 0; ii < colCount; ii++)
                            {
                                data.Add((row[ii]??"").ToString());
                            }
                        }
                        inserted = data.ToArray();

                        if (String.IsNullOrEmpty(error))
                        {
                            engineWrapper.AddToCacheTableRecordWithOnlyMatchedFields(values);
                        }
                    }
                }
            }
            return result;
        }

        public bool ChangeThresholds(string hash, string tableName, int high, int low, out string error)
        {
            bool result = false;
            error = "";
            lock (startedEngines)
            {
                string testHash = PortableHash.GetHash(tableName);
                if (hash == testHash)
                {
                    EngineWrapper engineWrapper;
                    if (startedEngines.TryGetValue(tableName.ToLower(), out engineWrapper))
                    {
                        engineWrapper.SetThreshold(low / 100.0);
                        result = true;
                    }
                }
            }
            return result;
        }

        public bool UpdateRecord(string hash, string tableName, string[] values, string id, out string error)
        {
            bool result = false;
            error = "";
            lock (startedEngines)
            {
                string testHash = PortableHash.GetHash(tableName);
                if (hash == testHash)
                {
                    EngineWrapper engineWrapper;
                    if (startedEngines.TryGetValue(tableName.ToLower(), out engineWrapper))
                    {
                        result = engineWrapper.UpdateRecord(tableName, values, id, out error);
                    }
                }
            }
            return result;
        }

        public bool DeleteRecord(string hash, string tableName, string id, out string error)
        {
            bool result = false;
            error = "";
            lock (startedEngines)
            {
                string testHash = PortableHash.GetHash(tableName);
                if (hash == testHash)
                {
                    EngineWrapper engineWrapper;
                    if (startedEngines.TryGetValue(tableName.ToLower(), out engineWrapper))
                    {
                        result = engineWrapper.DeleteRecord(tableName, id, out error);
                    }
                }
            }
            return result;
        }
        public string GetCommonName(string firstname)
        {
            string result = dataladder.Data.Format.CommonNames.Get(firstname);
            return result;
        }

        #endregion
    }
}