using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Data;

namespace VSview
{
    public class TerminalViewModel : BaseViewModel
    {
        private MainViewModel ViewModel;

        private object _lock = new object();
        #region Constructors
        /// <summary>
        /// Default constructor
        /// </summary>
        public TerminalViewModel(MainViewModel mainViewModel)
        {
            //Create reference to main view model
            ViewModel = mainViewModel;
            //setup command collection
            SetupCommands();
            //Create log object
            TerminalLog = new ObservableCollection<LogLine>();
            //Enable collection to be modified from any thread - using lock
            BindingOperations.EnableCollectionSynchronization(TerminalLog, _lock);

            SelectedEnquiryIndex = -1;
            SelectedCommandIndex = -1;
        }

        #endregion

        #region Public properties
        /// <summary>
        /// Stores content of command console for sending
        /// </summary>
        public string ConsoleContent { get; set; }

        /// <summary>
        /// Information about last selected Command/Enquiry
        /// </summary>
        public string SelectionInfo { get; set; }

        /// <summary>
        /// Selected command from command list
        /// </summary>
        public Command SelectedCommand { get; set; }

        /// <summary>
        /// Index of selected command
        /// </summary>
        public int SelectedCommandIndex { get; set; }

        /// <summary>
        /// Selected enquiry from enquiry list
        /// </summary>
        public Enquiry SelectedEnquiry { get; set; }

        /// <summary>
        /// Index of selected enquiry
        /// </summary>
        public int SelectedEnquiryIndex { get; set; }

        /// <summary>
        /// Terminal log string storage
        /// </summary>
        public static ObservableCollection<LogLine> TerminalLog { get; set; }

        #endregion

        #region Commands
        /// <summary>
        /// Dictionary of all command related to terminal tab
        /// </summary>
        public Dictionary<string, RelayCommand> Command { get; set; }

        /// <summary>
        /// Method for creating command dictionary
        /// </summary>
        private void SetupCommands()
        {
            //Create new instance of dictionary for terminal commands
            Command = new Dictionary<string, RelayCommand>();

            //Insert terminal commands
            Command.Add("CopyCommand", new RelayCommand(CopyToConsole_Command));
            Command.Add("CopyEnquiry", new RelayCommand(CopyToConsole_Enquiry));
            Command.Add("SendCommand", new RelayCommand(SendCommand));
            Command.Add("Service1", new RelayCommand(SendService1));
            Command.Add("Service2", new RelayCommand(SendService2));
            Command.Add("CopyToConsole", new RelayCommand(CopyToConsole_CommandEnquiry));
            Command.Add("CommandChanged", new RelayCommand(SelectionChangedCommand));
            Command.Add("EnquiryChanged", new RelayCommand(SelectionChangedEnquiry));
            Command.Add("LostFocusCommand", new RelayCommand(LostFocusCommand));
            Command.Add("LostFocusEnquiry", new RelayCommand(LostFocusEnquiry));
            Command.Add("ClearTerminal", new RelayCommand(ClearTerminal));
            Command.Add("SaveTerminal", new RelayCommand(SaveTerminal));
            Command.Add("OpenManual", new RelayCommand(OpenManual));
        }


        /// <summary>
        /// Method for copying selected command to the command console
        /// </summary>
        /// <param name="obj"></param>
        private void CopyToConsole_Command(object obj)
        {
            try
            {
                ConsoleContent = SelectedCommand.Name;
            }
            catch (Exception ex) { MessageBox.Show("Unable to copy enquiry to the console. \n Reason: " + ex.Message, "Terminal Error", MessageBoxButton.OK, MessageBoxImage.Warning); }
        }

        /// <summary>
        /// Method for copying selected enquiry to the command console
        /// </summary>
        /// <param name="obj"></param>
        private void CopyToConsole_Enquiry(object obj)
        {
            try
            {
                ConsoleContent = SelectedEnquiry.Name;
            }
            catch (Exception ex) { MessageBox.Show("Unable to copy enquiry to the console. \n Reason: " + ex.Message, "Terminal Error", MessageBoxButton.OK, MessageBoxImage.Warning); }
        }

