using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Script.Serialization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Xml;
using System.Xml.Serialization;
using Microsoft.FSharp.Collections;
using Microsoft.Win32;
using SqlDynamite.Common;

namespace SqlDynamite
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow
    {
        #region Fields

        public class DbObject
        {
            public string Name { get; set; }
            public string Type { get; set; }
            public string Database { get; set; }
            public string Schema { get; set; }
        }

        private static readonly string HistoryFile;
        private static readonly string LogFile;
        private readonly List<string> _words;
        private readonly ObservableCollection<Tuple<string, ObjectType, string, string>> _items;
        private readonly GridView _gridView;
        private readonly GridViewColumn _schemaColumn;
        private List<Tuple<string, ObjectType, string>> _objects;
        private string _serverType;
        private string _driver;
        private string _server;
        private string _database;
        private string _user;
        private string _password;
        private bool _sspi;
        private ConnectionType _connectionType;
        private Task _task;
        private CancellationTokenSource _cancellationTokenSource;
        private CancellationToken _cancellationToken;
        private HighlightDescriptor _searchDescriptor;

        #endregion

        #region Constructors

        static MainWindow()
        {
            string appdata = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
            if (!Directory.Exists(appdata + "\\SQL Dynamite"))
            {
                Directory.CreateDirectory(appdata + "\\SQL Dynamite");
            }
            HistoryFile = appdata + "\\SQL Dynamite\\SQL_Dynamite_HISTORY.txt";
            LogFile = appdata + "\\SQL Dynamite\\SQL_Dynamite_LOG.txt";
        }

        public MainWindow()
        {
            InitializeComponent();
            _gridView = new GridView();
            _schemaColumn = new GridViewColumn { Header = "Schema", DisplayMemberBinding = new Binding("Item4") };
            _gridView.Columns.Add(new GridViewColumn { Header = "Name", DisplayMemberBinding = new Binding("Item1") });
            _gridView.Columns.Add(new GridViewColumn { Header = "Type", DisplayMemberBinding = new Binding("Item2") });
            _gridView.Columns.Add(new GridViewColumn { Header = "Database", DisplayMemberBinding = new Binding("Item3") });
            list1.View = _gridView;
            _items = new ObservableCollection<Tuple<string, ObjectType, string, string>>();
            list1.ItemsSource = _items;
            _words = new List<string>();
            if (!File.Exists(HistoryFile))
            {
                File.CreateText(HistoryFile);
            }
            else
            {
                _words.AddRange(File.ReadAllLines(HistoryFile));
                _words.Reverse();
                foreach (string word in _words)
                {
                    Search.Items.Add(new ComboBoxItem { Content = word });
                }
            }
            progressBar1.Visibility = Visibility.Hidden;
            progressBar1.Value = 0;
            box1.Font = new Font("Courier New", 10);
        }

        #endregion

        #region Private Methods

        private ConnectionType GetConnectionType(string connectionTypeStr)
        {
            switch (connectionTypeStr)
            {
                case "ODBC": return ConnectionType.ODBC;
                case "OLEDB": return ConnectionType.OLEDB;
                default: return ConnectionType.NET;
            }
        }
        
        private List<ObjectType> FillTypes()
        {
            var types = new List<ObjectType>();
            if (SP_Check.IsChecked.Value) types.Add(ObjectType.PROCEDURE);
            if (FN_Check.IsChecked.Value) types.Add(ObjectType.FUNCTION);
            if (Table_Check.IsChecked.Value) types.Add(ObjectType.TABLE);
            if (View_Check.IsChecked.Value) types.Add(ObjectType.VIEW);
            if (TR_Check.IsChecked.Value) types.Add(ObjectType.TRIGGER);
            if (PK_Check.IsChecked.Value) types.Add(ObjectType.PRIMARY_KEY);
            if (FK_Check.IsChecked.Value) types.Add(ObjectType.FOREIGN_KEY);
            if (IX_Check.IsChecked.Value) types.Add(ObjectType.INDEX);
            if (Sequence_Check.IsChecked.Value) types.Add(ObjectType.SEQUENCE);
            if (Package_Check.IsChecked.Value) types.Add(ObjectType.PACKAGE);
            if (Synonym_Check.IsChecked.Value) types.Add(ObjectType.SYNONYM);
            if (Type_Check.IsChecked.Value) types.Add(ObjectType.TYPE);
            if (Job_Check.IsChecked.Value) types.Add(ObjectType.JOB);
            if (Report_Check.IsChecked.Value) types.Add(ObjectType.REPORT);
            if (Service_Broker_Check.IsChecked.Value) types.Add(ObjectType.SERVICE_QUEUE);
            if (Computed_Column_Check.IsChecked.Value) types.Add(ObjectType.COMPUTED_COLUMN);
            return types;
        }

        private void SearchObjects(MetadataFinder finder, List<ObjectType> types, CancellationTokenSource cancellationTokenSource)
        {
            _objects = new List<Tuple<string, ObjectType, string>>();
            bool[] boxes =
                               {
                                   Table_Check.IsChecked.Value,
                                   PK_Check.IsChecked.Value,
                                   FK_Check.IsChecked.Value,
                                   IX_Check.IsChecked.Value,
                                   SP_Check.IsChecked.Value,
                                   FN_Check.IsChecked.Value,
                                   View_Check.IsChecked.Value,
                                   TR_Check.IsChecked.Value,
                                   Sequence_Check.IsChecked.Value,
                                   Package_Check.IsChecked.Value,
                                   Synonym_Check.IsChecked.Value,
                                   Type_Check.IsChecked.Value,
                                   Job_Check.IsChecked.Value,
                                   Report_Check.IsChecked.Value,
                                   Service_Broker_Check.IsChecked.Value,
                                   Computed_Column_Check.IsChecked.Value,
                                   search_in_names.IsChecked.Value,
                                   search_in_def.IsChecked.Value,
                                   search_in_all_databases.IsChecked.Value
                               };
            box1.Text = "";
            btn_Search.IsEnabled = false;
            btn_Stop.IsEnabled = true;
            string query = search_in_names.IsChecked.Value
                               ? finder.GenerateNameScript(Search.Text.Trim(), types.Aggregate(FSharpList<ObjectType>.Empty, (current, type) => new FSharpList<ObjectType>(type, current)), match_case.IsChecked.Value)
                               : null;

            if (_task != null && _task.Status == TaskStatus.Running)
            {
                cancellationTokenSource.Cancel();
            }

            progressBar1.Visibility = Visibility.Visible;
            progressBar1.Value = 0;
            progressBar1.Maximum = 100;

            bool caseSensitive = match_case.IsChecked.Value;

            var objects = finder.SearchInNames(boxes, query, cancellationTokenSource);
            progressBar1.Value = 25;
            objects = MetadataFinder.JoinLists(objects, finder.SearchInDefinitionsByName(boxes, Search.Text.Trim().Replace("'", "''"), caseSensitive, cancellationTokenSource));
            progressBar1.Value = 50;
            objects = MetadataFinder.JoinLists(objects, finder.SearchInDefinitionsByContent(boxes, Search.Text.Trim().Replace("'", "''"), types.Aggregate(FSharpList<ObjectType>.Empty, (current, type) => new FSharpList<ObjectType>(type, current)), caseSensitive, cancellationTokenSource));
            progressBar1.Value = 100;
            _objects = new List<Tuple<string, ObjectType, string>>(objects);
            CompleteSearch();
        }

        private void SearchObjects(MetadataFinder finder, List<ObjectType> types)
        {
            _objects = new List<Tuple<string, ObjectType, string>>();
            bool[] boxes = 
                               {
                                   Table_Check.IsChecked.Value,
                                   PK_Check.IsChecked.Value,
                                   FK_Check.IsChecked.Value,
                                   IX_Check.IsChecked.Value,
                                   SP_Check.IsChecked.Value,
                                   FN_Check.IsChecked.Value,
                                   View_Check.IsChecked.Value,
                                   TR_Check.IsChecked.Value,
                                   Sequence_Check.IsChecked.Value,
                                   Package_Check.IsChecked.Value,
                                   Synonym_Check.IsChecked.Value,
                                   Type_Check.IsChecked.Value,
                                   Job_Check.IsChecked.Value,
                                   Report_Check.IsChecked.Value,
                                   Service_Broker_Check.IsChecked.Value,
                                   Computed_Column_Check.IsChecked.Value,
                                   search_in_names.IsChecked.Value,
                                   search_in_def.IsChecked.Value,
                                   search_in_all_databases.IsChecked.Value
                               };
            box1.Text = "";
            btn_Search.IsEnabled = false;
            btn_Stop.IsEnabled = true;
            string query = search_in_names.IsChecked.Value
                               ? finder.GenerateNameScript(Search.Text.Trim(), types.Aggregate(FSharpList<ObjectType>.Empty, (current, type) => new FSharpList<ObjectType>(type, current)), match_case.IsChecked.Value)
                               : null;
            SearchObjects(query, Search.Text.Trim().Replace("'", "''"), finder, types, boxes);
        }

        private void SearchObjects(string query, string searchStr, MetadataFinder finder, List<ObjectType> types,
            bool[] boxes)
        {
            _cancellationTokenSource = new CancellationTokenSource();
            _cancellationToken = _cancellationTokenSource.Token;

            if (_task != null && _task.Status == TaskStatus.Running)
            {
                _cancellationTokenSource.Cancel();
            }

            progressBar1.Visibility = Visibility.Visible;
            progressBar1.Value = 0;
            progressBar1.Maximum = 100;

            bool caseSensitive = match_case.IsChecked.Value;

            FSharpList<Tuple<string, ObjectType, string>> objects = null;

            _task = Task.Factory.StartNew(() =>
                {
                    objects = finder.SearchInNames(boxes, query, _cancellationTokenSource);
                }, _cancellationToken)
                .ContinueWith(task => progressBar1.Value = 25, TaskScheduler.FromCurrentSynchronizationContext())
                .ContinueWith(task => objects = MetadataFinder.JoinLists(objects, finder.SearchInDefinitionsByName(boxes, searchStr, caseSensitive, _cancellationTokenSource)), _cancellationToken)
                .ContinueWith(task => progressBar1.Value = 50, TaskScheduler.FromCurrentSynchronizationContext())
                .ContinueWith(task => objects = MetadataFinder.JoinLists(objects, finder.SearchInDefinitionsByContent(boxes, searchStr, types.Aggregate(FSharpList<ObjectType>.Empty, (current, type) => new FSharpList<ObjectType>(type, current)), caseSensitive, _cancellationTokenSource)), _cancellationToken)
                .ContinueWith(task => progressBar1.Value = 100, TaskScheduler.FromCurrentSynchronizationContext())
                .ContinueWith(task => _objects = new List<Tuple<string, ObjectType, string>>(objects), _cancellationToken)
                .ContinueWith(task => CompleteSearch(), TaskScheduler.FromCurrentSynchronizationContext());
        }

        private void FillListBox()
        {
            List<Tuple<string, ObjectType, string>> list = (from pair in _objects
                                                           let pair1 = pair
                                                           let keyFound = _items.Any(item => 
                                                                                     item.Item1 == pair1.Item1 &&
                                                                                     item.Item2.Equals(pair1.Item2) &&
                                                                                     item.Item3 == pair1.Item3)
                                                           where !keyFound
                                                           select pair).ToList();

            list.Sort(new TupleComparer());

            foreach (Tuple<string, ObjectType, string> tpl in list)
            {
                string[] parts = tpl.Item1.Split('.');
                string name = null;
                string schema = null;
                if (parts.Length == 2 && (!tpl.Item2.IsJOB || _serverType != "MSSQL"))
                {
                    name = parts[1];
                    schema = parts[0];
                }
                _items.Add(Tuple.Create(string.IsNullOrWhiteSpace(name) ? tpl.Item1 : name, tpl.Item2, tpl.Item3, parts.Length == 2 ? schema : null));
            }
            Msg.Content = list1.Items.Count + " objects found";
        }

        private void FillConnections()
        {
            string currentConnection = Connections.Text;
            Connections.Items.Clear();
            IEnumerable<Tuple<string, bool>> cns;
            try
            {
                cns = XmlUtil.SelectConfig(ListWindow.ConfigFile);
            }
            catch (Exception exc)
            {
                MessageBox.Show(exc.GetExceptionMessages());
                return;
            }
            foreach (Tuple<string, bool> cn in cns)
            {
                ComboBoxItem item = new ComboBoxItem { Content = cn.Item1 };
                Connections.Items.Add(item);
            }
            Connections.Text = currentConnection;
        }

        private void SetSearchMarkers()
        {
            box1.CaseSensitive = match_case.IsChecked.Value;
            string st = Search.Text.Trim();
            bool hasUnderline = st.StartsWith("_") || st.EndsWith("_");
            bool hasPercent = st.StartsWith("%") || st.EndsWith("%");
            if (hasUnderline || hasPercent)
            {
                st = st.Trim('_', '%');
            }
            string[] strings = st.Split(' ');
            var searchStrings = from s in strings
                                where !string.IsNullOrWhiteSpace(s.Trim())
                                select match_case.IsChecked.Value ? s : s.ToLower();
            foreach (string searchString in searchStrings)
            {
                _searchDescriptor = new HighlightDescriptor(searchString, ConfigWindow.SyntaxProvider.SearchColor, ConfigWindow.SyntaxProvider.SearchBackgroundColor,
                                                            new Font(box1.Font, System.Drawing.FontStyle.Underline),
                                                            DescriptorType.Word, DescriptorRecognition.Contains);
                box1.HighlightDescriptors.Add(_searchDescriptor);
            }
        }

        private void CompleteSearch()
        {
            FillListBox();
            btn_Stop.IsEnabled = false;
            btn_Search.IsEnabled = true;
            progressBar1.Visibility = Visibility.Hidden;
        }

        private void ShowDefinition(string searchStr, MetadataFinder finder, ObjectType type, string db)
        {
            try
            {
                if (_serverType == "Informix")
                {
                    var parts = _database.Split('/');
                    if (parts.Length > 1)
                    {
                        parts[1] = db;
                        db = string.Join("/", parts);
                    }
                }
                string cstring = finder.MakeConnectionString(_driver, _server, db, _user, _password, _sspi,
                    _connectionType);
                finder.EstablishConnection(cstring, _connectionType, db);
            }
            catch (Exception exception)
            {
                File.AppendAllText(LogFile, $"{DateTime.Now}: {exception.GetExceptionMessages()}{Environment.NewLine}");
                return;
            }

            if (finder._connection == null || finder is InformixMetadataFinder || finder is InterbaseMetadataFinder || 
                finder is UltraliteMetadataFinder || finder is MongoDbMetadataFinder || finder is CassandraMetadataFinder ||
                finder is RedisMetadataFinder || finder is SybaseAdvantageMetadataFinder || finder is Neo4jMetadataFinder)
            { }
            else
            {
                ConfigWindow.SyntaxProvider.SetKeywordColors(finder);
            }

            ConfigWindow.SyntaxProvider.InitializeSyntaxHighlighter(box1, syntax_highlighting.IsChecked.Value);

            SetSearchMarkers();

            _cancellationTokenSource = new CancellationTokenSource();
            _cancellationToken = _cancellationTokenSource.Token;

            if (_task != null && _task.Status == TaskStatus.Running)
            {
                _cancellationTokenSource.Cancel();
            }

            string content = null;

            try
            {
                _task = Task.Factory.StartNew(() => content = finder.RetrieveDefinition(searchStr, type, _cancellationTokenSource), _cancellationToken)
                    .ContinueWith(task => box1.Text = content, TaskScheduler.FromCurrentSynchronizationContext());
            }
            catch (Exception exc)
            {
                MessageBox.Show(exc.GetExceptionMessages(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        #endregion

        #region Event Handlers

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            FillConnections();
            if (Connections.Items.Count > 0)
            {
                IEnumerable<Tuple<string, bool>> confs;
                try
                {
                    confs = XmlUtil.SelectConfig(ListWindow.ConfigFile);
                }
                catch (Exception exc)
                {
                    MessageBox.Show(exc.GetExceptionMessages());
                    return;
                }
                foreach (Tuple<string, bool> conf in confs)
                {
                    if (conf.Item2)
                    {
                        Connections.Text = conf.Item1;
                        break;
                    }
                }
                if (string.IsNullOrWhiteSpace(Connections.Text))
                {
                    Connections.SelectedIndex = 0;
                }
            }
            else
            {
                ConfigWindow configWindow = new ConfigWindow { Owner = this, ShowInTaskbar = false };
                if (configWindow.ShowDialog().Value)
                {
                    try
                    {
                        XmlUtil.InsertConfig(ListWindow.ConfigFile, configWindow.ConnectionName.Text, configWindow.ServerType.Text,
                            configWindow.Driver.Text, configWindow.Server.Text,
                            configWindow.Database.Text, configWindow.User.Text,
                            configWindow.Password.Password, configWindow.SSPI.IsChecked.Value.ToString(),
                            configWindow.GetConnectionType().ToString());
                        FillConnections();
                        if (Connections.Items.Count > 0)
                        {
                            Connections.SelectedIndex = 0;
                        }
                    }
                    catch (Exception exc)
                    {
                        MessageBox.Show(exc.GetExceptionMessages());
                    }
                }
            }
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            Msg.Content = "";
            MetadataFinder finder = ConfigWindow.CreateMetadataFinder(_serverType, false);
            if (finder == null) return;
            var types = FillTypes();
            if (types.Count == 0) return;
            if (search_in_names.IsChecked.Value == false && search_in_def.IsChecked == false) return;
            if (!string.IsNullOrWhiteSpace(Search.Text) && !_words.Contains(Search.Text.Trim()))
            {
                _words.Add(Search.Text.Trim());
                Search.Items.Insert(0, new ComboBoxItem {Content = Search.Text.Trim()});
                File.AppendAllText(HistoryFile, Search.Text.Trim() + Environment.NewLine);
            }
            _items.Clear();
            try
            {
                string cstring = finder.MakeConnectionString(_driver, _server, _database, _user, _password,
                    _sspi, _connectionType);
                finder.EstablishConnection(cstring, _connectionType, _database);
            }
            catch (Exception exception)
            {
                File.AppendAllText(LogFile, $"{DateTime.Now}: {exception.GetExceptionMessages()}{Environment.NewLine}");
                MessageBox.Show(exception.GetExceptionMessages(), "Error while establishing connection", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            if (search_in_all_databases.IsChecked.Value)
            {
                var dbs = finder.GetDatabaseList("Databases");
                try
                {
                    btn_Search.IsEnabled = false;
                    foreach (string db in dbs)
                    {
                        if (!MetadataFinderHelper.SystemDbs[_serverType].Contains(db))
                        {
                            if (_serverType == "Informix")
                            {
                                var parts = db.Split('/');
                                if (parts.Length > 1 && MetadataFinderHelper.SystemDbs[_serverType].Contains(parts[1]))
                                {
                                    continue;
                                }
                            }
                            string cstring = finder.MakeConnectionString(_driver, _server, db, _user, _password,
                            _sspi, _connectionType);
                            finder.EstablishConnection(cstring, _connectionType, db);
                            _cancellationTokenSource = new CancellationTokenSource();
                            _cancellationToken = _cancellationTokenSource.Token;
                            SearchObjects(finder, types, _cancellationTokenSource);
                        }
                    }
                }
                catch (Exception exception)
                {
                    File.AppendAllText(LogFile, $"{DateTime.Now}: {exception.GetExceptionMessages()}{Environment.NewLine}");
                    MessageBox.Show(exception.GetExceptionMessages(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                }
                finally
                {
                    btn_Search.IsEnabled = true;
                }
            }
            else
            {
                SearchObjects(finder, types);
            }
        }

        private void button2_Click(object sender, RoutedEventArgs e)
        {
            ListWindow listWindow = new ListWindow { ShowInTaskbar = false, Owner = this };
            listWindow.ShowDialog();
            FillConnections();
            if (!string.IsNullOrWhiteSpace(listWindow.NewConnectionName))
            {
                for (int index = 0; index < Connections.Items.Count; index++)
                {
                    if (((ComboBoxItem)Connections.Items[index]).Content.ToString() == listWindow.NewConnectionName)
                    {
                        Connections.SelectedIndex = index;
                        break;
                    }
                }
            }
        }

        private void button3_Click(object sender, RoutedEventArgs e)
        {
            SP_Check.IsChecked =
                FN_Check.IsChecked =
                Table_Check.IsChecked =
                View_Check.IsChecked =
                TR_Check.IsChecked =
                PK_Check.IsChecked =
                FK_Check.IsChecked =
                IX_Check.IsChecked =
                Package_Check.IsChecked =
                Sequence_Check.IsChecked =
                Synonym_Check.IsChecked =
                Type_Check.IsChecked =
                Job_Check.IsChecked =
                Report_Check.IsChecked =
                Service_Broker_Check.IsChecked =
                Computed_Column_Check.IsChecked = true;
        }

        private void button4_Click(object sender, RoutedEventArgs e)
        {
            SP_Check.IsChecked =
                FN_Check.IsChecked =
                Table_Check.IsChecked =
                View_Check.IsChecked =
                TR_Check.IsChecked =
                PK_Check.IsChecked =
                FK_Check.IsChecked =
                IX_Check.IsChecked =
                Package_Check.IsChecked =
                Sequence_Check.IsChecked =
                Synonym_Check.IsChecked =
                Type_Check.IsChecked =
                Job_Check.IsChecked =
                Report_Check.IsChecked =
                Service_Broker_Check.IsChecked =
                Computed_Column_Check.IsChecked = false;
        }

        private void button5_Click(object sender, RoutedEventArgs e)
        {
            _cancellationTokenSource.Cancel();
        }

        private void Connections_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (Connections.SelectedItem != null)
            {
                ServerInfo crs;
                try
                {
                    crs = XmlUtil.SelectConfig(ListWindow.ConfigFile, ((ComboBoxItem)Connections.SelectedItem).Content.ToString());
                }
                catch (Exception exc)
                {
                    MessageBox.Show(exc.GetExceptionMessages());
                    return;
                }
                if (crs != null)
                {
                    _serverType = crs.ServerType;
                    _driver = crs.Driver;
                    _server = crs.Server;
                    _database = crs.Database;
                    _user = crs.User;
                    _password = crs.Password;
                    _sspi = bool.Parse(crs.SSPI);
                    _connectionType = GetConnectionType(crs.ConnectionType);
                    search_in_all_databases.IsEnabled =
                        _serverType == "MSSQL" || _serverType == "SAP ASE" ||
                        _serverType == "MySQL" || _serverType == "Informix" ||
                        _serverType == "PostgreSQL" || _serverType == "Redis" ||
                        _serverType == "Cassandra" || _serverType == "MongoDb" ||
                        _serverType == "SQL Azure" ||
                        _serverType == "SQL Analysis Services";
                    if (!search_in_all_databases.IsEnabled) search_in_all_databases.IsChecked = false;
                    if (_serverType == "MSSQL" || _serverType == "SAP ASE" ||
                        _serverType == "SAP Anywhere" || _serverType == "SAP IQ" ||
                        _serverType == "PostgreSQL" || _serverType == "Ingres" ||
                        _serverType == "DB2" || _serverType == "Informix" ||
                        _serverType == "Vertica" || _serverType == "Oracle" || 
                        _serverType == "SQL Azure" || _serverType == "SAP HANA" ||
                        _serverType == "SQL Analysis Services")
                    {
                        _schemaColumn.Header = _serverType == "SQL Analysis Services" ? "Cube" : "Schema";
                        if (!_gridView.Columns.Contains(_schemaColumn))
                            _gridView.Columns.Insert(0, _schemaColumn);
                    }
                    else
                    {
                        if (_gridView.Columns.Contains(_schemaColumn))
                            _gridView.Columns.Remove(_schemaColumn);
                    }
                }
            }
        }

        private void syntax_highlighting_Checked(object sender, RoutedEventArgs e)
        {
            if (box1 == null) return;
            ConfigWindow.SyntaxProvider.InitializeSyntaxHighlighter(box1, true);
            SetSearchMarkers();
            box1.Text = box1.Text;
        }

        private void syntax_highlighting_Unchecked(object sender, RoutedEventArgs e)
        {
            if (box1 == null) return;
            ConfigWindow.SyntaxProvider.InitializeSyntaxHighlighter(box1, false);
            SetSearchMarkers();
            box1.Text = box1.Text;
        }

        private void word_wrap_Checked(object sender, RoutedEventArgs e)
        {
            box1.WordWrap = true;
        }

        private void word_wrap_Unchecked(object sender, RoutedEventArgs e)
        {
            box1.WordWrap = false;
        }

        private void match_case_Changed(object sender, RoutedEventArgs e)
        {
            ConfigWindow.SyntaxProvider.InitializeSyntaxHighlighter(box1, syntax_highlighting.IsChecked.Value);
            SetSearchMarkers();
            box1.Text = box1.Text;
        }

        private void btn_SaveList_Click(object sender, RoutedEventArgs e)
        {
            SaveFileDialog sfd = new SaveFileDialog {Filter = "CSV Files|*.csv|XML Files|*.xml|JSON Files|*.json"};
            if (sfd.ShowDialog(this).GetValueOrDefault(false))
            {
                var dbObjects = new List<DbObject>();
                foreach (object item in list1.Items)
                {
                    var tuple = item as Tuple<string, ObjectType, string, string>;
                    dbObjects.Add(new DbObject
                    {
                        Name = tuple.Item1,
                        Type = tuple.Item2.ToString(),
                        Database = tuple.Item3,
                        Schema = tuple.Item4
                    });
                }
                if (sfd.FilterIndex == 1)
                {
                    StringBuilder csv = new StringBuilder();
                    if (_serverType == "SQL Analysis Services")
                        csv.Append("Name,Type,Database,Cube" + Environment.NewLine);
                    else
                        csv.Append("Name,Type,Database,Schema" + Environment.NewLine);
                    foreach (DbObject dbObject in dbObjects)
                    {
                        csv.Append($"{dbObject.Name},{dbObject.Type},{dbObject.Database},{dbObject.Schema}{Environment.NewLine}");
                    }
                    File.WriteAllText(sfd.FileName, csv.ToString());
                }
                else if (sfd.FilterIndex == 2)
                {
                    XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<DbObject>));
                    using (XmlWriter xmlWriter = XmlWriter.Create(sfd.FileName, new XmlWriterSettings { Indent = true }))
                    {
                        xmlSerializer.Serialize(xmlWriter, dbObjects);
                    }
                }
                else if (sfd.FilterIndex == 3)
                {
                    JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
                    string json = javaScriptSerializer.Serialize(dbObjects);
                    File.WriteAllText(sfd.FileName, DataUtil.FormatJson(json));
                }
            }
        }

        private void btn_DbInfo_Click(object sender, RoutedEventArgs e)
        {
            MetadataFinder finder = ConfigWindow.CreateMetadataFinder(_serverType, false);
            if (finder == null)
                return;
            try
            {
                string cstring = finder.MakeConnectionString(_driver, _server, _database, _user, _password, _sspi, _connectionType);
                finder.EstablishConnection(cstring, _connectionType, _database);
                if (finder._connection != null)
                {
                    MessageBox.Show(finder._connection.ServerVersion, "Server version", MessageBoxButton.OK, MessageBoxImage.None);
                }
            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.GetExceptionMessages(), "Error while getting DB info", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private void btn_About_Click(object sender, RoutedEventArgs e)
        {
            new WpfAboutBox(this).ShowDialog();
        }

        private void Search_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                button1_Click(sender, null);
            }
        }

        private void list1_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (list1.Items.Count > 0 && list1.SelectedIndex != -1)
            {
                MetadataFinder finder = ConfigWindow.CreateMetadataFinder(_serverType, true);

                if (finder == null) return;

                SetSearchMarkers();

                box1.Text = "";
                var tpl = (Tuple<string, ObjectType, string, string>)list1.Items[list1.SelectedIndex];
                string searchStr = tpl.Item4 != null ? tpl.Item4 + "." + tpl.Item1 : tpl.Item1;
                ObjectType type = tpl.Item2;
                string db;
                if (_serverType == "SQLite" || _serverType == "SAP Anywhere" || _serverType == "SAP IQ")
                    db = _database;
                else
                    db = tpl.Item3;
                ShowDefinition(searchStr, finder, type, string.IsNullOrWhiteSpace(db) ? _database : db);
            }
        }

        #endregion
    }
}