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

using lkfxdok.c;

namespace lkfxdok.LKF
{
    public class Aufenthalt
    {

        LKFAufenthalt _aufenthalt;
        bool _synchronized;
        bool _keyFieldChanged;

        LKFLine _x01;
        LKFLine _x05;
//        LKFLine _x07;
        AufenthaltResult _aufenthaltResult;

        List<Diagnose> _diagnosen;
        List<Leistung> _leistungen;
        List<Abteilung> _abteilungen;
        List<AkWarn> _akwarn;

        String _ident;

        public Aufenthalt(LKFAufenthalt aufenthalt)
        {
            _aufenthalt = aufenthalt;
            _ident = aufenthalt.Ident;
            _x01 = new LKFLine(aufenthalt.Line, this);
            var x05 = aufenthalt.LineRESULT;
            if (!string.IsNullOrEmpty(x05))
                _x05 = new LKFLine(x05, this);


            _diagnosen = new List<Diagnose>();
            _leistungen = new List<Leistung>();
            _abteilungen = new List<Abteilung>();
            _akwarn = new List<AkWarn>();

            uint i, count = aufenthalt.AbtCount;

            for (i = 0; i < count; i++)
            {
                _abteilungen.Add(new Abteilung(this, aufenthalt.GetAbteilung(i).Line, i));
            }

            count = aufenthalt.MELCount;
            for (i = 0; i < count; i++)
            {
                _leistungen.Add(new Leistung(this, aufenthalt.GetMEL(i).Line, i));
            }

            count = aufenthalt.DiagCount;
            for (i = 0; i < count; i++)
            {
                _diagnosen.Add(new Diagnose(this, aufenthalt.GetDiagnose(i).Line, i));
            }

            count = aufenthalt.AkWarnCount;
            for (i = 0; i < count; i++)
            {
                _akwarn.Add(new AkWarn(this, aufenthalt.GetAkWarn(i).Line, i));
            }

            _synchronized = true;
        }

        public Aufenthalt()
        {
            _x01 = new LKFLine("X01", this);
            _diagnosen = new List<Diagnose>();
            _leistungen = new List<Leistung>();
            _abteilungen = new List<Abteilung>();
            _akwarn = new List<AkWarn>();
        }

        public string Id
        {
            get
            {
                return _ident;
            }
        }
        public Aufenthalt(String line)
        {

            if (line.StartsWith ("X01|"))
            {
                _x01 = new LKFLine(line, this);
            }
            else
            {
                _x01 = new LKFLine("x01", this);
            }

            _x01 = new LKFLine(line, this);
            _diagnosen = new List<Diagnose>();
            _leistungen = new List<Leistung>();
            _abteilungen = new List<Abteilung>();
            _akwarn = new List<AkWarn>();
        }
        
        public Aufenthalt (string aufDat, string gebDat, string geschlecht, string entdat)
        {
            _x01 = new LKFLine("X01", this);
            _diagnosen = new List<Diagnose>();
            _leistungen = new List<Leistung>();
            _abteilungen = new List<Abteilung>();
            _akwarn = new List<AkWarn>();

            KANR = "K901";
            AUFNR = "1234";

            AufDat = aufDat;
            AufZeit = "1200";
            Behandlungsart = "S";
            GebDat = gebDat;
            Geschlecht = geschlecht;
            STAATB = "AT";
            STAATW = "AT";
            PLZW = "1020";
            GEMCO = "90101";
            AUFART1 = "A";
            AUFART2 = "P";

            if (string.IsNullOrEmpty(entdat))
            {
                ENTART = "V";
            }
            else
            {
                ENTART = "E";
                ENTDAT = entdat;
                ENTZEIT = "1200";
            }
            LEIST_KOST = "11";
            RELEVANZ = "J";
        }

        public Aufenthalt(string aufDat, string gebDat, string geschlecht)
        {
            _x01 = new LKFLine("X01", this);
            _diagnosen = new List<Diagnose>();
            _leistungen = new List<Leistung>();
            _abteilungen = new List<Abteilung>();
            _akwarn = new List<AkWarn>();

            AufDat = aufDat;
            AufZeit = "1200";
            Behandlungsart = "I";
            GebDat = gebDat;
            Geschlecht = geschlecht;
            STAATB = "AT";
            STAATW = "AT";
            PLZW = "1020";
            GEMCO = "90101";
            AUFART1 = "1";
            AUFART2 = "P";
            LEIST_KOST = "11";
            RELEVANZ = "J";
            ENTART = "1";
        }


