using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Navigation;
using System.Windows.Threading;

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

using BeWo.Core;
using BeWo.Office;
using BeWo.Office.TableModels;
using BeWo.ServiceProxy;
using BeWo.ViewModel;

using Microsoft.Win32;

namespace BeWo.View.Detail
{
    public partial class WordDocumentTemplateView
    {
        private TreeViewItem _SelectedTreeNode;

        private object drag;

        private Point _MouseDownPosition = new Point(-1, -1);

        private readonly long _ObjectOid;

        private readonly TableID _ObjectTid;

        private String _UploadFileName;

        public WordDocumentTemplateView(TableID pObjectTid, long pObjectOid)
        {
            // Bei der ersten Anmeldung:
            // INSERT INTO bewofolder(Tid, ObjectOid, ObjectTid, Name, InsTs, InsUser, Version, UdpUser, IsActive, SystemEntryID) VALUES(61, 1, 47, 'Vorlagen', now(), 'System', 1, 'System', 1, 8);

            InitializeComponent();
            CursorControl.Visibility = Visibility.Collapsed;
            _ObjectOid = pObjectOid;
            _ObjectTid = pObjectTid;

            FileAttachmentTypeDictionary = new Dictionary<FileAttachmentType, string>
                {
                    {FileAttachmentType.CustomerTemplate, "Klientenvorlage"},
                    {FileAttachmentType.OrganisationTemplate, "Organisationenvorlage"},
                    {FileAttachmentType.PersonTemplate, "Personenvorlage"},
                    {FileAttachmentType.SupportConceptTemplate, "Hilfeplanvorlage"}
                };

            ServiceFacade.DoOperationsServiceAsync(
                s => s.GetFolderTree(_ObjectTid, _ObjectOid),
                r => this.Dispatch(
                    delegate
                        {
                            if (r == null) return;

                            var vmList = r.Select(item => new BeWoFolderVM(item)).ToList();
                            Treeview.DataContext = vmList;
                            if (Treeview.Items.Count <= 0) return;

                            object treeviewitem = Treeview.Items[0];
                            if (treeviewitem != null)
                            {
                                var container = Treeview.ItemContainerGenerator.ContainerFromItem(treeviewitem);
                                var ci = container as TreeViewItem;
                                if (ci != null)
                                {
                                    ci.IsSelected = true;
                                    ci.IsExpanded = true;
                                }
                            }
                        }));

            PreviewMouseLeftButtonDown += treeview_PreviewMouseLeftButtonDown;
            PreviewMouseLeftButtonUp += treeview_PreviewMouseLeftButtonUp;
            PreviewMouseMove += treeview_PreviewMouseMove;
        }

        private void button_uploadDocument_Click(object sender, RoutedEventArgs e)
        {
            if (string.IsNullOrEmpty(PopupeditFile.Text)) return;

            long? bewoFolderOid = null;

            var folder = GetSelectedFolder();
            if (folder != null)
                bewoFolderOid = folder.DataContract.BeWoFolderOid;

            var fatId = (int) ((KeyValuePair<FileAttachmentType, string>) FileAttachmentTypeComboBox.SelectedItem).Key;

			ProgressStream upload = new ProgressStream(File.OpenRead(_UploadFileName));
			upload.ProgressChanged += (s2, e2) => Dispatcher.BeginInvoke(
				DispatcherPriority.Normal,
				(Action)(() =>
				{
					ProgressbarUpload.Value = e2.Data;
					TextProgress.Content = string.Format("Bitte warten... {0:00}%", e2.Data * 100);
				}));
			var lUlPackage = new UploadPackage(bewoFolderOid, fatId, PopupeditFile.Text, TextboxFileNotice.Text, _ObjectOid, (int)_ObjectTid, upload);

            ServiceFacade.DoStreamingServiceAsync(
                s => s.UploadDocument(lUlPackage),
                r => this.Dispatch(
                    delegate
                        {
                            var selectedVM = (BeWoFolderVM) Treeview.SelectedItem;
                            var newFileVM = new FileAttachmentVM(r.Attachment);
                            selectedVM.Files.Add(newFileVM);
                            newFileVM.Folder = selectedVM;

                            ProgressbarUpload.Value = 0;
                            TextProgress.Content = string.Empty;
                            _UploadFileName = null;
                            ButtonUploadDocument.IsEnabled = false;
                            PopupeditFile.Text = string.Empty;
							upload.Dispose();

                        })
						,
						() =>
						this.Dispatch(
							delegate
							{
								ProgressbarUpload.Value = 0;
								TextProgress.Content = string.Empty;
								upload.Dispose();
							})
						);
        }

