using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

using BeWo.Annotations;
using BeWo.Core;
using BeWo.ServiceProxy;
using BeWo.Validation;
using BeWo.View.Controls;
using BeWo.ViewModel;
using BeWo.ViewModel.ListViewModel;

using BS.Shared;
using BS.Shared.DataContracts;
using BS.Shared.Extensions;

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

namespace BeWo.View
{
    public partial class BargeldkassenView : INotifyPropertyChanged
    {
        public BargeldtransaktionsVM NewBargeldtransaktion { get; set; }

        [Validation(ValidationRule = ValidationRules.NotNullOrStringEmpty)]
        public BargeldkassenVM       SelectedBargeldkasse  { get; set; }

        public static int PreselectedMonth
        {
            get { return DateTime.Now.Month; }
        }
        public static int PreselectedYear
        {
            get { return DateTime.Now.Year; }
        }

        private readonly List<int> _JahresComboBoxSource; 
        public IEnumerable<int> JahresComboBoxSource 
        {
            get { return _JahresComboBoxSource; }
        }

        private readonly List<int> _MonatsComboBoxSource;
        public IEnumerable<int> MonatsComboBoxSource
        {
            get { return _MonatsComboBoxSource; }
        }

        private static bool darfBargeldTransaktionenBearbeiten;
        private static DefaultBoolean darfBargeldTransaktionenBearbeitenAsDefaultBoolean;
        private static bool darfBargeldTransaktionenAnlegen;
        private static bool darfBargeldTransaktionenLoeschen;

        public static bool DarfBargeldtransaktionenBearbeiten
        {
            get { return darfBargeldTransaktionenBearbeiten; }
        }

        public static DefaultBoolean BargeldtransaktionenBearbeitenAlsDefaultBooelan
        {
            get { return darfBargeldTransaktionenBearbeitenAsDefaultBoolean; }
        }

        public static bool DarfBargeldTransaktionLoeschen
        {
            get { return darfBargeldTransaktionenLoeschen; }
        }

        public static bool DarfBargeldTransaktionAnlegen
        {
            get { return darfBargeldTransaktionenAnlegen; }
        }

        private BargeldkassenListVM _ViewModel;

        private BargeldkassenListVM ViewModel
        {
            get { return _ViewModel; }
            set
            {
                DataContext = value;
                _ViewModel  = value;
            }
        }

        private readonly TableID currentObjectTid;
        private readonly long    currentObjectOid;

        public override bool IsDirty
        {
            get
            {
                return ViewModel != null && ViewModel.IsDirty;
            }
        }

        public BargeldkassenView(TableID objectTid, long objectOid)
        {
            InitializeComponent();
            
            _JahresComboBoxSource = new List<int>();
            for (var i = 9; i >= 0; i--)
            {
                _JahresComboBoxSource.Add(DateTime.Now.Year - i);
            }

            _MonatsComboBoxSource = new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};

            currentObjectOid = objectOid;
            currentObjectTid = objectTid;

            NewBargeldtransaktion = new BargeldtransaktionsVM(new BargeldtransaktionDC());

            InitRights();

            ReloadViewModel();

            if (tabcontrol_bargeldkassen != null && tabcontrol_bargeldkassen.SelectedIndex == -1)
            {
                tabcontrol_bargeldkassen.SelectedIndex = 0;
            }
        }