        public bool Synchronized
        {
            get
            {
                return _synchronized;
            }
            internal set
            {
                _synchronized = value;
            }
        }

        public LKFAufenthalt C
        {
            get
            {
                return _aufenthalt;
            }
        }

        public IEnumerable<Leistung> Leistungen
        {
            get
            {
                return _leistungen;
            }
        }

        public IEnumerable<AkWarn> AkWarn
        {
            get
            {
                return _akwarn;
            }
        } 

        public int LeistungCount => _leistungen.Count;
        public int AbteilungCount => _abteilungen.Count;
        public int DiagnoseCount => _diagnosen.Count;
        public int AkWarnCount => _akwarn.Count;

        public IEnumerable<Abteilung> Abteilungen
        {
            get
            {
                return _abteilungen;
            }
        }

        public IEnumerable<AufenthaltError> Issues
        {
            get
            {
                var error = _aufenthalt.FirstError;
                while (error != null)
                {
                    yield return new AufenthaltError(this, error);
                    error = error.NextError;
                }
                yield break;
            }
        }

        public IEnumerable<AufenthaltError> Errors => Issues.Where(e => e.ErrorType == ErrorType.Error);
        public IEnumerable<AufenthaltError> Warnings => Issues.Where(e => e.ErrorType == ErrorType.Warning);
        public IEnumerable<AufenthaltError> Infos => Issues.Where(e => e.ErrorType == ErrorType.Info);

        public Aufenthalt CopyTo (ContextWithData context)
        {

            LKFContextWithData cContext = context.C as LKFContextWithData;

            var cAufenthalt = new LKFAufenthalt(context.C);

            foreach (var l in Lines)
            {
                cAufenthalt.AddLine(l);
            }


            if (cContext != null)
                cAufenthalt.AttachToContext(cContext);

            return new Aufenthalt(cAufenthalt);
        }

        public IEnumerable<Diagnose> Diagnosen
        {
            get
            {
                return _diagnosen;
            }
        }

        public IEnumerable<AkWarn> Akwarn
        {
            get
            {
                return _akwarn;
            }
        }

        public Leistung GetLeistung(uint index)
        {
            if (index < _leistungen.Count)
            {
                return _leistungen[(int)index];
            }
            return null;
        }

        public Abteilung GetAbteilung(uint index)
        {
            if (index < _abteilungen.Count)
            {
                return _abteilungen[(int)index];
            }
            return null;
        }

        public Diagnose GetDiagnose(uint index)
        {
            if (index < _diagnosen.Count)
            {
                return _diagnosen[(int)index];
            }
            return null;
        }

        public bool DeleteDiagnose(uint index)
        {
            if (index < _diagnosen.Count)
            {
                _diagnosen.RemoveAt((int)index);
                Synchronized = false;
                return true;
            }
            return false;
        }

        public bool DeleteAbteilung(uint index)
        {
            if (index < _abteilungen.Count)
            {
                _abteilungen.RemoveAt((int)index);
                Synchronized = false;
                return true;
            }
            return false;
        }

        public bool DeleteLeistung(uint index)
        {
            if (index < _leistungen.Count)
            {
                _leistungen.RemoveAt((int)index);
                Synchronized = false;
                return true;
            }
            return false;
        }

        public bool DeleteAkWarn(uint index)
        {
            if (index < _akwarn.Count)
            {
                _akwarn.RemoveAt((int)index);
                Synchronized = false;
                return true;
            }
            return false;
        }

        public Leistung AddLeistung(string line)
        {
            Synchronized = false;
            return new Leistung(this, line);
        }

        public Diagnose AddDiagnose(string line)
        {
            Synchronized = false;
            return new Diagnose(this, line);
        }

        public Abteilung AddAbteilung(string line)
        {
            Synchronized = false;
            return new Abteilung(this, line);
        }

        public AkWarn AddAkWarn(string line)
        {
            Synchronized = false;
            return new AkWarn(this, line);
        }

        public Leistung AddLeistung()
        {
            Synchronized = false;
            return new Leistung(this);
        }

        public Diagnose AddDiagnose()
        {
            Synchronized = false;
            return new Diagnose(this);
        }

        public Abteilung AddAbteilung()
        {
            Synchronized = false;
            return new Abteilung(this);
        }

