using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Diagnostics;
using System.Reflection;
using System.Windows.Data;
using System.Data;
using Sched.CustomClasses;
using System.Windows.Input;
using Microsoft.Win32;
using System.IO;

namespace Sched.CustomControls
{
    public class EditTableForm : Grid
    {
        private string _className;
        private Type _classType;
        private object _classInstance;
        private DataTable _DTable;
        private DataView _DView;
        private DataGrid _DG;
        private Assembly _assem;

        public EditTableForm()
        {

        }

        public EditTableForm(string className)
        {
            Type t = typeof(Curriculum);    //All the classes are defined in the same namespace as this class
            _assem = t.Assembly;
            object c = _assem.CreateInstance(t.Namespace + "." + className);
            this.CreateForm(c, className);
        }

        void CreateForm(object classInstance, string className)
        {
            this._className = className;
            this._classInstance = classInstance;
            this._classType = classInstance.GetType();

            int nProperties = classInstance.GetType().GetProperties().Length;

            //Construct Grid
            int nCols = 2;
            int nRows = nProperties + 3; //+1 Label (+ buttons), +1 allTableData +1 SaveButton

            for (int i = 0; i < nCols; i++)
            {
                ColumnDefinition colDef = new ColumnDefinition();
                if (i == 0)
                {
                    colDef.Width = GridLength.Auto;
                }
                ColumnDefinitions.Add(colDef);
            }
            for (int i = 0; i < nRows; i++)
            {
                RowDefinition rowDef = new RowDefinition();
                rowDef.Height = GridLength.Auto;
                if (i == (nRows - 2))   //only DataGrid will get set height
                {
                    rowDef.Height = new GridLength(240.0);
                }
                RowDefinitions.Add(rowDef);
            }

            //Label
            Label lbl = new Label();
            lbl.SetResourceReference(Label.ContentProperty, "Str_" + className);
            lbl.FontSize = 16;
            lbl.FontWeight = FontWeights.Bold;
            Grid.SetRow(lbl, 0);
            Grid.SetColumn(lbl, 0);
            Grid.SetColumnSpan(lbl, 2);
            this.Children.Add(lbl);

            //Margin
            Thickness rightMargin = new Thickness(0, 0, 20, 0);

            //Buttons
            Button btnAdd = new Button();
            btnAdd.SetResourceReference(Button.ContentProperty, "DB_BTN_Add");
            btnAdd.Click += BTN_Add_Click;
            btnAdd.Margin = rightMargin;

            Button btnCSVImport = new Button();
            btnCSVImport.SetResourceReference(Button.ContentProperty, "DB_BTN_ImportCSV");
            btnCSVImport.Click += BTN_CSVImport_Click;
            btnCSVImport.Margin = new Thickness(0, 0, 5, 0);

            Button btnCSVExport = new Button();
            btnCSVExport.SetResourceReference(Button.ContentProperty, "DB_BTN_ExportCSV");
            btnCSVExport.Click += BTN_CSVExport_Click;
            btnCSVExport.Margin = new Thickness(0, 0, 5, 0);

            StackPanel btnPanel = new StackPanel();
            btnPanel.Orientation = Orientation.Horizontal;
            Grid.SetRow(btnPanel, 0);
            Grid.SetColumn(btnPanel, 1);
            btnPanel.HorizontalAlignment = HorizontalAlignment.Right;
            btnPanel.VerticalAlignment = VerticalAlignment.Center;
            btnPanel.Children.Add(btnCSVImport);
            btnPanel.Children.Add(btnCSVExport);
            btnPanel.Children.Add(btnAdd);
            this.Children.Add(btnPanel);

            Button btnSaveChanges = new Button();
            btnSaveChanges.SetResourceReference(Button.ContentProperty, "DB_BTN_SaveChangesToDatabase");
            btnSaveChanges.Click += BTN_SaveChanges_Click;
            btnSaveChanges.Margin = rightMargin;
            Grid.SetRow(btnSaveChanges, nRows-1);
            Grid.SetColumn(btnSaveChanges, 1);
            btnSaveChanges.HorizontalAlignment = HorizontalAlignment.Right;
            this.Children.Add(btnSaveChanges);


            //TextBlocks + Other UI Elements
            PropertyInfo[] pInfoArray = classInstance.GetType().GetProperties();
            for (int i = 0; i < nProperties; i++)
            {
                PropertyInfo PropInfo = pInfoArray[i];
                string PropName = PropInfo.Name;

                TextBlock tBlock = new TextBlock();
                tBlock.SetResourceReference(TextBlock.TextProperty, "Str_" + PropName);
                tBlock.FontWeight = FontWeights.Bold;
                tBlock.Margin = new Thickness(20, 5, 20, 5);

                Grid.SetRow(tBlock, i + 1);
                Grid.SetColumn(tBlock, 0);
                this.Children.Add(tBlock);

                UIElement propCtrl;
                Binding propBind = new Binding(PropName);
                propBind.Source = this._classInstance;
                
                if ((PropName.Contains("Id")) && (PropName != "Id"))    // aka the property name has the form "classnameId"
                {
                    propCtrl = new ComboBox();
                    string propClassName = PropName.Substring(0,PropName.Length - 2);
                    ((ComboBox)propCtrl).ItemsSource = DBI.GetItems(propClassName);

                    ((ComboBox)propCtrl).Name = PropName;
                    ((ComboBox)propCtrl).SelectionChanged += CB_SelectionChanged;
                    ((ComboBox)propCtrl).Margin = rightMargin;   
                }
                else if (PropInfo.PropertyType == typeof(DateTime))
                {
                    propCtrl = new DatePicker();
                    ((DatePicker)propCtrl).Background = Brushes.White;
                    ((DatePicker)propCtrl).SetBinding(DatePicker.SelectedDateProperty, propBind);
                    ((DatePicker)propCtrl).Margin = rightMargin;
                }
                else
                {
                    propCtrl = new TextBox();
                    ((TextBox)propCtrl).SetBinding(TextBox.TextProperty, propBind);
                    ((TextBox)propCtrl).Margin = rightMargin;
                }
                
                Grid.SetRow(propCtrl, i + 1);
                Grid.SetColumn(propCtrl, 1);
                this.Children.Add(propCtrl);
            }

            //Table
            DataGrid dataG = new DataGrid();
            _DG = dataG;
            _DG.AutoGeneratingColumn += DG_AutoGeneratingColumn;
            _DTable = DBI.GetTableByName(_className);
            _DView = _DTable.DefaultView;
            _DG.ItemsSource = _DView;
            _DG.HeadersVisibility = DataGridHeadersVisibility.Column;
            dataG.CanUserAddRows = false;
            //dataG.CanUserDeleteRows = false;

            ScrollViewer scrollV = new ScrollViewer();
            scrollV.Content = dataG;
            scrollV.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
            scrollV.Margin = new Thickness(20, 5, 20, 5);
            Grid.SetRow(scrollV, nRows - 2);
            Grid.SetColumn(scrollV, 0);
            Grid.SetColumnSpan(scrollV, 2);
            this.Children.Add(scrollV);
        }