        private void InitRights()
        {
            bool editRight;
            DefaultBoolean editRightAsDefaultBoolean;
            bool deleteRight;
            bool createRight;

            if (currentObjectTid == TableID.Customer)
            {
                editRight = BeWoApp.LoggedOnUser.HasRight(UserRightType.BargeldverwaltungBearbeiten) || BeWoApp.LoggedOnUser.HasRight(UserRightType.EditAll);
                editRightAsDefaultBoolean = (DefaultBoolean)(Convert.ToInt32((BeWoApp.LoggedOnUser.HasRight(UserRightType.BargeldverwaltungBearbeiten)) || BeWoApp.LoggedOnUser.HasRight(UserRightType.EditAll)) + 1);

                deleteRight = BeWoApp.LoggedOnUser.HasRight(UserRightType.BargeldverwaltungLoeschen) || BeWoApp.LoggedOnUser.HasRight(UserRightType.DeleteAll);
                createRight = BeWoApp.LoggedOnUser.HasRight(UserRightType.BargeldverwaltungAnlegen) || BeWoApp.LoggedOnUser.HasRight(UserRightType.CreateAll);
            }
            else
            {
                editRight = BeWoApp.LoggedOnUser.HasRight(UserRightType.BargeldverwaltungFinanzenBearbeiten) || BeWoApp.LoggedOnUser.HasRight(UserRightType.EditAll);
                editRightAsDefaultBoolean = (DefaultBoolean)(Convert.ToInt32((BeWoApp.LoggedOnUser.HasRight(UserRightType.BargeldverwaltungFinanzenBearbeiten)) || BeWoApp.LoggedOnUser.HasRight(UserRightType.EditAll)) + 1);

                deleteRight = BeWoApp.LoggedOnUser.HasRight(UserRightType.BargeldverwaltungFinanzenLoeschen) || BeWoApp.LoggedOnUser.HasRight(UserRightType.DeleteAll);
                createRight = BeWoApp.LoggedOnUser.HasRight(UserRightType.BargeldverwaltungFinanzenAnlegen) || BeWoApp.LoggedOnUser.HasRight(UserRightType.CreateAll);
            }

            darfBargeldTransaktionenBearbeiten                 = editRight;
            darfBargeldTransaktionenBearbeitenAsDefaultBoolean = editRightAsDefaultBoolean;
            darfBargeldTransaktionenLoeschen                   = deleteRight;
            darfBargeldTransaktionenAnlegen                    = createRight;
        }

        private void ReloadViewModel()
        {
            var previouslySelectedTab = tabcontrol_bargeldkassen.SelectedIndex;

            ServiceFacade.DoOperationsServiceAsync(s => s.LoadBargeldkassenForObject(currentObjectTid, currentObjectOid), r => this.Dispatch(
                    delegate
                    {
                        if (r.Any())
                        {
                            int? alteAnzahl = null;

                            if (ViewModel != null)
                            {
                                alteAnzahl = ViewModel.VMList.Count;
                            }

                            ViewModel = new BargeldkassenListVM(r);

                            var neueAnzahl = ViewModel.VMList.Count;

                            if (alteAnzahl != null && neueAnzahl > alteAnzahl)
                            {
                                tabcontrol_bargeldkassen.SelectedIndex = neueAnzahl - 1;
                            }
                            else if (previouslySelectedTab > -1)
                            {
                                tabcontrol_bargeldkassen.SelectedIndex = previouslySelectedTab;
                            }
                            else
                            {
                                tabcontrol_bargeldkassen.SelectedIndex = 0;
                            }
                            

                            ViewModel.VMList.DoForEach(d => d.Bargeldtransaktionen.VMList.ListChanged += (sender, args) =>
                            {
                                var isRelevantProperty = false;

                                if (args.PropertyDescriptor != null)
                                {
                                    isRelevantProperty = args.PropertyDescriptor.Name.Equals(BargeldtransaktionsVM.PropertyName_Betrag) ||
                                                         args.PropertyDescriptor.Name.Equals(BargeldtransaktionsVM.PropertyName_Notice) ||
                                                         args.PropertyDescriptor.Name.Equals(BargeldtransaktionsVM.PropertyName_Zahlungsdatum) ||
                                                         args.PropertyDescriptor.Name.Equals(BargeldtransaktionsVM.PropertyName_Zahlungstyp);
                                }

                                if (args.ListChangedType.Equals(ListChangedType.ItemChanged) && isRelevantProperty)
                                {
                                    var bargeldtransaktionsListe = (BindingList<BargeldtransaktionsVM>) sender;
                                    var bargeldkasse             = ViewModel.VMList.FirstOrDefault(f => f.Bargeldtransaktionen.VMList.Equals(bargeldtransaktionsListe));
                                    
                                    if (bargeldkasse != null)
                                    {
                                        bargeldkasse.RecalculateTransaktionsbestaende();

                                        ServiceFacade.DoOperationsServiceAsync(s => s.UpdateBargeldkasse(bargeldkasse.CommitToDataContract()), r2 => this.Dispatch(ReloadViewModel));
                                    }
                                }
                            });
                        }
                        else
                        {
                            ViewModel = new BargeldkassenListVM(new List<BargeldkassenDC>());
                        }
                    }));
        }

