using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using IndianHealthService.BMXNet.Model;
using System.Data;
using IndianHealthService.BMXNet.Services;
 

namespace IndianHealthService.BMXNet.WinForm
{
    public class DesktopSession : DesktopObject, Session
    {
        
        private DesktopFramework _framework= null;

        public DesktopFramework Framework
        {
            get { return _framework; }
            set { _framework = value; }
        }

        public BMXNetSession Bmx
        {
            get { return this.Framework.Bmx; }
        }

    

        public void Open(DesktopFramework aFramework,DesktopContext aContext)
        {
            this.Framework = aFramework;
            this.DesktopContext = aContext;
        }

        public List<Visit> VisitsFor(Patient aPatient)
        {

            return this.FetchVisits(aPatient);

        }

        public virtual Patient FindPatientFromChart(String aChart, bool updateSelf)
        {
            String rawData = null;

            try    {

                if (aChart.Length == 2 && (Char.IsLetter(aChart[0])))
                {
                    rawData = this.Bmx.TransmitRPC("VEN CF GET DEMO PT DFN", aChart, "VEN RPC");
                }
                else
                {
                    rawData = this.Bmx.TransmitRPC("VEN GET PATIENT IDENTIFIERS", aChart, "VEN RPC");
                }

                rawData=rawData.Trim();

                if (rawData.Length==0) {
                    return null;
                }

                DesktopPatient patient = new DesktopPatient();

                String[] peices = rawData.Split(new char[] { '|' });
                patient.Ien = peices[0].Trim();
                patient.PatientName = peices[1].Trim();
                patient.PatientName = patient.PatientName;
                patient.Age = int.Parse(peices[2].Trim());
                patient.Dob = DateTime.Parse(peices[3].Trim());
                patient.PrimaryProvider = peices[4];
                patient.Sex = (peices[5].Equals("M") ? "MALE" : "FEMALE");
                patient.HealthRecordNumber = aChart;

                return patient;
            }
            catch
            {
                return null;
            }
        }

        public List<Visit> Visits
        {
            get { return this.FetchVisits(this.Context.Patient); }
        }

        protected List<Visit> FetchVisits(Patient aPatient)
        {
            List<Visit> answer = new List<Visit>();

            if (aPatient == null)
            {
                return answer;
            }
            else
            {
                //Interesting to add to BMX
                DataTable visits = this.Bmx.TableFromRPC("VEN CF LIST VISITS", aPatient.Ien, "VEN RPC");

                foreach (DataRow each in visits.Rows)
                {
                    DesktopVisit visit = new DesktopVisit();
                    visit.FillFromRow(each);
                    answer.Add(visit);
                }
                return answer;
            }
        }


        private DesktopContext _desktopContext = null;

        public DesktopContext DesktopContext
        {
            get { return this._desktopContext; }
            set { this._desktopContext = value; }
        }

        public Context Context
        {
            get
            {
                return this.DesktopContext;
            }
        }


        public User User
        {
            get { return this.Framework.User; }
        }

        
        #region Session Members

        protected EventRegistry EventRegistry
        {
            get
            {
                return this.Framework.EventRegistry;
            }
        }

        public event EventHandler<ApplicationEventArgs> ApplicationEvent;

        public void FireLocalEvent(string anEvent, string aStub)
        {
            this.EventRegistry.TriggerEvent(anEvent, aStub);       
        }

        public void FireRemoteEvent(string anEventName, string someDetails)
        {

        }


        public void IncomingEventCallback(String anEventType, String aStub)
        {
            //Cascade "well-known" events here
            if ("REFRESH".Equals(anEventType))
            {
                this.FireRefreshRequestedEvent();
            }
            else
            {
                this.FireApplicationEvent(anEventType, aStub);
            }
        }

        private void FireRefreshRequestedEvent()
        {
            if (this.refreshRequested != null)
            {
                this.refreshRequested.Invoke(this, new EventArgs());
            }
        }

        private void FireApplicationEvent(String anEventType, String aStub)
        {
            ApplicationEventArgs args = new ApplicationEventArgs();
            args.EventType = anEventType;
            args.Stub = aStub;

            if (this.ApplicationEvent != null)
            {
                try
                {
                    this.ApplicationEvent.Invoke(this, args);
                }
                catch
                {
                    //TODO: Decide what to do in case of error.  For now, do not 
                    //disrupt work.
                }
            }
        }

   
        public void Subscribe(string anEventName)
        {
            this.EventRegistry.Subscribe(anEventName, this);
        }

  
        public bool HasSubscribers(string anEventName)
        {
            return this.EventRegistry.HasSubscribers(anEventName);
        }

     
        public void Unsubscribe(string anEventName)
        {
            this.EventRegistry.Unsubscribe(anEventName, this);
        }

        private ILog _logger = new NullLog();

        public ILog Logger
        {
            get { return _logger; }
            set { _logger = value; }
        }

        EventHandler refreshRequested;
        public event EventHandler RefreshRequested
        {
            add
            {
                refreshRequested = (EventHandler)Delegate.Combine(refreshRequested, value);
                if (!this.HasSubscribers("REFRESH"))
                {
                    this.Subscribe("REFRESH");
                }
            }
            remove
            {
                refreshRequested = (EventHandler)Delegate.Remove(refreshRequested, value);
                if (this.HasSubscribers("REFRESH"))
                {
                    this.Unsubscribe("REFRESH");
                }
            }
        }

        #endregion

        public void Log(string aClass, string aCategory, params string[] lines)
        {
            if (this.Logger.IsLogging)
            {
                this.LogLines(aClass, aCategory, lines);
            }
        }

        public void Log(string aClass, string aCategory, Exception anException, params string[] lines)
        {
            if (this.Logger.IsLogging)
            {
                this.LogLines(aClass, aCategory, lines);
                this.LogException(aClass, aCategory, anException);
            }
         }

        protected void LogLines(string aClass, string aCategory, params string[] someLines)
        {
            foreach (string each in someLines)
            {
                String message = null;

                if (each.StartsWith("***"))
                {
                    String header = each.Substring(0, each.IndexOf("***", 4) + 3 ).Trim();
                    message = each.Substring(3 + 3 + header.Length - 1).Trim();

                    if (header.Length > 0)
                    {
                        this.Logger.Log(aClass,aCategory,header);
                    }
                }
                else
                {
                    message = each;
                }

                if (message.Length > 0)
                {
                    this.Logger.Log(aClass,aCategory,message);
                }
            }
        }

        protected void LogException(string aClass, string aCategory, Exception anException)
        {
            this.Logger.Log(aClass, aCategory, "Exception" + ((anException.InnerException != null) ? " (w/Inner)" : ""));
            this.Logger.Log(aClass, aCategory, anException.Message);
            this.Logger.Log(aClass, aCategory, anException.StackTrace);

            if (anException.InnerException != null)
            {
                this.Logger.Log(aClass, aCategory, "Inner Exception");
                this.Logger.Log(aClass, aCategory, anException.InnerException.Message);
                this.Logger.Log(aClass, aCategory, anException.InnerException.StackTrace);
            }
        }


        #region Session Members


        public bool IsLogging
        {
            get { return this.Logger.IsLogging; }
        }

        #endregion
    }
}