        public AkWarn AddAkWarn()
        {
            Synchronized = false;
            return new AkWarn(this);
        }

        internal void _AddLeistung (Leistung leistung)
        {
            _leistungen.Add(leistung);
            Synchronized = false;
        }

        internal void _AddDiagnose (Diagnose diagnose)
        {
            _diagnosen.Add(diagnose);
            Synchronized = false;
        }

        internal void _AddAkWarn (AkWarn akwarn)
        {
            _akwarn.Add(akwarn);
            Synchronized = false;
        }

        internal void _AddAbteilung (Abteilung abteilung)
        {
            _abteilungen.Add(abteilung);
            Synchronized = false;
        }

        public Leistung AddLeistung(Leistung leistung)
        {
            string kaleist = null;
            if (string.IsNullOrEmpty(leistung.FCLEIST) && string.IsNullOrEmpty(leistung.KALEIST))
            {
                kaleist = "K900";
            }
            var copy = new Leistung(this, leistung.Line.GetLine(_x01.GetKeyParts(5), false));

            if (kaleist != null)
            {
                copy.KALEIST = kaleist;
            }
            Synchronized = false;
            return copy;
        }

        public AkWarn AddAkWarn(AkWarn akwarn)
        {
            var copy = new AkWarn(this, akwarn.Line.GetLine(_x01.GetKeyParts(5), false));
            Synchronized = false;
            return copy;
        }

        public Diagnose AddDiagnose(Diagnose diagnose)
        {
            var copy = new Diagnose(this, diagnose.Line.GetLine(_x01.GetKeyParts(5), false));
            Synchronized = false;
            return copy;
        }

        public Abteilung AddAbteilung(Abteilung abteilung)
        {
            string abtpos = null;
            string abtdat = null;
            if (string.IsNullOrEmpty (abteilung.ABTPOS))
            {
                abtpos = String.Format("{0:000}", _abteilungen.Count + 1);
            }
            if (string.IsNullOrEmpty (abteilung.DATUM))
            {
                abtdat = AufDat;
            }

            var copy = new Abteilung(this, abteilung.Line.GetLine(_x01.GetKeyParts(5), false));

            if (abtpos != null)
            {
                copy.ABTPOS = abtpos;
            }

            if (abtdat != null)
            {
                copy.DATUM = abtdat;
            }

            Synchronized = false;
            return copy;
        }

        public bool Synchronize()
        {

            if (_aufenthalt == null)
            {
                return false;
            }

            if (!_synchronized)
            {
                string[] replacements = null;

                _aufenthalt.ClearData();
                _aufenthalt.AddLine(_x01.GetLine(null, true));

                if (_keyFieldChanged)
                {
                    replacements = _x01.GetKeyParts(5);
                }


                int index = 0;
                foreach (var a in _abteilungen)
                {
                    a._lastSyncIndex = index++;
                    _aufenthalt.AddLine(a.Line.GetLine(replacements, true));
                }

                index = 0;
                foreach (var l in _leistungen)
                {
                    l._lastSyncIndex = index++;
                    _aufenthalt.AddLine(l.Line.GetLine(replacements, true));
                }

                index = 0;
                foreach (var d in _diagnosen)
                {
                    d._lastSyncIndex = index++;
                    _aufenthalt.AddLine(d.Line.GetLine(replacements, true));
                }

                index = 0;
                foreach (var w in _akwarn)
                {
                    w._lastSyncIndex = index++;
                    _aufenthalt.AddLine(w.Line.GetLine(replacements, true));
                }

                _synchronized = true;
                _keyFieldChanged = false;
            }
            return _synchronized;
        }

        public void PlausCheck(Context context)
        {
            if (!_synchronized)
            {
                if (_aufenthalt == null)
                {
                    _aufenthalt = new LKFAufenthalt(context.C);
                }
                Synchronize();
            }
            C.PlausCheck(context.C);
        }

        public void Scoring(Context context)
        {
            if (!_synchronized)
                Synchronize();
            C.Scoring(context.C);
            var x05 = C.LineRESULT;
            if (!string.IsNullOrEmpty(x05))
                _x05 = new LKFLine(x05, this);
        }

        public void Execute(Context context)
        {
            PlausCheck(context);
            if (C.PlausFlag.CompareTo("4") < 0)
                Scoring(context);
            else
            {
                var x05 = C.LineRESULT;
                if (!string.IsNullOrEmpty(x05))
                    _x05 = new LKFLine(x05, this);
            }
        }