        private void GridBargeldtransaktionenOnCustomColumnSort(object sender, CustomColumnSortEventArgs e)
        {
            e.Result = DateTime.Compare(Convert.ToDateTime(e.Value1), Convert.ToDateTime(e.Value2));
            e.Handled = true;
        }

        private void KlassenbuchLinkOnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var textBlock = (TextBlock) sender;
            var kasse     = ((BargeldkassenVM) textBlock.Tag).CommitToDataContract();

            var parentStackPanel = (StackPanel) textBlock.Parent;
            var kinder           = parentStackPanel.Children;

            var monatsCombobox = (ComboBox) kinder[0];
            var jahresCombobox = (ComboBox) kinder[1];

            var monat = Convert.ToInt32(monatsCombobox.SelectedItem);
            var jahr  = Convert.ToInt32(jahresCombobox.SelectedItem);

            var zeitraum = new DateTime(jahr, monat, 1);

            BeWoUtils.ShowReport("Kassenbuch", null, new Dictionary<String, Object> { { "bargeldkasse", kasse }, { "zeitraum", zeitraum }, { "objectoid", kasse.ObjectOid }, { "objecttid", kasse.ObjectTid } }, ReportEnum.KassenbuchReportEnum);
        }

        private void ButtonBargeldtransaktionDeleteClick(object sender, RoutedEventArgs e)
        {
            var btn = ((Button) sender);

            var transaktion = ((BargeldtransaktionsVM) ((EditGridCellData) btn.Tag).RowData.Row);

            if (MessageBox.Show("Möchten Sie die Bargeldtransaktion wirklich löschen?", "Transaktion löschen", MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.No)
            {
                return;
            }

            var cellEditor           = ((CellEditor) btn.TemplatedParent).RowData.View;
            var selectedBargeldkasse = (BargeldkassenVM) cellEditor.DataControl.Tag;

            var removingSuccessfull = selectedBargeldkasse.Bargeldtransaktionen.VMList.Remove(transaktion);
            selectedBargeldkasse.RecalculateTransaktionsbestaende();
            var kb = selectedBargeldkasse.Kassenbestand;

            ServiceFacade.DoOperationsServiceAsync(s => s.UpdateBargeldkasse(selectedBargeldkasse.CommitToDataContract()), r => this.Dispatch(ReloadViewModel));
        }

        private void LinkZahlungsbelegDruckenClick(object sender, RoutedEventArgs e)
        {
            var link       = (System.Windows.Documents.Hyperlink)sender;
            var cellEditor = ((CellEditor) link.TemplatedParent).RowData.View;
            var kasse      = (BargeldkassenVM)cellEditor.DataControl.Tag;
            var control    = (GridControl) cellEditor.DataControl;

            var transaktion = control.GetCurrentValue<BargeldtransaktionsVM>().CommitToDataContract();

            BeWoUtils.ShowReport("Zahlungsbeleg", null, new Dictionary<String, Object> {{"transaktion", transaktion}, {"objectoid", kasse.ObjectOid}, {"objecttid", kasse.ObjectTid}}, ReportEnum.ZahlungsbelegEnum);
        }

        private void ButtonAddBargeldkasseClick(object sender, RoutedEventArgs e)
        {
            if (!Validate(groupbox_newBargeldkasse))
            {
                return;
            }

            var neu       = ViewModel.NewVM;
            neu.ObjectOid = currentObjectOid;
            neu.ObjectTid = currentObjectTid;

            ServiceFacade.DoOperationsServiceAsync(s => s.InsertNewBargeldkasse(neu.CommitToDataContract()), r => this.Dispatch(delegate
            {
                popup_newBargeldkasse.IsOpen = false;

                ViewModel.NewVM = new BargeldkassenVM(new BargeldkassenDC());

                ReloadViewModel();
            }));
        }
		
		private void ButtonCancelAddBargeldkasseClick(object sender, RoutedEventArgs e)
        {
            popup_newBargeldkasse.IsOpen = false;
        }

        private void ButtonOpenAddBargeldkasseClick(object sender, RoutedEventArgs e)
        {
            popup_newBargeldkasse.IsOpen = true;
        }

        private void ButtonAddBargeldtransaktionClick(object sender, RoutedEventArgs e)
        {
            if (!Validate(groupbox_newBargeldtransaktion))
            {
                return;
            }

            var transaktionsBetrag = NewBargeldtransaktion.Betrag * (NewBargeldtransaktion.Zahlungstyp.Enum == Zahlungstyp.Auszahlung ? -1 : 1);

            var latestTransactionDate = new DateTime(1, 1, 1);
            foreach (var tVM in SelectedBargeldkasse.Bargeldtransaktionen.VMList.Where(tVM => tVM.Zahlungsdatum > latestTransactionDate && tVM.Zahlungsdatum != null))
            {
                latestTransactionDate = tVM.Zahlungsdatum.Value.GetShortDateTime();
            }

            if (NewBargeldtransaktion.Zahlungsdatum <= latestTransactionDate)
            {
                var vorherigeTransaktion = SelectedBargeldkasse.Bargeldtransaktionen.VMList.OrderByDescending(o => o.Zahlungsdatum).FirstOrDefault(f => f.Zahlungsdatum <= NewBargeldtransaktion.Zahlungsdatum);
                var liste = vorherigeTransaktion == null ?
                    SelectedBargeldkasse.Bargeldtransaktionen.VMList.OrderBy(o => o.Zahlungsdatum) :
                    SelectedBargeldkasse.Bargeldtransaktionen.VMList.Where(w => w.Zahlungsdatum > vorherigeTransaktion.Zahlungsdatum).OrderBy(o => o.Zahlungsdatum);

                NewBargeldtransaktion.Transaktionskassenbestand = (vorherigeTransaktion == null ? 0m : vorherigeTransaktion.Transaktionskassenbestand) + transaktionsBetrag;

                var tmp = NewBargeldtransaktion.Transaktionskassenbestand;

                foreach (var tvm in liste)
                {
                    tvm.Transaktionskassenbestand = tmp + tvm.Betrag * (tvm.Zahlungstyp.Enum == Zahlungstyp.Auszahlung ? -1 : 1);
                    tmp = tvm.Transaktionskassenbestand != null ? tvm.Transaktionskassenbestand.Value : 0m;
                }
            }
            else
            {
                NewBargeldtransaktion.Transaktionskassenbestand = SelectedBargeldkasse.Kassenbestand + transaktionsBetrag;
            }

            SelectedBargeldkasse.Bargeldtransaktionen.NewVM = NewBargeldtransaktion;
            SelectedBargeldkasse.Bargeldtransaktionen.AddNewVMToList();
            var kb = SelectedBargeldkasse.Kassenbestand;

            NewBargeldtransaktion = new BargeldtransaktionsVM(new BargeldtransaktionDC());

            ServiceFacade.DoOperationsServiceAsync(s => s.UpdateBargeldkasse(SelectedBargeldkasse.CommitToDataContract()), r => this.Dispatch(delegate
            {
                popup_newBargeldtransaktion.IsOpen = false;

                NewBargeldtransaktion = new BargeldtransaktionsVM(new BargeldtransaktionDC());
                SelectedBargeldkasse = null;

                OnPropertyChanged("NewBargeldtransaktion");
                OnPropertyChanged("SelectedBargeldkasse");

                ReloadViewModel();
            }));
        }

        private void ButtonCancelAddBargeldtransaktionClick(object sender, RoutedEventArgs e)
        {
            NewBargeldtransaktion = new BargeldtransaktionsVM(new BargeldtransaktionDC());
            SelectedBargeldkasse  = null;

            OnPropertyChanged("NewBargeldtransaktion");
            OnPropertyChanged("SelectedBargeldkasse");

            popup_newBargeldtransaktion.IsOpen = false;
        }

        private void ButtonOpenAddBargeldtransaktionClick(object sender, RoutedEventArgs e)
        {
            var abc = ((Button) sender).Tag;

            if (abc != null)
            {
                var kasse = (BargeldkassenVM) abc;
                SelectedBargeldkasse = kasse;
                OnPropertyChanged("SelectedBargeldkasse");
            }

            popup_newBargeldtransaktion.IsOpen = true;
        }

        private void BtnDeleteBargeldkasseClick(object sender, RoutedEventArgs e)
        {
            var button               = (Button) sender;
            var selectedBargeldkasse = (BargeldkassenVM) button.Tag;

            var result = MessageBox.Show(string.Format("Möchten Sie die Bargeldkasse \"{0}\" wirklich löschen?", selectedBargeldkasse.Kassenname), "Bargeldkasse löschen", MessageBoxButton.YesNo, MessageBoxImage.Warning);

            if (result == MessageBoxResult.No)
            {
                return;
            }

            ViewModel.VMList.Remove(selectedBargeldkasse);

            ServiceFacade.DoOperationsServiceAsync(s => s.DeactivateBargeldkasse(selectedBargeldkasse.DataContract.BargeldkassenOid.Value, selectedBargeldkasse.DataContract.BargeldkassenVersion.Value), () => this.Dispatch(ReloadViewModel));
        }
        
        private void AuszahlungsIntervallCBEditValueChanged(object sender, EditValueChangedEventArgs e)
        {
            var cbe = (ComboBoxEdit) sender;

            var containingStackPanel = (StackPanel) cbe.Parent;
            var blubb2 = (Grid) containingStackPanel.Parent;
            
            var bargeldkasse = (BargeldkassenVM) blubb2.Tag;

            if (bargeldkasse == null || !bargeldkasse.IsDirty)
            {
                return;
            }

            ServiceFacade.DoOperationsServiceAsync(s => s.UpdateBargeldkasse(bargeldkasse.CommitToDataContract()), r => this.Dispatch(ReloadViewModel));
        }

        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private void KassennamenChangeButtonClick(object sender, RoutedEventArgs e)
        {
            var btn   = (Button) sender;
            var panel = (StackPanel) btn.Parent;
            var popup = (PopupNonTopmost) panel.Children[2];

            popup.IsOpen = !popup.IsOpen;
        }

        private void KassennamenChangeCancelButtonClick(object sender, RoutedEventArgs e)
        {
            var btn                 = (Button) sender;
            var popupMostInnerChild = BeWoWpfUtils.FindParent<Border>(btn);
            var popup               = (PopupNonTopmost) LogicalTreeHelper.GetParent(popupMostInnerChild);

            popup.IsOpen = false;
        }

        private void KassennamenChangeSaveButtonClick(object sender, RoutedEventArgs e)
        {
            var btn                 = (Button) sender;
            var popupMostInnerChild = BeWoWpfUtils.FindParent<Border>(btn);
            var popup               = (PopupNonTopmost) LogicalTreeHelper.GetParent(popupMostInnerChild);
            var bargeldkasse        = (BargeldkassenVM) tabcontrol_bargeldkassen.SelectedItem;

            ServiceFacade.DoOperationsServiceAsync(s => s.UpdateBargeldkasse(bargeldkasse.CommitToDataContract()), r => this.Dispatch(delegate
            {
                popup.IsOpen = false;

                ReloadViewModel();
            }));
        }
    }
}