        private void BTN_CSVExport_Click(object sender, RoutedEventArgs e)
        {
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.Filter = "CSV (*.csv)|*.csv";
            dlg.DefaultExt = ".csv";
            if ((bool)dlg.ShowDialog())
            {
                using (StreamWriter sw = new StreamWriter(dlg.FileName, false))      //(path,append)
                {
                    string separator = ";";

                    try
                    {   //Columns
                        string colNames = "";
                        for (int j = 0; j < _DTable.Columns.Count; j++)
                        {
                            if (colNames.Length > 0)
                            { 
                                colNames += separator;
                            }
                            colNames += _DTable.Columns[j].ColumnName;
                        }
                        sw.WriteLine(colNames);

                        //Rows
                        for (int i = 0; i < _DTable.Rows.Count; i++)
                        {
                            string fields = "";
                            for (int j = 0; j < _DTable.Columns.Count; j++)
                            {
                                if (fields.Length > 0)
                                {
                                    fields += separator;
                                }
                                fields += _DTable.Rows[i][j].ToString();
                            }
                            sw.WriteLine(fields);
                        }

                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                }

            }
        }

        private void BTN_CSVImport_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.DefaultExt = ".csv";
            dlg.Filter = "CSV (*.csv)|*.csv";
            if ((bool)dlg.ShowDialog()) {
                string separator = ";";

                using (StreamReader sr = new StreamReader(dlg.FileName))
                {
                    List<String> colNames = new List<string>();
                    string colNamesStr = "";
                    for (int i = 0; i < _DTable.Columns.Count; i++)
                    {
                        colNames.Add(_DTable.Columns[i].ColumnName);
                        if (colNamesStr.Length > 0)
                        {
                            colNamesStr += separator + " ";
                        }
                        colNamesStr += _DTable.Columns[i].ColumnName;
                    }

                    try
                    {
                        //Columns
                        string[] fileColNames = ((string)sr.ReadLine()).Split(separator, StringSplitOptions.None);  //
                        for (int i = 0; i < _DTable.Columns.Count; i++)
                        {
                            if ((colNames.Count != fileColNames.Length) || (fileColNames[i] != colNames[i]))
                            {
                                string msg = (string)Application.Current.Resources.MergedDictionaries[App._languageResDictIndex]["BTN_ImportCSV_header_msgEx_ColNames"];
                                throw new Exception(msg);
                            }
                        }
                        DBI.InsertCSVValues(dlg.FileName, this._classInstance, separator);
                    }
                    catch (Exception ex)
                    {
                        string msgSeparator = (string)Application.Current.Resources.MergedDictionaries[App._languageResDictIndex]["BTN_ImportCSV_header_msgEx_Separator"];
                        string msgColNames = (string)Application.Current.Resources.MergedDictionaries[App._languageResDictIndex]["BTN_ImportCSV_header_msgEx_CorrectColNames"];
                        MessageBox.Show(ex.Message + ".\n\n" +
                                            msgSeparator + ":   " + separator + "\n" +
                                            msgColNames + ": " + colNamesStr);
                    }

                }

                _DTable = DBI.GetTableByName(_className);
                _DView = _DTable.DefaultView;
                _DG.ItemsSource = _DView;
            }
        }