        public void DoFileUpdate(Stream upload, string fileName, string notice, long fileOid, Action pCallback, int fileAttachmentTypeId)
        {
            long? bewoFolderOid = null;

            this.Dispatch(delegate
                {
                    var folder = Treeview.SelectedItem as BeWoFolderVM;
                    if (folder != null)
                        bewoFolderOid = folder.DataContract.BeWoFolderOid;
                });

            var lUlPackage = new UpdatePackage(bewoFolderOid, fileAttachmentTypeId,fileName, fileOid, notice, _ObjectOid, (int)_ObjectTid, upload);

            ServiceFacade.DoStreamingServiceAsync(
                s => s.UpdateDocument(lUlPackage),
                r => this.Dispatch(
                    delegate
                        {
                            ProgressbarUpload.Value = 0;
                            TextProgress.Content = string.Empty;
                            _UploadFileName = null;
                            ButtonUploadDocument.IsEnabled = false;
                            PopupeditFile.Text = string.Empty;
                            pCallback();
                        })
						,
						() => this.Dispatch(
							delegate
							{
								ProgressbarUpload.Value = 0;
								TextProgress.Content = string.Empty;
								_UploadFileName = null;
							})
						);
        }

        public Dictionary<FileAttachmentType, string> FileAttachmentTypeDictionary { get; set; }

        private BeWoFolderVM GetSelectedFolder()
        {
            return Treeview.SelectedItem as BeWoFolderVM;
        }

        private void popupedit_file_PopUpClick(object sender, RoutedEventArgs args)
        {
            var dlg = new OpenFileDialog();

            if (dlg.ShowDialog() != true) return;

            try
            {
	            _UploadFileName = dlg.FileName;

                PopupeditFile.Text = dlg.SafeFileName;
                ButtonUploadDocument.IsEnabled = true;

				
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Exclamation);
            }
        }

