using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using IndianHealthService.BMXNet.WinForm;
using IndianHealthService.BMXNet.WinForm.Configuration;
using System.Reflection;
using System.IO;
using IndianHealthService.BMXNet.Model;
using IndianHealthService.BMXNet.WinForm.Model;
using IndianHealthService.BMXNet.Services;
using IndianHealthService.BMXNet.Net;
using IndianHealthService.BMXNet.Util;

namespace IndianHealthService.BMXNet.Tools.ComponentTestBench
{
    public partial class ComponentTestBenchMainWindow : Form
    {

        public ComponentTestBenchMainWindow(UserControl aControl)
        {
            InitializeComponent();
            this.ConstructorProvidedControl = aControl;
        }

        public ComponentTestBenchMainWindow()
        {
            InitializeComponent();
        }

        private UserControl _constructorProvidedControl = null;

        public UserControl ConstructorProvidedControl
        {
            get { return _constructorProvidedControl; }
            set { _constructorProvidedControl = value; }
        }

        private WinFramework _framework = null;

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

        private RemoteSession _remoteSession = null;

        public RemoteSession RemoteSession
        {
            get { return _remoteSession; }
            set { _remoteSession = value; }
        }


        private void WindowsApplicationMainWindow_Load(object sender, EventArgs e)
        {
            bool usePrimarySession = this.Framework == null;

            if (this.Framework == null)
            {
                this.Framework = WinFramework.CreateWithNetworkBroker(true,(Log)this.logTranscriptControl1);
                this.Framework.HardCodedSettings.Set("SetHardcodedSettingsHereOrAnywhere", "Hello");
                //Settings are tierted ... Command-line / Persistent / hardcoded
                this.Framework.LoadSettings(LocalPersistentStore.CreateIn(Environment.SpecialFolder.LocalApplicationData, EntryAssemblyInfo.AssemblyCompany + "/" + EntryAssemblyInfo.AssemblyProduct, false), "settings");
                this.Framework.LoadConnectionSpecs(LocalPersistentStore.CreateIn(Environment.SpecialFolder.LocalApplicationData, EntryAssemblyInfo.AssemblyCompany + "/" + EntryAssemblyInfo.AssemblyProduct, false), "connections");
          
                if (this.Framework.ConnectionSettings.ConnectionSpecs.Count == 0)
                {
                    try
                    {
                        Assembly priorAssembly = Assembly.LoadFrom("PriorBmxForEvidence/BMXNet30.dll");
                        this.Framework.LoadConnectionSpecsAndMergeWithExistingBMXConfiguration(priorAssembly, LocalPersistentStore.CreateDefaultStorage(true), "MyApplication", "v5");
                    }
                    catch
                    {
                    }
                }

                LoginProcess login = this.Framework.CreateLoginProcess();
                login.AttemptingLogin += new EventHandler<AttemptingLoginEventArgs>(login_AttemptingLogin);

                login.LoginAttempted += new EventHandler<LoginAttemptedEventArgs>(login_LoginAttempted);
                if (login.HasDefaultConnectionWithUseWindowsAuth)
                {
                    login.AttemptWindowsAuthLogin();
                }

                if (!login.WasLoginAttempted || !login.WasSuccessful)
                {
                    login.AttemptUserInputLogin("BMXNet Testbench Login", 3, !this.Framework.BootStrapSettings.Get("lockedit", false), this);
                }

                if (!login.WasSuccessful)
                {
                    this.Close();
                    return;
                }
                LocalSession local = this.Framework.LocalSession;

                if ((this.Framework.User.Division==null) && !this.Framework.AttemptUserInputSetDivision("Set Initial Division", this))
                {
                    this.Close();
                    return;
                }
            }

            if (usePrimarySession) {
                this.RemoteSession =this.Framework.PrimaryRemoteSession;
            } else {
                this.RemoteSession = this.Framework.RemoteSessionPool.OpenSession((Log)this.logTranscriptControl1);
                this.changeUserToolStripMenuItem.Enabled = false;
            }
            
            this.RemoteSession.SendTimeout= 20000;
            this.RemoteSession.ReceiveTimeout = 20000;
            
            this.AddControl();

            this.Framework.Context.Changed += new EventHandler<ContextChangedArgs>(Context_Changed);
            this.currentCheckBox.Checked = this.Framework.BootStrapSettings.Get("CurrentVisit", true);
            this.patientCombo.Focus();

            this.UpdateTitle();
        }