        public void PlausCheck()
        {
            if (!_synchronized)
                Synchronize();
            C.PlausCheck();
        }

        public void Scoring()
        {
            if (!_synchronized)
                Synchronize();
            C.Scoring();
            var x05 = C.LineRESULT;
            if (!string.IsNullOrEmpty(x05))
                _x05 = new LKFLine(x05, this);
        }

        public void Execute()
        {
            PlausCheck();
            if (C.PlausFlag.CompareTo("4") < 0)
                Scoring();
            else
            {
                var x05 = C.LineRESULT;
                if (!string.IsNullOrEmpty(x05))
                    _x05 = new LKFLine(x05, this);
            }
        }

        public enum AufenthaltPos : int { KANR = 1, AUFNR = 2, BMID = 3, AufDat = 4, AufZeit = 5, Behandlungsart = 6, GebDat = 7, Altersgruppe = 8, Geschlecht = 9, STAATB = 10, STAATW = 11, PLZW = 12,
                                          GEMCO = 13, AUFART1 = 14, AUFART2 = 15, TRANSPORTART = 16, KANR_VON = 17, KANR_AN = 18, ENTART = 19, ENTDAT = 20, ENTZEIT = 21, LEIST_KOST = 22,
                                          RELEVANZ = 23, FLAG = 24, UEB_KOST = 25, QUARTAL = 26};

        public string KANR
        {
            get
            {
                return _x01[(int)AufenthaltPos.KANR];
            }
            set
            {
                _x01[(int)AufenthaltPos.KANR] = value;
                _keyFieldChanged = true;
            }
        }

        public string AUFNR
        {
            get
            {
                return _x01[(int)AufenthaltPos.AUFNR];
            }
            set
            {
                _x01[(int)AufenthaltPos.AUFNR] = value;
                _keyFieldChanged = true;
            }
        }

        public string BMID
        {
            get
            {
                return _x01[(int)AufenthaltPos.BMID];
            }
            set
            {
                _x01[(int)AufenthaltPos.BMID] = value;
                _keyFieldChanged = true;
            }
        }

        public string AufDat
        {
            get
            {
                return _x01[(int)AufenthaltPos.AufDat];
            }
            set
            {
                _x01[(int)AufenthaltPos.AufDat] = value;
                _keyFieldChanged = true;
            }
        }

        public string AufZeit
        {
            get
            {
                return _x01[(int)AufenthaltPos.AufZeit];
            }
            set
            {
                _x01[(int)AufenthaltPos.AufZeit] = value;
                _keyFieldChanged = true;
            }
        }

        public string Behandlungsart
        {
            get
            {
                return _x01[(int)AufenthaltPos.Behandlungsart];
            }
            set
            {
                _x01[(int)AufenthaltPos.Behandlungsart] = value;
            }
        }

        public string GebDat
        {
            get
            {
                return _x01[(int)AufenthaltPos.GebDat];
            }
            set
            {
                _x01[(int)AufenthaltPos.GebDat] = value;
            }
        }

        public string Altersgruppe
        {
            get
            {
                return _x01[(int)AufenthaltPos.Altersgruppe];
            }
            set
            {
                _x01[(int)AufenthaltPos.Altersgruppe] = value;
            }
        }

        public string Geschlecht
        {
            get
            {
                return _x01[(int)AufenthaltPos.Geschlecht];
            }
            set
            {
                _x01[(int)AufenthaltPos.Geschlecht] = value;
            }
        }

        public string STAATB
        {
            get
            {
                return _x01[(int)AufenthaltPos.STAATB];
            }
            set
            {
                _x01[(int)AufenthaltPos.STAATB] = value;
            }
        }

        public string STAATW
        {
            get
            {
                return _x01[(int)AufenthaltPos.STAATW];
            }
            set
            {
                _x01[(int)AufenthaltPos.STAATW] = value;
            }
        }

        public string PLZW
        {
            get
            {
                return _x01[(int)AufenthaltPos.PLZW];
            }
            set
            {
                _x01[(int)AufenthaltPos.PLZW] = value;
            }
        }

        public string GEMCO
        {
            get
            {
                return _x01[(int)AufenthaltPos.GEMCO];
            }
            set
            {
                _x01[(int)AufenthaltPos.GEMCO] = value;
            }
        }