        /// <summary>
        /// Method for copying selected command/enquiry to the command console
        /// </summary>
        /// <param name="obj"></param>
        private void CopyToConsole_CommandEnquiry(object obj)
        {
            try
            {
                if (SelectedCommandIndex >= 0)
                    ConsoleContent = SelectedCommand.Name;
                else if (SelectedEnquiryIndex >= 0)
                    ConsoleContent = SelectedEnquiry.Name;
            }
            catch (Exception ex) { MessageBox.Show("Unable to copy command or enquiry to the console. \n Reason: " + ex.Message, "Terminal Error", MessageBoxButton.OK, MessageBoxImage.Warning); }
        }

        /// <summary>
        /// Method for storing last selected command and displaying information from active resource file
        /// </summary>
        /// <param name="obj"></param>
        private void SelectionChangedCommand(object obj)
        {
            try
            {
                if (SelectedCommandIndex >= 0)
                    SelectionInfo = SelectedCommand.Information;
            }
            catch (Exception ex) { MessageBox.Show("Unable to get information from selected command. \n Reason: " + ex.Message, "Terminal Error", MessageBoxButton.OK, MessageBoxImage.Warning); }
        }

        /// <summary>
        /// Method for storing last selected enquiry and displaying information from active resource file
        /// </summary>
        /// <param name="obj"></param>
        private void SelectionChangedEnquiry(object obj)
        {
            try
            {
                if (SelectedEnquiryIndex >= 0)
                    SelectionInfo = SelectedEnquiry.Information;
            }
            catch (Exception ex) { MessageBox.Show("Unable to get information from selected enquiry. \n Reason: " + ex.Message, "Terminal Error", MessageBoxButton.OK, MessageBoxImage.Warning); }
        }

        /// <summary>
        /// Method for unselecting last selected command
        /// This method makes sure that selection change event will fire even if selecting same command over and over
        /// Used for updating command information textbox
        /// </summary>
        /// <param name="obj"></param>
        private void LostFocusCommand(object obj)
        {
            try
            {
                SelectedCommandIndex = -1;
            }
            catch (Exception ex) { MessageBox.Show("Unable to unselect command", "Terminal Error", MessageBoxButton.OK, MessageBoxImage.Warning); }
        }

        /// <summary>
        /// Method for unselecting last selected enquiry
        /// This method makes sure that selection change event will fire even if selecting same enquiry over and over
        /// Used for updating enquiry information textbox
        /// </summary>
        /// <param name="obj"></param>
        private void LostFocusEnquiry(object obj)
        {
            try
            {
                SelectedEnquiryIndex = -1;
            }
            catch (Exception ex) { MessageBox.Show("Unable to unselect enquiry", "Terminal Error", MessageBoxButton.OK, MessageBoxImage.Warning); }
        }

        /// <summary>
        /// Method for sending command from the command console
        /// </summary>
        /// <param name="obj"></param>
        private void SendCommand(object obj)
        {
            try
            {
                ViewModel.Detector.SendToDetector(ConsoleContent, true);
            }
            catch (Exception ex) { MessageBox.Show("Error during writing to detector send queue. Reason: " + ex.Message, "Terminal Error", MessageBoxButton.OK, MessageBoxImage.Warning); }
        }

        /// <summary>
        /// Method for sending SERVICE1 command
        /// </summary>
        /// <param name="obj"></param>
        private void SendService1(object obj)
        {
            try
            {
                ViewModel.Detector.SendToDetector("SERVICE1", true);
            }
            catch (Exception ex) { MessageBox.Show("Error during writing to detector send queue. Reason: " + ex.Message, "Terminal Error", MessageBoxButton.OK, MessageBoxImage.Warning); }
        }

