using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Navigation;

using BeWo.Controls;
using BeWo.Core;
using BeWo.ServiceProxy;
using BeWo.View.Search;

using BS.Shared;
using BS.Shared.Core;
using BS.Shared.DataContracts;
using BS.Shared.DataContracts.Compact;
using BS.Shared.Extensions;

using DevExpress.Xpf.Editors;
using DevExpress.Xpf.Grid;

using BeWo.Core.Service;

using Microsoft.Win32;

namespace BeWo.View.Detail.Report
{
    /// <summary>
    /// Interaction logic for QueryView.xaml
    /// </summary>
    public partial class QueryView : BeWoView
    {
        private readonly Dictionary<string, UIElement> parameterUIElements = new Dictionary<string, UIElement>();

        private CompactEmployeeDC lastSelectedEmployee;
        private CompactCustomerDC lastSelectedCustomer;

        public QueryView(IEnumerable<QueryDC> pQueries)
        {
            try
            {
                InitializeComponent();

                var filteredList = pQueries.Where(LoggedOnUserHasRightForQuery).ToList();

                combo_query.ItemsSource = filteredList;
                textblock_link.Visibility = Visibility.Collapsed;
                textblock_link_pdfexport.Visibility = Visibility.Collapsed;

                DownloadLinkEngine = new DownloadLinkEngine();
                linkExcelExport.NavigateUri = DownloadLinkEngine.GenerateNewExcelLink();

                btnExecuteQuery.Visibility = Visibility.Collapsed;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public DownloadLinkEngine DownloadLinkEngine { get; set; }

        public override string Title
        {
            get
            {
                return "öffentliche Abfragen";
            }
        }

        private DateEdit CreateDateEdit()
        {
            var dtp = new DateEdit
                {
                    Margin = new Thickness(3),
                    Background = Brushes.White,
                    Foreground = Brushes.Black,
                    BorderThickness = new Thickness(1),
                    BorderBrush = Application.Current.FindResource("TextBoxBorderBrush") as Brush,
                    Width = 90
                };
            //dtp.TodayContent = "Heute";

            return dtp;
        }

        private ComboBox CreateMonthCombo()
        {
            var comboboxMonth = new ComboBox
                {
                    ItemsSource = DateTimeFormatInfo.CurrentInfo.MonthNames.Where(s => !string.IsNullOrEmpty(s))
                };

            var firstOfMonth = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
            comboboxMonth.SelectedIndex = firstOfMonth.Subtract(new TimeSpan(1, 0, 0, 0)).Month - 1;
            comboboxMonth.Width = 100;
            return comboboxMonth;
        }

        private ComboBox CreateValueListEntryCombo(ValueListEntryType t)
        {
            var combobox = new ComboBox();

			Cache.GetInstance().GetAllValueListEntrysByTypeAsync(t,
                                                            cb => this.Dispatch(
                                                                delegate
                                                                    {
                                                                        var items = new List<ValueListEntryDC>();
                                                                        var dummy = new ValueListEntryDC
                                                                            {
                                                                                ValueListEntryOid = 0,
                                                                                TypeDescription = ""
                                                                            };
                                                                        items.Add(dummy);
                                                                        items.AddRange(cb);
                                                                        combobox.ItemsSource = items;
                                                                        combobox.SelectedItem = items[0];
                                                                    }));

            combobox.Width = 250;
            return combobox;
        }

        private bool CreateParameterFieldsAndExecute(QueryDC query)
        {
            bool canExecute = true;

            datagrid_result.Visibility = Visibility.Collapsed;
            textblock_link.Visibility = Visibility.Collapsed;
            textblock_link_pdfexport.Visibility = Visibility.Collapsed;

            foreach (var item in query.Parameter)
            {
                string[] itemNames = item.Name.Split(new[] {'_'}, StringSplitOptions.RemoveEmptyEntries);

                bool addPanel = true;
                var sp = new StackPanel {Orientation = Orientation.Horizontal};

                var lbl = new Label
                    {
                        VerticalAlignment = VerticalAlignment.Center,
                        Content = itemNames[0],
                        Width = 100
                    };
                sp.Children.Add(lbl);

                switch (item.ParamType)
                {
                    case QueryParameterType.SupportConcept:
                        break;
                    case QueryParameterType.Employee:
                        var peEmp = new PopUpEdit
                            {
                                IsReadOnly = true,
                                Width = 250,
                                Margin = new Thickness(3),
                                DeleteButtonVisibility = Visibility.Collapsed
                            };

                        if (lastSelectedEmployee != null)
                        {
                            peEmp.Text = lastSelectedEmployee.ToString();
                        }

                        var popupEmployee = new Popup();
                        popupEmployee.StaysOpen = false;
                        popupEmployee.Width = 370;
                        popupEmployee.Height = 250;
						popupEmployee.Placement = PlacementMode.MousePoint;
                        var esv = new EmployeeSearchView();
                        esv.ItemSelected += (s, e) =>
                            {
                                popupEmployee.IsOpen = false;
                                peEmp.Focus();

                                CompactEmployeeDC newEmployee = e.Data;

                                peEmp.Text = newEmployee.ToString();

                                lastSelectedEmployee = newEmployee;
                            };
                        popupEmployee.Child = esv;

                        parameterUIElements.Add(item.Name + "_" + item.ParamType + "_1", esv);

                        peEmp.PopUpClick += (s, e) => { popupEmployee.IsOpen = true; };
                        sp.Children.Add(peEmp);
                        sp.Children.Add(popupEmployee);
                        break;
                    case QueryParameterType.Customer:
                        var pe = new PopUpEdit
                            {
                                IsReadOnly = true,
                                Width = 250,
                                Margin = new Thickness(3),
                                DeleteButtonVisibility = Visibility.Collapsed
                            };

                        if (lastSelectedCustomer != null)
                        {
                            pe.Text = lastSelectedCustomer.ToString();
                        }

                        var popup = new Popup();
                        popup.StaysOpen = false;
						popup.Placement = PlacementMode.MousePoint;
                        popup.Width = 370;
                        popup.Height = 250;
                        var csv = new CustomerSearchView();
                        csv.ItemSelected += (s, e) =>
                            {
                                popup.IsOpen = false;
                                pe.Focus();

                                CompactCustomerDC newCustomer = e.Data;

                                pe.Text = newCustomer.ToString();

                                lastSelectedCustomer = newCustomer;
                            };
                        popup.Child = csv;

                        parameterUIElements.Add(item.Name + "_" + item.ParamType + "_1", csv);

                        pe.PopUpClick += (s, e) => { popup.IsOpen = true; };
                        sp.Children.Add(pe);
                        sp.Children.Add(popup);

                        break;
                    case QueryParameterType.Month:
                        ComboBox monthCombo = CreateMonthCombo();
                        monthCombo.Margin = new Thickness(3);
                        sp.Children.Add(monthCombo);

                        ComboBox monthYearCombo = CreateYearCombo();
                        monthYearCombo.Margin = new Thickness(3);
                        sp.Children.Add(monthYearCombo);

                        parameterUIElements.Add(item.Name + "_" + item.ParamType + "_1", monthCombo);
                        parameterUIElements.Add(item.Name + "_" + item.ParamType + "_2", monthYearCombo);

                        break;
                    case QueryParameterType.Year:
                        ComboBox yearCombo = CreateYearCombo();
                        yearCombo.Margin = new Thickness(3);
                        sp.Children.Add(yearCombo);

                        parameterUIElements.Add(item.Name + "_" + item.ParamType + "_1", yearCombo);

                        break;
                    case QueryParameterType.Date:
                        break;
                    case QueryParameterType.DateRange:
                        DateEdit dtpStart = CreateDateEdit();
                        sp.Children.Add(dtpStart);

                        if (itemNames.Length > 1)
                        {
                            lbl = new Label();
                            lbl.VerticalAlignment = VerticalAlignment.Center;
                            lbl.Content = itemNames[1];
                            sp.Children.Add(lbl);
                        }

                        DateEdit dtpEnd = CreateDateEdit();
                        sp.Children.Add(dtpEnd);

                        parameterUIElements.Add(item.Name + "_" + item.ParamType + "_1", dtpStart);
                        parameterUIElements.Add(item.Name + "_" + item.ParamType + "_2", dtpEnd);

                        break;
                    case QueryParameterType.CurrentEmployee:
                    case QueryParameterType.CurrentUser:
                        addPanel = false;
                        break;
                    case QueryParameterType.ValueListEntryType:
                        int t = 0;
                        if (itemNames.Length > 1 && Int32.TryParse(itemNames[1], out t))
                        {
                            ComboBox vleCombo = CreateValueListEntryCombo((ValueListEntryType) t);
                            vleCombo.Margin = new Thickness(3);
                            sp.Children.Add(vleCombo);

                            parameterUIElements.Add(item.Name + "_" + item.ParamType + "_1", vleCombo);
                        }
                        break;
                }
                if (addPanel)
                {
                    canExecute = false;
                    paramterPanel.Children.Add(sp);
                }
            }
            return canExecute;
        }

        private List<QueryParamDC> CreateQueryParamValues(QueryDC query)
        {
            var parameter = new List<QueryParamDC>();

            foreach (QueryParamDC item in query.Parameter)
            {
                var param = new QueryParamDC();
                parameter.Add(param);

                param.Name = item.Name;
                param.ParamType = item.ParamType;

                switch (item.ParamType)
                {
                    case QueryParameterType.SupportConcept:
                        break;
                    case QueryParameterType.Employee:
                        if (lastSelectedEmployee != null)
                        {
                            param.Value = lastSelectedEmployee.EmployeeOid;
                        }
                        break;
                    case QueryParameterType.Customer:
                        if (lastSelectedCustomer != null)
                        {
                            param.Value = lastSelectedCustomer.CustomerOid;
                        }

                        break;
                    case QueryParameterType.Month:
                        if (parameterUIElements.ContainsKey(item.Name + "_" + item.ParamType + "_1") &&
                            parameterUIElements.ContainsKey(item.Name + "_" + item.ParamType + "_2"))
                        {
                            var monthCombo = parameterUIElements[item.Name + "_" + item.ParamType + "_1"] as ComboBox;
                            var yearCombo = parameterUIElements[item.Name + "_" + item.ParamType + "_2"] as ComboBox;

                            var dt = new DateTime((int) yearCombo.SelectedItem,
                                                  DateTimeFormatInfo.CurrentInfo.MonthNames.IndexOf(
                                                      (string) monthCombo.SelectedItem) + 1, 1);

                            param.Value = dt;
                        }

                        break;
                    case QueryParameterType.Year:
                        if (parameterUIElements.ContainsKey(item.Name + "_" + item.ParamType + "_1"))
                        {
                            var yearCombo = parameterUIElements[item.Name + "_" + item.ParamType + "_1"] as ComboBox;

                            var dt = new DateTime((int) yearCombo.SelectedItem, 1, 1);

                            param.Value = dt;
                        }

                        break;
                    case QueryParameterType.Date:
                        break;
                    case QueryParameterType.DateRange:
                        if (parameterUIElements.ContainsKey(item.Name + "_" + item.ParamType + "_1") &&
                            parameterUIElements.ContainsKey(item.Name + "_" + item.ParamType + "_2"))
                        {
                            var dtpStart = parameterUIElements[item.Name + "_" + item.ParamType + "_1"] as DateEdit;
                            var dtpEnd = parameterUIElements[item.Name + "_" + item.ParamType + "_2"] as DateEdit;

                            var dts = new DateTimeSpan();
                            if (dtpStart.EditValue != null)
                            {
                                dts.StartDate = dtpStart.DateTime;
                            }
                            else
                            {
                                dts.StartDate = DateTime.MinValue;
                            }

                            if (dtpEnd.EditValue != null)
                            {
                                dts.EndDate = dtpEnd.DateTime;
                            }
                            else
                            {
                                dts.EndDate = DateTime.MaxValue;
                            }

                            param.Value = dts;
                        }

                        break;
                    case QueryParameterType.CurrentEmployee:
                        param.Value = BeWoApp.LoggedOnEmployee.EmployeeOid;

                        break;
                    case QueryParameterType.CurrentUser:
                        param.Value = BeWoApp.LoggedOnUser.UserOid;

                        break;
                    case QueryParameterType.ValueListEntryType:
                        if (parameterUIElements.ContainsKey(item.Name + "_" + item.ParamType + "_1"))
                        {
                            var combo = parameterUIElements[item.Name + "_" + item.ParamType + "_1"] as ComboBox;
                            var vle = combo.SelectedItem as ValueListEntryDC;
                            if (vle != null)
                                param.Value = vle.ValueListEntryOid.Value;
                        }

                        break;
                }
            }

            return parameter;
        }

        private ComboBox CreateYearCombo()
        {
            var comboboxYear = new ComboBox();

            var years = new List<int>();
            for (int i = -1; i <= 10; i++)
            {
                years.Add(DateTime.Now.Year - i);
            }

            comboboxYear.ItemsSource = years;

            var firstOfMonth = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
            comboboxYear.SelectedItem = firstOfMonth.Subtract(new TimeSpan(1, 0, 0, 0)).Year;

            return comboboxYear;
        }

        private void ExecuteQuery(QueryDC query)
        {
            List<QueryParamDC> parameter = CreateQueryParamValues(query);

            ExecuteQuery(query, parameter);
        }

        private void ExecuteQuery(QueryDC query, List<QueryParamDC> parameterList)
        {
            datagrid_result.Visibility = Visibility.Visible;
            textblock_link.Visibility = Visibility.Visible;
            textblock_link_pdfexport.Visibility = Visibility.Visible;
            datagrid_result.Columns.Clear();

            ServiceFacade.DoQueryServiceAsync(
                s =>
                    {
                        try
                        {
                            return s.ExecuteQuery(query.Oid, parameterList);
                        }
                        catch
                        {
                        }

                        return null;
                    },
                r => this.Dispatch(delegate
                    {
                        datagrid_result.ItemsSource = r;
                        SetOidColumnsInvisible();

                        foreach (
                            GridColumn column in
                                datagrid_result.Columns.Where(column => column.HeaderCaption.Equals("Mail") ||
                                                                        column.HeaderCaption.Equals("Mail (dienstl.)") ||
                                                                        column.HeaderCaption.Equals("Homepage")))
                        {
                            column.CellTemplate = BuildLinkTemplate(column.HeaderCaption.ToString());
                        }

                        if (r == null || r.Columns.Count <= 0) return;

                        summaryItem.FieldName = r.Columns[0].ColumnName;
                        summaryItem.DisplayFormat = "anz: {0}";
                    }));
        }

        private void Hyperlink_OnRequestNavigate(object sender, RequestNavigateEventArgs e)
        {
            BeWoUtils.OpenMailClient(e.Uri.ToString());
        }

        private void Hyperlink_OnRequestNavigateToHomepage(object sender, RequestNavigateEventArgs e)
        {
            var originalString = e.Uri.OriginalString;
            var u = !originalString.StartsWith("http://") ? new Uri("http://" + e.Uri.OriginalString) : e.Uri;

            Process.Start(u.AbsoluteUri);
            e.Handled = true;
        }

        private DataTemplate BuildLinkTemplate(string columnName)
        {
            var binding = new Binding {Path = new PropertyPath("Data." + columnName)};

            var textBlockInHyperLinkFactory = new FrameworkElementFactory(typeof (TextBlock));
            textBlockInHyperLinkFactory.SetBinding(TextBlock.TextProperty, binding);

            var hyperLinkFactory = new FrameworkElementFactory(typeof (Hyperlink));

            hyperLinkFactory.AddHandler(Hyperlink.RequestNavigateEvent,
                                        columnName.Equals("Homepage")
                                            ? Hyperlink_OnRequestNavigateToHomepage
                                            : new RequestNavigateEventHandler(Hyperlink_OnRequestNavigate));

            hyperLinkFactory.SetBinding(Hyperlink.NavigateUriProperty, binding);
            hyperLinkFactory.AppendChild(textBlockInHyperLinkFactory);

            var outerTextBlockFactory = new FrameworkElementFactory(typeof (TextBlock));
            outerTextBlockFactory.AppendChild(hyperLinkFactory);

            var template = new DataTemplate {VisualTree = outerTextBlockFactory};

            return template;
        }

        private void SetOidColumnsInvisible()
        {
            foreach (var col in datagrid_result.Columns.Where(col => !String.IsNullOrEmpty(col.FieldName) && col.FieldName.ToLower().IndexOf("oid") >= 0))
            {
                col.Visible = false;
            }
        }


        private bool LoggedOnUserHasRightForQuery(QueryDC item)
        {
            if (!String.IsNullOrEmpty(item.UserGroupOids))
            {
                List<UserGroupDC> groups = BeWoApp.LoggedOnUser.UserGroups;

                string oids = "," + item.UserGroupOids + ",";
                return groups.Any(@group => oids.IndexOf(String.Format(",{0},", @group.UserGroupOid.Value)) >= 0);
            }

            return true;
        }

        private void ResetQueryFields()
        {
            paramterPanel.Children.Clear();
            parameterUIElements.Clear();
        }

        private void UpdatePDFExportUri(QueryDC query)
        {
            string url = BeWoApp.SiteOfOrigin + "/ReportView.aspx?dcid=" + BeWoApp.Tenant + "queryeoid" + BeWoApp.LoggedOnUser.Employee.EmployeeOid + "&qoid=" + query.Oid + "&type=" + Utils.EnumName(ReportTypes.QueryReport);

            url = BeWoWpfUtils.GetHTMLEncodedURL(url);
            linkPdfExport.NavigateUri = new Uri(BeWoUtils.RemoveAuthenticationInfoFromUri(url));

            linkPdfExport.TargetName = Guid.NewGuid().ToString();

            linkPdfExport_direct.NavigateUri = linkPdfExport.NavigateUri;
            linkPdfExport_direct.TargetName = linkPdfExport.TargetName;
        }


        private void btnExecuteQuery_Click(object sender, RoutedEventArgs e)
        {
            var lQuery = combo_query.SelectedItem as QueryDC;

            if (lQuery != null)
            {
                ExecuteQuery(lQuery);
            }
        }

        private void combo_query_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var lQuery = combo_query.SelectedItem as QueryDC;

            ResetQueryFields();

            if (lQuery != null)
            {
                if (lQuery.Parameter == null || lQuery.Parameter.Count == 0)
                {
                    if (lQuery.IsDirect)
                    {
                        datagrid_result.Visibility = Visibility.Collapsed;
                        textblock_link.Visibility = Visibility.Collapsed;
                        textblock_link_pdfexport.Visibility = Visibility.Collapsed;
                        btnExecuteQuery.Visibility = Visibility.Hidden;
                        textblock_link_pdfexport_direct.Visibility = Visibility.Visible;
                    }
                    else
                    {
                        btnExecuteQuery.Visibility = Visibility.Collapsed;
                        textblock_link_pdfexport_direct.Visibility = Visibility.Collapsed;
                        ExecuteQuery(lQuery, null);
                    }
                }
                else
                {
                    if (CreateParameterFieldsAndExecute(lQuery))
                    {
                        btnExecuteQuery.Visibility = Visibility.Collapsed;
                        textblock_link_pdfexport_direct.Visibility = Visibility.Collapsed;
                        ExecuteQuery(lQuery);
                    }
                    else
                    {
                        if (lQuery.IsDirect)
                        {
                            btnExecuteQuery.Visibility = Visibility.Hidden;
                            textblock_link_pdfexport_direct.Visibility = Visibility.Visible;
                        }
                        else
                        {
                            btnExecuteQuery.Visibility = Visibility.Visible;
                            textblock_link_pdfexport_direct.Visibility = Visibility.Hidden;
                        }
                    }
                }

                UpdatePDFExportUri(lQuery);
            }
        }

        private void linkExcelExport_RequestNavigate(object sender, RequestNavigateEventArgs e)
        {
            var lView = datagrid_result.View as TableView;

            var lHeaderCaptions = new List<string>();
            var lContent = new List<List<string>>();

            if (lView != null)
            {
                foreach (GridColumn iCol in lView.VisibleColumns)
                {
                    lHeaderCaptions.Add(iCol.HeaderCaption.ToString());

                    for (int iRowIndex = 0; iRowIndex < datagrid_result.VisibleRowCount; iRowIndex++)
                    {
                        if (lContent.Count <= iRowIndex)
                        {
                            lContent.Add(new List<string>());
                        }

                        lContent[iRowIndex].Add(datagrid_result.GetCellValue(iRowIndex, iCol).ToStringNullCheck());
                    }
                }
            }

			
			var path = BeWoApp.GetAndCreateUserAppDataPath() + "\\BeWoDokument.xls";
			var lQuery = combo_query.SelectedItem as QueryDC;
	        if (lQuery != null)
	        {
		        path = String.Format("{0}\\{1}.xls", BeWoApp.GetAndCreateUserAppDataPath(), lQuery.Title);
	        }
			var sf = new SaveFileDialog
                {
                    FileName = Path.GetFileName(path),
                    Filter = "Microsoft Excel 97-2003-Arbeitsblatt|*.xls|Alle Dateien|*.*"
                };
            if (sf.ShowDialog() != true)
                return;
            ServiceFacade.DoDownloadServiceSync(
                s =>
                BeWoUtils.WriteExcelFile(s.PrepareExcelFile(DownloadLinkEngine.ExcelFileId, lHeaderCaptions, lContent),
                                         sf.FileName));

            //string navitageUri = ((Hyperlink)sender).NavigateUri.ToString();
            //BeWoUtils.NavigateToReportUri(navitageUri);
            //System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo((sender as System.Windows.Documents.Hyperlink).NavigateUri.ToString()));

            //// Workaround Hyperlink mit neuem ersetzen, Navigate Uri lässt auf dem alten nicht ändern...
            //this.textblock_link.Inlines.Clear();
            //var lNewLink = new Hyperlink(new Run("Excel Export")) { NavigateUri = this.DownloadLinkEngine.GenerateNewExcelLink(), Foreground = Brushes.Black, TargetName = "newWindow" };
            //lNewLink.RequestNavigate += this.linkExcelExport_RequestNavigate;
            //this.textblock_link.Inlines.Add(lNewLink);
        }

        private void linkPdfExport_RequestNavigate(object sender, RequestNavigateEventArgs e)
        {
            var lQuery = combo_query.SelectedItem as QueryDC;
            if (lQuery != null)
            {
                var dt = datagrid_result.ItemsSource as DataTable;
                ServiceFacade.DoQueryServiceSync(
                    q =>
                    q.PrepareQueryReport(dt, BeWoApp.Tenant + "queryeoid" + BeWoApp.LoggedOnUser.Employee.EmployeeOid));

				string navigateUri = linkPdfExport.NavigateUri.ToString();

				navigateUri = BeWoUtils.RemoveAuthenticationInfoFromUri(navigateUri);

				BeWoUtils.NavigateToReportUri(navigateUri, lQuery.Title);
            }
            
            e.Handled = true;
        }

        private void linkPdfExport_direct_RequestNavigate(object sender, RequestNavigateEventArgs e)
        {
            var lQuery = combo_query.SelectedItem as QueryDC;
            if (lQuery != null)
            {
                List<QueryParamDC> parameterList = CreateQueryParamValues(lQuery);

                DataTable dt = ServiceFacade.DoQueryServiceSync(s => s.ExecuteQuery(lQuery.Oid, parameterList));
                ServiceFacade.DoQueryServiceSync(
                    q =>
                    q.PrepareQueryReport(dt, BeWoApp.Tenant + "queryeoid" + BeWoApp.LoggedOnUser.Employee.EmployeeOid));

                string navigateUri = linkPdfExport.NavigateUri.ToString();
                navigateUri = BeWoUtils.RemoveAuthenticationInfoFromUri(navigateUri);
                BeWoUtils.NavigateToReportUri(navigateUri, lQuery.Title);
            }
        }
    }
}