        void login_AttemptingLogin(object sender, AttemptingLoginEventArgs e)
        {
            e.Process.ConnectionSpec.SendTimeout = 10000;
            e.Process.ConnectionSpec.ReceiveTimeout= 10000;
        }

        /// <summary>
        /// Example for providing another broker key so key can be routinely updated by application/broker
        /// developers.
        /// </summary>
        /// <param name="aBroker"></param>
       // protected void RekeyBroker(BMXNetBroker aBroker)
      //  {
       //     this.Framework.Broker.EncryptionProvider = BmxAdeEncryptionProvider.Keyed(new string[2]);
      //  }

        void login_LoginAttempted(object sender, LoginAttemptedEventArgs e)
        {
            this.Framework.Log.Log("Bench", "Login", e.WasSuccessful ? "Succesful Login" : e.Process.FailureMessage);
            e.Cancel = false;
        }

        private Context _managedContext = null;

        public Context ManagedContext
        {
            get { return _managedContext; }
            set { _managedContext = value; }
        }

        void Context_Changed(object sender, ContextChangedArgs e)
        {
            if (e.IsPatientChange)
            {
                if (e.IsPatientChange && e.AfterContext.Patient == null)
                {
                    this.patientCombo.Items.Clear();
                    this.patientCombo.Text = "";
                }
                this.UpdateVisits();
            }
        }



        private String _componentClassName;

        public String ComponentClassName
        {
            get { return _componentClassName; }
            set { _componentClassName = value; }
        }
        private String _componentAssemblyName;

        public String ComponentAssemblyName
        {
            get { return _componentAssemblyName; }
            set { _componentAssemblyName = value; }
        }

        private void AddControl(UserControl aControl)
        {
            try
            {
                (aControl as LocalConsumer).LocalSession = this.Framework.LocalSession;
                (aControl as RemoteSessionConsumer).RemoteSession = this.RemoteSession;
                aControl.Dock = DockStyle.Fill;

                this.controlPanel.Controls.Clear();
                this.controlPanel.Controls.Add(aControl);
            }
            catch (Exception problem)
            {
                this.Framework.LocalSession.Notify("Unable to create control from command line " + Environment.CommandLine,problem);
            }
        }

        private void AddControl()
        {
            if (this.ConstructorProvidedControl != null)
            {
                this.AddControl(this.ConstructorProvidedControl);
            }
            else if (this.Framework.BootStrapSettings.Get("assembly", "").Length == 0)
            {
                return;
            }
            else
            {
                try
                {
                    Assembly componentAssembly = Assembly.LoadFrom(this.Framework.BootStrapSettings.Get("assembly", ""));
                    UserControl control = (UserControl)componentAssembly.CreateInstance(this.Framework.BootStrapSettings.Get("class", ""));
                    this.AddControl(control);
                }
                catch
                {
                    MessageBox.Show("Unable to create control from command line " + Environment.CommandLine);
                }
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            AboutDialog dialog = new AboutDialog();
            dialog.ShowDialog(this);
        }


        public Patient SelectedPatient
        {
            get { return (Patient)this.patientCombo.SelectedItem; }
        }

        private void patientCombo_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this.SelectedPatient == this.Framework.Context.Patient)
            {
                return;
            }

            if (!this.Framework.ChangePatient(this.SelectedPatient, this.overrideContextVeto.Checked))
            {
                this.Framework.LocalSession.Notify("Patient Change Vetoed", "Unable to change patient");
                this.patientCombo.SelectedItem = this.Framework.Context.Patient;
            }
        }