        private void TextBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Return)
            {
                UpdateSelectedTreeItemText((TextBox)sender);
            }
        }

        private void TextBox_LostFocus(object sender, RoutedEventArgs e)
        {
            UpdateSelectedTreeItemText((TextBox)sender);
        }

        private void UpdateSelectedTreeItemText(TextBox textBox)
        {
            if (!textBox.IsReadOnly)
            {
                textBox.Background = Brushes.Transparent;
                textBox.IsReadOnly = true;
                textBox.BorderThickness = new Thickness(0);

                if (textBox.Tag != null)
                {

                    var folder = textBox.Tag as BeWoFolderVM;
                    if (folder != null)
                    {
                        folder.Name = textBox.Text;
                        if (folder.IsDirty)
                            UpdateFolder(folder);
                    }
                }
            }
        }

        private static void InsertFolder(BeWoFolderVM folder)
        {
            ServiceFacade.DoOperationsServiceAsync(
                s => s.InsertNewFolder(folder.CommitToDataContract()),
                r =>
                    {
                        folder.DataContract.BeWoFolderOid = r;
                        folder.DataContract.BeWoFolderVersion = 1;
                    }
                );
        }

        private static void UpdateFolder(BeWoFolderVM folder)
        {
            ServiceFacade.DoOperationsServiceAsync(
                            s => s.UpdateFolder(folder.CommitToDataContract()),
                            r => folder.DataContract.BeWoFolderVersion = r.BeWoFolderVersion);

        }

        private static void DeleteFolder(BeWoFolderVM folder)
        {
            if (folder.SubFolders != null)
            {
                foreach (var subfolder in folder.SubFolders)
                {
                    DeleteFolder(subfolder);
                }
            }
            if (folder.ParentFolder != null && folder.Files != null)
            {
                foreach (var file in folder.Files)
                {
                    folder.ParentFolder.Files.Add(file);
                    file.Folder = folder.ParentFolder;
                }
            }

            if (folder.DataContract.BeWoFolderOid.HasValue && folder.DataContract.BeWoFolderVersion.HasValue)
                ServiceFacade.DoOperationsServiceSync(
                            s => s.DeleteFolder(folder.DataContract.BeWoFolderOid.Value, folder.DataContract.BeWoFolderVersion.Value));
        }

        private void ContextMenu_Opened(object sender, RoutedEventArgs e)
        {
            if (e.OriginalSource is ContextMenu)
            {
                var menu = e.OriginalSource as ContextMenu;

                var folder = Treeview.SelectedItem as BeWoFolderVM;

                bool enabled = false;

                if (folder != null)
                {
                    if (folder.ParentFolder != null)
                        enabled = true;
                }

                foreach (var item in menu.Items)
                {
                    if (item is MenuItem)
                    {
                        var menuitem = item as MenuItem;
                        if (menuitem.Header.Equals("Umbenennen"))
                            menuitem.IsEnabled = enabled;
                    }
                }
            }
        }

        private void ContextMenu_Click(object sender, RoutedEventArgs e)
        {
            var source = e.OriginalSource as MenuItem;
            if (source != null)
            {
                var twi = source;

                if (twi.Header.Equals("Neu"))
                {
                    var item = (BeWoFolderVM) Treeview.SelectedItem;
                    var newItem = new BeWoFolderVM(new BeWoFolderDC()) {Name = "Neuer Ordner"};

                    _SelectedTreeNode.ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
                    item.SubFolders.Add(newItem);
                    newItem.ParentFolder = item;
                    InsertFolder(newItem);
                    _SelectedTreeNode.IsExpanded = true;
                }
                else if (twi.Header.Equals("Umbenennen"))
                {
                    EditSelected();
                }
                else if (twi.Header.Equals("Löschen"))
                {
                    var p = ItemsControl.ItemsControlFromItemContainer(_SelectedTreeNode) as TreeViewItem;
                    if (p == null && ((BeWoFolderVM)Treeview.SelectedItem).Name.Equals("Vorlagen"))
                    {
                        MessageBox.Show("Das Löschen dieses Ordners ist leider nicht möglich.", "Löschen nicht möglich", MessageBoxButton.OK, MessageBoxImage.Information);
                        return;
                    }

                    var child = (BeWoFolderVM)Treeview.SelectedItem;

                    if (MessageBox.Show("ACHTUNG: Das Löschen von Ordnern kann nicht rückgängig gemacht werden.\n" +
                                        "Alle enthaltenen Dokumente bleiben erhalten und werden in den obersten Ordner \"Alle Ordner\" verschoben.\n\n" +
                                        "Wollen Sie den Ordner '" + child.Name + "' wirklich löschen?",
                                        "Löschen bestätigen", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
                    {
                        if (p != null)
                            p.IsSelected = true;

                        var parent = (BeWoFolderVM) Treeview.SelectedItem;
                        parent.SubFolders.Remove(child);
                        DeleteFolder(child);
                    }
                }
            }
        }

        private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
        {
            var ig = (ItemContainerGenerator) sender;
            if (ig.Status != GeneratorStatus.ContainersGenerated) return;

            var n = (TreeViewItem) ig.ContainerFromIndex(_SelectedTreeNode.Items.Count - 1);
            n.IsSelected = true;

            new DispatcherTimer(
                TimeSpan.FromMilliseconds(200),
                DispatcherPriority.Background,
                (s1, e1) =>
                    {
                        _SelectedTreeNode = n;
                        EditSelected();
                        ((DispatcherTimer) s1).Stop();
                    },
                Dispatcher).Start();

            _SelectedTreeNode.ItemContainerGenerator.StatusChanged -= ItemContainerGenerator_StatusChanged;
        }

        private void EditSelected()
        {
            var textBox = BeWoWpfUtils.FindVisualChild<TextBox>(_SelectedTreeNode);
            textBox.IsReadOnly = false;
            textBox.BorderThickness = new Thickness(1);
            textBox.Background = Brushes.White;
            textBox.Tag = Treeview.SelectedItem;
            textBox.Focus();
            textBox.SelectAll();
        }

        private void DeleteButton_Click(object sender, RoutedEventArgs e)
        {
            var lDC = datagrid_documents.GetCurrentValue<FileAttachmentVM>();

            if (lDC == null)
                return;

            if (MessageBox.Show("ACHTUNG: Das Löschen von Dateien kann nicht rückgängig gemacht werden!\nWollen Sie das Dokument '" + lDC.FileName + "' wirklich löschen?", "Löschen bestätigen", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.No)
                return;

            BeWoFolderVM parentFolder = lDC.Folder;

            if (lDC.DataContract.FileAttachmentOid.HasValue && lDC.DataContract.FileAttachmentVersion.HasValue)
                ServiceFacade.DoOperationsServiceAsync(s => s.DeleteFileAttachment(lDC.DataContract.FileAttachmentOid.Value, lDC.DataContract.FileAttachmentVersion.Value));

            if (parentFolder != null)
                parentFolder.Files.Remove(lDC);

            BeWoWpfUtils.RefreshDXGrid(datagrid_documents);
        }
        
        private void Hyperlink_OnRequestNavigate(object sender, RequestNavigateEventArgs e)
        {
            var hyperLink = (Hyperlink) sender;
            var navitageUri = ((Hyperlink)sender).NavigateUri.ToString();
            var splittedUri = navitageUri.Split('=');
            long fileOid;
            long.TryParse(splittedUri[1], out fileOid);

            try
            {
                var lFA = new FileAttachmentDC();

                ServiceFacade.DoDownloadServiceAsync(d => lFA = d.GetFileAttachment(fileOid),
                                                     cb => this.Dispatch(delegate
                                                     {
                                                         if (lFA.URL == null)
                                                             return;

                                                         if (hyperLink.Tag != null)
                                                         {
                                                             var tmp = Path.GetTempPath() + Path.GetFileName(lFA.URL);

                                                             using (var uFileStream = File.Create(tmp))
                                                             {
                                                                 uFileStream.Write(lFA.BinaryData, 0, lFA.BinaryData.Length);

                                                                 uFileStream.Close();
                                                                 switch (hyperLink.Tag.ToString())
                                                                 {
                                                                     case "Bearbeiten":
                                                                         OpenSerienBrief(ViewDestination.Edit, tmp, lFA.FileAttachmentType, lFA);
                                                                         break;
                                                                     case "Drucken":
                                                                         OpenSerienBrief(ViewDestination.Printer, tmp, lFA.FileAttachmentType);
                                                                         break;
                                                                     case "Vorschau":
                                                                         OpenSerienBrief(ViewDestination.Preview, tmp, lFA.FileAttachmentType);
                                                                         break;
                                                                 }
                                                                 
                                                                 uFileStream.Dispose();
                                                                 return;
                                                             }
                                                         }

                                                         var odialog = new OpenOrSaveDialog(lFA.FileName);
                                                         odialog.ShowDialog();

                                                         if (odialog.Selection == null)
                                                             return;

                                                         if (!odialog.Selection.Value)
                                                         {
                                                             var tmp = Path.GetTempPath() + Path.GetFileName(lFA.URL);

                                                             using (var uFileStream = File.Create(tmp))
                                                             {
                                                                 uFileStream.Write(lFA.BinaryData, 0, lFA.BinaryData.Length);
                                                                 System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(tmp));

                                                                 uFileStream.Close();
                                                                 uFileStream.Dispose();
                                                                 return;
                                                             }
                                                         }

                                                         if (odialog.Selection.Value)
                                                         {
                                                             var sf = new SaveFileDialog { FileName = Path.GetFileName(lFA.URL) };
                                                             if (sf.ShowDialog() != true)
                                                                 return;

                                                             using (var myStream = (FileStream)sf.OpenFile())
                                                             {
                                                                 myStream.Write(lFA.BinaryData, 0, lFA.BinaryData.Length);
                                                                 myStream.Close();
                                                             }
                                                         }
                                                     }));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Exclamation);
            }
        }

        private void TreeViewItem_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            var source = e.OriginalSource as DependencyObject;
            while (source != null && !(source is TreeViewItem))
            {
                source = VisualTreeHelper.GetParent(source);
            }

            if (source != null)
            {
                ((TreeViewItem) source).IsSelected = true;
                _SelectedTreeNode = (TreeViewItem) source;
            }
            else
            {
                _SelectedTreeNode = null;
            }
        }

        private void treeview_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (drag == null) return;

            var node = drag as BeWoFolderVM;
            var file = drag as FileAttachmentVM;
            drag = null;

            CursorControl.Visibility = Visibility.Collapsed;

            var newParent = Treeview.GetDataItemUnderMouse<BeWoFolderVM>(e);

            if (newParent != null)
            {
                if (node != null)
                {
                    var children = node.SubFolders.FlatOut(d => d.SubFolders).ToList();

                    if (newParent.Equals(node) || node.ParentFolder == null || children.Contains(newParent))
                    {
                        return;
                    }

                    node.ParentFolder.SubFolders.Remove(node);
                    newParent.SubFolders.Add(node);
                    node.ParentFolder = newParent;

                    UpdateFolder(node);
                }
                else if (file != null)
                {
                    file.Folder.Files.Remove(file);
                    newParent.Files.Add(file);
                    file.Folder = newParent;

                    UpdateFile(file);
                }
            }
            _MouseDownPosition = new Point(-1, -1);
        }

        private void treeview_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            if (drag != null && _MouseDownPosition.X >= 0 && _MouseDownPosition.Y >= 0)
            {
                Point p = e.GetPosition(this);
                var distX = (int) Math.Abs(p.X - _MouseDownPosition.X);
                var distY = (int) Math.Abs(p.Y - _MouseDownPosition.Y);
                if (distX > 10 || distY > 10)
                {
                    Rect bounds = VisualTreeHelper.GetDescendantBounds(this);

                    if ((bounds.Top < p.Y) && (bounds.Bottom > p.Y))
                        Canvas.SetTop(CursorControl, p.Y);

                    if ((bounds.Left < p.X) && (bounds.Right > p.X))
                        Canvas.SetLeft(CursorControl, p.X);

                    CursorControl.Visibility = Visibility.Visible;

                    if (drag is BeWoFolderVM)
                    {
                        ImageFolder.Visibility = Visibility.Visible;
                        ImageFile.Visibility = Visibility.Hidden;
                        var folder = drag as BeWoFolderVM;
                        LabelFrom.Text = String.Format("Verzeichnis {0}", folder.Name);
                    }
                    else if (drag is FileAttachmentVM)
                    {
                        ImageFolder.Visibility = Visibility.Hidden;
                        ImageFile.Visibility = Visibility.Visible;
                        var file = drag as FileAttachmentVM;
                        LabelFrom.Text = String.Format("Datei {0}", file.FileName);
                    }
                    var targetFolder = Treeview.GetDataItemUnderMouse<BeWoFolderVM>(e);


                    LabelTo.Text = targetFolder != null ? String.Format("-> Nach {0} verschieben", targetFolder.Name) : "";
                }
            }
        }

        private static void UpdateFile(FileAttachmentVM file)
        {
            ServiceFacade.DoOperationsServiceAsync(
                        s => s.UpdateFileAttachment(file.CommitToDataContract()),
                        r => file.DataContract.FileAttachmentVersion = r.FileAttachmentVersion);
        }

        private void treeview_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            drag = Treeview.GetDataItemUnderMouse<BeWoFolderVM>(e) ?? datagrid_documents.GetRow(datagrid_documents.View.GetRowHandleByMouseEventArgs(e));
            _MouseDownPosition = e.GetPosition(this);
        }

        private void OpenSerienBrief(ViewDestination viewDestination, string pPath, FileAttachmentType fileType, FileAttachmentDC file = null)
        {
            var wp = new WordProcessor
                {
                    DocumentPath = pPath,
                    CreateFormLetter = true
                };

            if (fileType.Equals(FileAttachmentType.CustomerTemplate))
            {
                wp.TableModel = new CustomerTableModel { Customers = new List<CustomerDC>() };
            }
            else if (fileType.Equals(FileAttachmentType.PersonTemplate))
            {
                wp.TableModel = new PersonTableModel {Persons = new List<PersonDC>()};
            }
            else if (fileType.Equals(FileAttachmentType.OrganisationTemplate))
            {
                wp.TableModel = new OrganisationTableModel {Organisations = new List<OrganisationDC>()};
            }
            else if (fileType.Equals(FileAttachmentType.SupportConceptTemplate))
            {
                wp.TableModel = new SupportConceptTableModel { SupportConcepts = new List<SupportConceptDC>() };
            }

            if(viewDestination.Equals(ViewDestination.Edit) && file != null)
                wp.FileAttachment = file;

            wp.TemplateView = this;
            wp.CreateReport(viewDestination, null, null);
        }
    }
}