        /// <summary>
        /// Method for sending SERVICE2 command
        /// </summary>
        /// <param name="obj"></param>
        private void SendService2(object obj)
        {
            try
            {
                ViewModel.Detector.SendToDetector("SERVICE2", true);
            }
            catch (Exception ex) { MessageBox.Show("Error during writing to detector send queue. Reason: " + ex.Message, "Terminal Error", MessageBoxButton.OK, MessageBoxImage.Warning); }
        }

        /// <summary>
        /// Method for clearing terminal log
        /// </summary>
        /// <param name="obj"></param>
        private void ClearTerminal(object obj)
        {
            try
            {
                if (TerminalLog != null && TerminalLog.Count > 0)
                    TerminalLog.Clear();
            }
            catch (Exception ex) { MessageBox.Show("Error during writing to detector send queue. Reason: " + ex.Message, "Terminal Error", MessageBoxButton.OK, MessageBoxImage.Warning); }
        }

        /// <summary>
        /// Method for saving actual terminal content
        /// </summary>
        /// <param name="obj"></param>
        private void SaveTerminal(object obj)
        {
            try
            {
                new Thread(() =>
                {
                    string VSviewPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Labtech", "VSview", "Exports");

                    if (!Directory.Exists(VSviewPath))
                        Directory.CreateDirectory(VSviewPath);

                    SaveFileDialog dialog = new SaveFileDialog()
                    {
                        InitialDirectory = VSviewPath,
                        Filter = "TXT files(.txt)|*.txt|all Files(*.*)|*.*",
                        DefaultExt = ".txt",
                        FilterIndex = 1,
                        RestoreDirectory = true
                    };

                    if (dialog.ShowDialog() == true)
                    {
                        StreamWriter streamWriter = new StreamWriter(dialog.FileName);
                        StringBuilder stringBuilder = new StringBuilder();

                        stringBuilder.Append("Date");
                        stringBuilder.Append(",");
                        stringBuilder.Append("Time");
                        stringBuilder.Append(",");
                        stringBuilder.Append("Text");

                        streamWriter.WriteLine(stringBuilder);

                        stringBuilder.Clear();
                        streamWriter.Flush();

                        foreach (LogLine line in TerminalLog)
                        {
                            stringBuilder.Append(line.Date);
                            stringBuilder.Append(",");
                            stringBuilder.Append(line.Time);
                            stringBuilder.Append(",");
                            stringBuilder.Append(line.Text);

                            streamWriter.WriteLine(stringBuilder);

                            stringBuilder.Clear();
                            streamWriter.Flush();
                        }
                    }
                }).Start();
            }
            catch (Exception ex) { MessageBox.Show("Error during saving terminal file. Reason: " + ex.Message, "Terminal Error", MessageBoxButton.OK, MessageBoxImage.Warning); }
        }

        /// <summary>
        /// Method for opening Manual
        /// </summary>
        /// <param name="obj"></param>
        private void OpenManual(object obj)
        {
            try
            {
                string path = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.FullName + @"\View\Manuals\VS manual.pdf";
                string FinalPath = path.Replace(@"\\", @"\");

                Process process = new Process();
                ProcessStartInfo startInfo = new ProcessStartInfo()
                {
                    Arguments = "/A \"page=211=OpenActions\"",
                    FileName = FinalPath
                };
                process.StartInfo = startInfo;
                process.Start();

            }
            catch (Exception ex)
            {
                MessageBox.Show("Could not open manual.\n Reason: " + ex.Message, "Terminal Error", MessageBoxButton.OK, MessageBoxImage.Warning);
            }
        }

        #endregion

        #region Public methods

        /// <summary>
        /// Method for adding text to log
        /// </summary>
        /// <param name="text"></param>
        public static void WriteToLog(string text)
        {
            try
            {
                if (TerminalLog != null && !string.IsNullOrEmpty(text))
                {
                    LogLine line = new LogLine(text);
                    TerminalLog.Add(line);                    
                }
            }
            catch (Exception ex) { MessageBox.Show("Error occured while writing to log. \nReason: " + ex.Message, "Terminal Error", MessageBoxButton.OK, MessageBoxImage.Warning); }
        }
        #endregion
    }
}