        private void DG_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
        {
            string colheader = "Str_" + e.Column.Header.ToString();
            e.Column.Header = (string)Application.Current.Resources.MergedDictionaries[App._languageResDictIndex][colheader];
            if (e.PropertyType == typeof(DateTime))
            {
                ((DataGridTextColumn)e.Column).Binding.StringFormat = System.Globalization.DateTimeFormatInfo.InvariantInfo.SortableDateTimePattern;
            }
        }
        private void CB_SelectionChanged(object sender, RoutedEventArgs e)
        {
            var CB = sender as ComboBox;
            if (CB != null)
            {
                string propName = CB.Name;  //eg. CurriculumId

                //Get "Id" from chosen object
                int id = (int)(CB.SelectedItem.GetType().GetProperty("Id")).GetValue(CB.SelectedItem);

                //Pass the "Id" value to the object associated with the the input form
                (_classInstance.GetType().GetProperty(propName)).SetValue(_classInstance, id);
                //Debug.WriteLine((_classInstance.GetType().GetProperty(propName)).GetValue(_classInstance));
            }
            
        }
        private void BTN_Add_Click(object sender, RoutedEventArgs e)
        {
            bool IsIdValid = true;
            //Debug.WriteLine(_classType.GetProperty("Id").GetValue(_classInstance));
            if (_classType.GetProperty("Id") != null)
            {
                int id = (int)(_classType.GetProperty("Id").GetValue(_classInstance));
                if (id == 0)  //0 means it has not been assigned yet
                {
                    IsIdValid = false;
                }
            }

            DBI.InsertRow(_classInstance, IsIdValid);

            _DTable = DBI.GetTableByName(_className);
            _DView = _DTable.DefaultView;
            _DG.ItemsSource = _DView; 
        }
        private void BTN_SaveChanges_Click(object sender, RoutedEventArgs e)
        {
            DBI.UpdateTable(_DTable);

            //Get updated view
            _DTable = DBI.GetTableByName(_className);
            _DView = _DTable.DefaultView;
            _DG.ItemsSource = _DView;
        }

        public void DG_Filter(string searchString)
        {
            string filter = string.Empty;
            if (searchString != string.Empty)
            {
                
                for (int i = 0; i < _DTable.Columns.Count; i++)
                {
                    DataColumn DataCol = _DTable.Columns[i];
                    Type colDataType = DataCol.DataType;
                    if (colDataType.Equals(typeof(System.Int64)) || colDataType.Equals(typeof(System.Int32)))  //it's int column
                    {
                        int num = 0;
                        if (int.TryParse(searchString, out num))     //the search is entirely number
                        {
                            if (filter != string.Empty) //there's already a condition
                            {
                                filter += " OR ";
                            }
                            filter += DataCol.ToString() + " = " + searchString;
                        }
                    }
                    if (colDataType == typeof(string))     //it's string column
                    {
                        if (filter != string.Empty) //there's already a condition
                        {
                            filter += " OR ";
                        }
                        filter += _DTable.Columns[i].ToString() + " LIKE '%" + searchString + "%'";
                    }
                }
            }
            _DView.RowFilter = filter;   
        }
    }
}