        private void UpdateVisits()
        {
            this.visitComboBox.BeginUpdate();
            this.visitComboBox.Items.Clear();
            if (this.SelectedPatient != null)
            {
                List<Visit> visits = this.Framework.Visits(this.SelectedPatient, 20);
                this.visitComboBox.Items.AddRange(visits.ToArray());
                this.visitComboBox.SelectedIndex = (this.currentCheckBox.Checked ? Math.Min(visits.Count - 1, 0) : -1);
            }
            this.visitComboBox.EndUpdate();
        }

        private void findButton_Click(object sender, EventArgs e)
        {
            this.DoSearch();
        }

        protected void DoSearch()
        {

            List<Patient> found = this.Framework.FindPatients(this.patientCombo.Text.ToUpper(), 20);

            this.patientCombo.BeginUpdate();
            this.patientCombo.Items.Clear();
            foreach (Patient each in found)
            {
                this.patientCombo.Items.Add(each);
            }

            if (found.Count == 1)
            {
                this.patientCombo.SelectedItem = found[0];
            }
            else if (found.Count == 0)
            {
                this.patientCombo.Text = "<No patients found>";
                this.patientCombo.Focus();
            }
            else
            {
                this.patientCombo.Text = found.Count.ToString() + " patients found...";
            }

            this.patientCombo.EndUpdate();
        }