        public string AUFART1
        {
            get
            {
                return _x01[(int)AufenthaltPos.AUFART1];
            }
            set
            {
                _x01[(int)AufenthaltPos.AUFART1] = value;
            }
        }

        public string AUFART2
        {
            get
            {
                return _x01[(int)AufenthaltPos.AUFART2];
            }
            set
            {
                _x01[(int)AufenthaltPos.AUFART2] = value;
            }
        }

        public string TRANSPORTART
        {
            get
            {
                return _x01[(int)AufenthaltPos.TRANSPORTART];
            }
            set
            {
                _x01[(int)AufenthaltPos.TRANSPORTART] = value;
            }
        }

        public string KANR_VON
        {
            get
            {
                return _x01[(int)AufenthaltPos.KANR_VON];
            }
            set
            {
                _x01[(int)AufenthaltPos.KANR_VON] = value;
            }
        }

        public string KANR_AN
        {
            get
            {
                return _x01[(int)AufenthaltPos.KANR_AN];
            }
            set
            {
                _x01[(int)AufenthaltPos.KANR_AN] = value;
            }
        }

        public string ENTART
        {
            get
            {
                return _x01[(int)AufenthaltPos.ENTART];
            }
            set
            {
                _x01[(int)AufenthaltPos.ENTART] = value;
            }
        }

        public string ENTDAT
        {
            get
            {
                return _x01[(int)AufenthaltPos.ENTDAT];
            }
            set
            {
                _x01[(int)AufenthaltPos.ENTDAT] = value;
            }
        }

        public string ENTZEIT
        {
            get
            {
                return _x01[(int)AufenthaltPos.ENTZEIT];
            }
            set
            {
                _x01[(int)AufenthaltPos.ENTZEIT] = value;
            }
        }

        public string LEIST_KOST
        {
            get
            {
                return _x01[(int)AufenthaltPos.LEIST_KOST];
            }
            set
            {
                _x01[(int)AufenthaltPos.LEIST_KOST] = value;
            }
        }

        public string RELEVANZ
        {
            get
            {
                return _x01[(int)AufenthaltPos.RELEVANZ];
            }
            set
            {
                _x01[(int)AufenthaltPos.RELEVANZ] = value;
            }
        }

        public string FLAG
        {
            get
            {
                return _x01[(int)AufenthaltPos.FLAG];
            }
            set
            {
                _x01[(int)AufenthaltPos.FLAG] = value;
            }
        }

        public string UEB_KOST
        {
            get
            {
                return _x01[(int)AufenthaltPos.UEB_KOST];
            }
            set
            {
                _x01[(int)AufenthaltPos.UEB_KOST] = value;
            }
        }

        public string QUARTAL
        {
            get
            {
                return _x01[(int)AufenthaltPos.QUARTAL];
            }
            set
            {
                _x01[(int)AufenthaltPos.QUARTAL] = value;
            }
        }


        public IEnumerable<LKFLine> LKFLines
        {
            get
            {
                if (!_synchronized)
                    Synchronize();
                yield return _x01;
                foreach (var abt in _abteilungen)
                    yield return abt.Line;
                foreach (var diag in _diagnosen)
                    yield return diag.Line;
                foreach (var mel in _leistungen)
                    yield return mel.Line;
                if (_x05 != null)
                    yield return _x05;
                foreach (var akwarn in _akwarn)
                    yield return akwarn.Line;
//                if (_x07 != null)
//                    yield return _x07;
            }
        }


        public IEnumerable<string> Lines
        {
            get
            {
                if (!_synchronized)
                    Synchronize();
                yield return _x01.Line;
                foreach (var abt in _abteilungen)
                    yield return abt.Line.Line;
                foreach (var diag in _diagnosen)
                    yield return diag.Line.Line;
                foreach (var mel in _leistungen)
                    yield return mel.Line.Line;
                if (_x05 != null)
                    yield return _x05.Line;
                foreach (var akwarn in _akwarn)
                    yield return akwarn.Line.Line;
 //               if (_x07 != null)
 //                   yield return _x07.Line;
            }
        }

        public LKFLine Line => _x01;
        public LKFLine ResultLine => _x05;
        public LKFLine CommentLine => null; // _x07;

        public AufenthaltResult Result
        {
            get
            {
                if (_x05 != null)
                {
                    if (_aufenthaltResult == null)
                        _aufenthaltResult = new AufenthaltResult(this, _x05);
                    return _aufenthaltResult;
                }
                return null;
            }
        }
    }
}
