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


namespace IndianHealthService.BMXNet.WinForm.Model
{
    internal class WinSession : WinObject, LocalSession, LocalEventService
    {
        public User NewUser(String aName, String anIen, Division aDivision)
        {
            WinUser user = new WinUser();
            user.Ien = anIen;
            user.Name = aName;
            user.Division = aDivision;
            return user;
        }
   


        
        private WinFramework _framework= null;

        public WinFramework Framework
        {
            get { return _framework; }
            set
            {
                _framework = value;
                this.RemoteSession = this._framework.PrimaryRemoteSession;
            }
        }
  
        public void Open(WinFramework aFramework,WinContext aContext)
        {
            this.Framework = aFramework;
            this.DesktopContext = aContext;
        }


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

            try    {

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

                rawData=rawData.Trim();

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

                WinPatient patient = new WinPatient();

                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.Framework.Visits(this.Context.Patient,50); }
        }

        private WinContext _desktopContext = null;

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

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

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

        
        #region Session Members

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

        public event EventHandler<LocalEventArgs> ApplicationEvent;

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

        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 someDetails)
        {
            LocalEventArgs args = new LocalEventArgs();
            args.EventType = anEventType;
            args.Details = someDetails;

            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 Log _logger = new NullLog();

        public Log 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; }
            set { this.Logger.IsLogging = value; }
        }


        #endregion

        #region Session Members


        public void Close()
        {
            this.Framework.Close(this);
        }

        #endregion

       
        public LocalEventService EventServices
        {
            get { return this; }
        }



        #region LocalSession Members


        public void Notify(String aTitle, Exception anException)
        {
            ExceptionMessageDialog.SafeShow(aTitle, anException);
        }

        public void Notify(String aTitle, String aMessage)
        {
            MessageBox.Show(aMessage, aTitle);
        }

        #endregion
    }
}