        private void patientCombo_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                this.DoSearch();
            }
        }

        private void resetButton_Click(object sender, EventArgs e)
        {
            this.Framework.ChangePatient(this.Framework.Context.Patient,this.overrideContextVeto.Checked);
        }

        private void refreshButton_Click(object sender, EventArgs e)
        {
            this.Framework.TriggerLocalEvent("REFRESH", "UserSelected");
        }

        public Visit SelectedVisit
        {
            get { return (Visit)this.visitComboBox.SelectedItem; }
        }


        private void visitComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this.SelectedVisit == this.Framework.Context.Visit)
            {
                return;
            }

            if (!this.Framework.ChangeVisit(this.SelectedVisit, this.overrideContextVeto.Checked))
            {
                this.Framework.LocalSession.Notify("Visit Change Vetoed", "Unable to change visit");
                this.visitComboBox.SelectedItem = this.Framework.Context.Visit;
            }
        }

        private void divisionButton_Click(object sender, EventArgs e)
        {
            if (this.Framework.AttemptUserInputSetDivision("Change Divsion @ " + DateTime.Now.ToLongTimeString(), this))
            {
                this.patientCombo.Items.Clear();
                this.patientCombo.Text = null;
                this.patientCombo.Focus();
            }

        }

        private void keyEntry_TextChanged(object sender, EventArgs e)
        {
            this.keyEntry.BackColor = Color.White;
        }

        private void keyButton_Click(object sender, EventArgs e)
        {
            this.keyEntry.BackColor = this.Framework.User.HasSecurityKey(this.keyEntry.Text.Trim()) ? Color.LightGreen : Color.Red;
        }

        private void aboutDialogToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new AboutDialog().ShowDialog(this);
        }

        private void bMXVersionInfoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //  DataTable peek = this.Framework.Bmx.VersionInfo;
            this.NotYetImplemented();
        }

        private void NotYetImplemented()
        {
            MessageBox.Show("Not yet implement", "Demo App Message");
        }

        private void WindowsApplicationMainWindow_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (this.RemoteSession != null)
            {
                this.RemoteSession.Close();
            }
        }

        private void spawnSessionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ComponentTestBenchMainWindow window = new ComponentTestBenchMainWindow();
            window.Framework = this.Framework;
            window.Show();
        }

        public void UpdateTitle()
        {
            this.Text = "BMXNet Testbench :: " + this.RemoteSession.ToString();
        }

        private void closeRemoteSessionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.RemoteSession.Close();
        }

        private void remoteTriggerButton_Click(object sender, EventArgs e)
        {
            String eventName = this.remoteEventTriggerCombo.Text.Trim();
            String eventParam = this.remoteParamTriggerCombo.Text.Trim();

            if (eventName.Length > 0)
            {
                int result = this.RemoteSession.EventServices.TriggerEvent(eventName, eventParam, this.remoteCallBackCheck.Checked);
            }
        }

        private void localTriggerButton_Click(object sender, EventArgs e)
        {
            String eventName = this.localEventTriggerCombo.Text.Trim();
            String eventParam = this.localParamTriggerCombo.Text.Trim();

            if (eventName.Length > 0)
            {
                this.Framework.TriggerLocalEvent(eventName, eventParam);
            }
        }

        private void logViewerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.showLogTranscriptToolStripMenuItem.Checked = !this.showLogTranscriptToolStripMenuItem.Checked;
            this.componentTranscriptSplitter.Panel2Collapsed = !this.showLogTranscriptToolStripMenuItem.Checked;
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Type componentType = null;
            OpenFileDialog open = new OpenFileDialog();
            open.Filter = "BMX Component (*.dll)|*.dll";
            if (open.ShowDialog(this) == DialogResult.OK)
            {
                //Find RemoteConsumer or LocalConsumer
                Assembly target = Assembly.LoadFile(open.FileName);
                foreach (Type each in target.GetTypes())
                {
                    foreach (Type eachInterface in each.GetInterfaces())
                    {
                        if (eachInterface.Equals(typeof(LocalConsumer)) || eachInterface.Equals(typeof(RemoteSessionConsumer)))
                        {
                            componentType = each;
                            break;
                        }
                    }
                    if (componentType != null)
                    {
                        break;
                    }
                }
            }
            if (componentType != null)
            {       
                this.AddControl((UserControl)Activator.CreateInstance(componentType));
            }
        }

        private void changeDivisionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Framework.AttemptUserInputSetDivision("Reset Division", this);
        }

        private void changeUserToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Framework.Close();
            this.controlPanel.Controls.Clear();

            this.Framework = WinFramework.CreateWithNetworkBroker(true, (Log)this.logTranscriptControl1);
            this.Framework.LoadSettings(LocalPersistentStore.CreateIn(Environment.SpecialFolder.LocalApplicationData, EntryAssemblyInfo.AssemblyCompany + "/" + EntryAssemblyInfo.AssemblyProduct, false), "settings");
            this.Framework.LoadConnectionSpecs(LocalPersistentStore.CreateIn(Environment.SpecialFolder.LocalApplicationData, EntryAssemblyInfo.AssemblyCompany + "/" + EntryAssemblyInfo.AssemblyProduct, false), "connections");
            
            if (this.Framework.ConnectionSettings.ConnectionSpecs.Count == 0)
            {
                try
                {
                    Assembly priorAssembly = Assembly.LoadFrom("PriorBmxForEvidence/BMXNet30.dll");
                    this.Framework.LoadConnectionSpecsAndMergeWithExistingBMXConfiguration(priorAssembly, LocalPersistentStore.CreateDefaultStorage(true), "MyApplication", "v5");
                }
                catch
                {
                }
            }

            LoginProcess login = this.Framework.CreateLoginProcess();

            login.IsSwitchServerModeEnabled = true;
            login.LoginAttempted += new EventHandler<LoginAttemptedEventArgs>(login_LoginAttempted);
            login.AttemptUserInputLogin("BMXNet Testbench Login", 3, true, this);

            if (!login.WasSuccessful)
            {
                this.Close();
                return;
            }
            LocalSession local = this.Framework.LocalSession;

            if (!this.Framework.AttemptUserInputSetDivision("Set Initial Division", this))
            {
                this.Close();
                return;
            }

            this.RemoteSession = this.Framework.PrimaryRemoteSession;

            this.AddControl();

            this.Framework.Context.Changed += new EventHandler<ContextChangedArgs>(Context_Changed);
            this.currentCheckBox.Checked = this.Framework.BootStrapSettings.Get("CurrentVisit", true);
            this.patientCombo.Focus();

            this.UpdateTitle();
        }

 

      
    }
}