using lkfxdok.c;
using lkfxdok.LKF;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace test.LKF
{
    internal class LKFExecution
    {
        public override string ToString()
        {
            return "LKFExecution base class - does nothing";
        }
        public virtual void execute()
        {

        }

        public virtual void validate()
        {

        }

        public virtual void Dispose()
        {

        }
    }

    internal class LKFBatchFileExecution : LKFExecution
    {
        LKFFileExecution[] executions;

        public LKFBatchFileExecution(LKFFileExecution[] executions)
        {
            this.executions = executions;
        }

        public override void execute()
        {
            if (executions != null)
            {
                foreach (var item in executions)
                {
                    Console.WriteLine($"Batch-Execution of " + item.ToString());
                    item.execute();
                }
            }
        }

        public override void validate()
        {

            if (executions == null)
            {
                return;
            }

            LKFContextComparer comparer = null;

            foreach (var item in executions)
            {
                if (item.lkfContext == null)
                {
                    continue;
                }
                if (comparer == null)
                {
                    comparer = new LKFContextComparer(item.lkfContext);
                    continue;
                }
                comparer.Compare(item.lkfContext, item.ToString());
            }
        }

        public override string ToString()
        {
            if (executions != null)
            {
                return $"Batch-Execution with {executions.Length} items";
            }
            return "Empty Batch-Execution";
        }

        public override void Dispose()
        {
            if (executions != null)
            {
                foreach (var item in executions)
                {
                    item.Dispose();
                }
            }
        }
    }

    internal class LKFFileExecution : LKFExecution
    {

        int model;
        int year;
        int flags;
        string filePath;
        string outputPath;
        LKFMetaData metaData;
        string traceAufenthalt = null;

        public bool PrintMeldeDiag = false;
        public bool KeepContext = false;

        private ContextWithData _lkfContext;

        public ContextWithData lkfContext => _lkfContext;

        public LKFFileExecution(LKFFileExecution source)
        {
            this.metaData = source.metaData;
            this.model = source.model;
            this.year = source.year;
            this.flags = source.flags;
            this.filePath = source.filePath;
            this.outputPath = source.outputPath;
            this.PrintMeldeDiag = source.PrintMeldeDiag;
            this.KeepContext = source.KeepContext;
        }

        public LKFFileExecution(string filePath, int year, int model = 0, int flags = 0, string outputPath = null, LKFMetaData metaData = null)
        {
            if (metaData != null)
            {
                this.metaData = metaData;
                this.model = metaData.Modelljahr;
            }
            else if (model == 0)
            {
                this.model = year;
            }
            else
            {
                this.model = model;
            }
            this.year = year;
            this.flags = flags;
            this.filePath = filePath;
            this.outputPath = outputPath;

        }

        public override string ToString()
        {
            if (metaData != null)
            {
                return $"{Path.GetFileName(filePath)}, metaData={metaData.Name}, flags={flags}, year={year}";
            }
            else
            {
                return $"{Path.GetFileName(filePath)}, model={model}, flags={flags}, year={year}";
            }
        }
        public override void execute()
        {
            var _context = new ContextWithData();
            if (KeepContext)
            {
                this._lkfContext = _context;
            }

            try
            {
                _context.Flags = flags;
                if (metaData != null)
                {
                    _context.SetMetaData(metaData);
                }
                else
                {
                    _context.Modelljahr = model;
                }
            }
            catch (LKFException ex)
            {
                Console.WriteLine(ex.Message);
                return;
            }

            _context.SetAbrechnungsPeriode(year, 1, 1, LKFContextPeriode.Jahr, -1);

            /* load file to byte array */
            var content = File.ReadAllBytes(filePath);
            _context.AddBuffer(content);

            //_context.LoadFile("C:\\LKF\\k999j001.s17");

            uint aufenthaltCount = _context.AufenthaltCount;
            Console.WriteLine("Aufenthalte: {0}", aufenthaltCount);

            if (traceAufenthalt != null)
            {
                _context.C.EnableDebugTrace();
                if (traceAufenthalt != string.Empty)
                {
                    _context.C.SetTraceAufenthalt(traceAufenthalt);
                }
            }
            _context.PlausCheck();

            if (PrintMeldeDiag)
            {
                printMeldeDiag(_context);
            }

            _context.Scoring();

            if (!string.IsNullOrEmpty(outputPath))
            {
                var fileName = Path.GetFileName(filePath);
                _context.WriteFile(LKFContextFileType.Result, Path.Combine(outputPath, fileName));
                _context.WriteFile(LKFContextFileType.Error, Path.Combine(outputPath, fileName + ".error"));
                _context.WriteFile(LKFContextFileType.Warning, Path.Combine(outputPath, fileName + ".warning"));
            }

            if (!KeepContext)
            {
                _context.Dispose();
                _context = null;
            }
        }

        public void printMeldeDiag(ContextWithData context)
        {
            foreach (var aufenthalt in context.Aufenthalte)
            {
                var meldeDiag = aufenthalt.C.FirstMeldeDiag;
                while (meldeDiag != null)
                {
                    Console.WriteLine($"{aufenthalt.BMID}: {meldeDiag.TypeId}/{meldeDiag.DiagIndex}: {meldeDiag.TypeText} / {meldeDiag.Diag} / {meldeDiag.Line}");
                    meldeDiag = meldeDiag.NextMeldeDiag;
                }
            }
        }

        public override void Dispose()
        {
            if (metaData != null) { metaData.Dispose(); metaData = null; }
            if (lkfContext != null) { _lkfContext = null; }
        }

        public static LKFFileExecution[] Repeat(IEnumerable<LKFFileExecution> sources, int count)
        {
            List<LKFFileExecution> exList = new List<LKFFileExecution>();

            for (int i = 0; i < count; i++)
            {
                foreach (var source in sources)
                {
                    exList.Add(new LKFFileExecution(source));
                }
            }
            return exList.ToArray();

        }
    }
}
