using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Media.Imaging;
using InABox.Clients;
using InABox.Core;
using InABox.WPF;
using Microsoft.Win32;
using Syncfusion.Pdf.Interactive;
using Syncfusion.Pdf.Parsing;
using Syncfusion.Pdf;

namespace InABox.DynamicGrid
{

    public delegate String OnGetWatermark(CoreRow row);

    public class DynamicDocumentGrid<TDocument, TEntity, TEntityLink> : DynamicManyToManyGrid<TDocument, TEntity>
        where TEntity : Entity, IPersistent, IRemotable, new()
        where TDocument : Entity, IEntityDocument<TEntityLink>, IPersistent, IRemotable, new() // Entity, IPersistent, IRemotable, IManyToMany<TEntity, Document>, new()
        where TEntityLink : EntityLink<TEntity>, new()
    {
        private DynamicActionColumn supercedecolumn;

        public bool ShowSupercededColumn
        {
            get
            {
                return supercedecolumn.Position != DynamicActionColumnPosition.Hidden;
            }
            set
            {
                supercedecolumn.Position = value ? DynamicActionColumnPosition.End : DynamicActionColumnPosition.Hidden;
            }
        }

        public DynamicDocumentGrid()
        {
            MultiSelect = false;
            HiddenColumns.Add(x => x.DocumentLink.ID);
            HiddenColumns.Add(x => x.Superceded);
            HiddenColumns.Add(x => x.DocumentLink.FileName);
            ActionColumns.Add(new DynamicImageColumn(DocumentImage, ViewDocument) { Position = DynamicActionColumnPosition.Start });
            ActionColumns.Add(new DynamicImageColumn(DiskImage, SaveDocument) { Position = DynamicActionColumnPosition.Start });
            supercedecolumn = new DynamicImageColumn(SupercededImage, SupercedeDocument);
            ActionColumns.Add(supercedecolumn);
        }

        protected override void DoReconfigure(FluentList<DynamicGridOption> options)
        {
            base.DoReconfigure(options);

            options.Add(DynamicGridOption.DragTarget);
        }

        private bool SaveDocument(CoreRow? row)
        {
            var filename = row.Get<TDocument, string>(x => x.DocumentLink.FileName);
            if (Path.GetExtension(filename).ToUpper().Equals(".PDF"))
            {
                var dlg = new SaveFileDialog();
                dlg.Filter = "PDF Files (*.pdf)|*.pdf";
                dlg.FileName = Path.ChangeExtension(filename, ".pdf");
                if (dlg.ShowDialog() == true)
                {
                    var imageid = row.Get<TDocument, Guid>(x => x.DocumentLink.ID);
                    var data = new Client<Document>().Query(new Filter<Document>(x => x.ID).IsEqualTo(imageid)).Rows.FirstOrDefault().Get<Document, byte[]>(x => x.Data);
                    var name = dlg.FileName;
                    File.WriteAllBytes(name, data);

                    var gsProcessInfo = new ProcessStartInfo();
                    gsProcessInfo.Verb = "open";
                    gsProcessInfo.WindowStyle = ProcessWindowStyle.Normal;
                    gsProcessInfo.FileName = name;
                    gsProcessInfo.UseShellExecute = true;

                    Process.Start(gsProcessInfo);
                }

            }
            else if (Path.GetExtension(filename).ToUpper().Equals(".PNG") || Path.GetExtension(filename).ToUpper().Equals(".JPG") || Path.GetExtension(filename).ToUpper().Equals(".GIF"))
            {
                var imageid = row.Get<TDocument, Guid>(x => x.DocumentLink.ID);
                if (imageid == Guid.Empty)
                    return false;

                var dlg = new SaveFileDialog();
                dlg.Filter = "Image Files (*.png)|*.png";
                dlg.FileName = filename;
                if (dlg.ShowDialog() == true)
                {
                    var bmp = LoadBitmapFromDatabase(imageid);
                    bmp?.Save(dlg.FileName);
                }
            }

            return false;
        }

        private Bitmap LoadBitmapFromDatabase(Guid imageid)
        {
            if (imageid == Guid.Empty)
                return null;
            Bitmap result = null;
            var image = new Client<Document>().Query(
                new Filter<Document>(x => x.ID).IsEqualTo(imageid),
                new Columns<Document>(x => x.ID, x => x.Data)
            ).Rows.FirstOrDefault();
            if (image != null)
            {
                var ms = new MemoryStream(image.Get<Document, byte[]>(x => x.Data));
                result = new Bitmap(ms);
            }

            return result;
        }

        private BitmapImage? DiskImage(CoreRow? arg)
        {
            return Wpf.Resources.disk.AsBitmapImage();
        }

        public override int Order()
        {
            return int.MaxValue;
        }

        private BitmapImage SupercededImage(CoreRow? row)
        {
            if (row == null)
                return Wpf.Resources.tick.AsBitmapImage();
            if (row.Get<TDocument, DateTime>(x => x.Superceded) != DateTime.MinValue)
                return Wpf.Resources.warning.AsBitmapImage();
            return Wpf.Resources.tick.AsBitmapImage();
        }

        private bool SupercedeDocument(CoreRow? row)
        {
            if (!ReadOnly)
            {
                var id = row.Get<TDocument, Guid>(x => x.ID);
                var document = WorkingList.FirstOrDefault(x => x.ID.Equals(id));
                if (document != null)
                    document.Superceded = document.Superceded == DateTime.MinValue ? DateTime.Now : DateTime.MinValue;
                return true;
            }
            else
            {
                return false;
            }
        }

        private BitmapImage DocumentImage(CoreRow? arg)
        {
            return Wpf.Resources.view.AsBitmapImage();
        }

        private bool ViewDocument(CoreRow? row)
        {
            var filename = row.Get<TDocument, string>(x => x.DocumentLink.FileName);
            if (Path.GetExtension(filename).ToUpper().Equals(".PDF"))
            {
                var viewer = new DocumentEditor(row.ToObject<TDocument>());
                viewer.Watermark = OnGetWaterMark?.Invoke(row);
                //viewer.PrintAllowed = true;
                viewer.SaveAllowed = true;
                viewer.ShowDialog();
            }
            else
            {
                var id = row.Get<TDocument, Guid>(x => x.DocumentLink.ID);
                var docrow = new Client<Document>().Query(new Filter<Document>(x => x.ID).IsEqualTo(id)).Rows.FirstOrDefault();
                if (docrow != null)
                {
                    var tmpfile = Path.ChangeExtension(Path.GetTempFileName(), Path.GetExtension(filename));
                    File.WriteAllBytes(tmpfile, docrow.Get<Document, byte[]>(x => x.Data));
                    var gsProcessInfo = new ProcessStartInfo();
                    gsProcessInfo.Verb = "open";
                    gsProcessInfo.WindowStyle = ProcessWindowStyle.Normal;
                    gsProcessInfo.FileName = tmpfile;
                    gsProcessInfo.UseShellExecute = true;

                    Process.Start(gsProcessInfo);
                }
                else
                {
                    MessageBox.Show(string.Format("Unable to retrieve {0}!", filename));
                }
            }

            //Document doc = new Client<Document>().Load(new Filter<Document>(x => x.ID).IsEqualTo(id)).FirstOrDefault();
            //if (doc != null)
            //{
            //    if (System.IO.Path.GetExtension(doc.FileName).ToUpper().Equals(".PDF"))
            //    {
            //        PDFViewer viewer = new PDFViewer(doc);
            //        viewer.ShowDialog();
            //    }
            //    else
            //    {
            //        String filename = System.IO.Path.ChangeExtension(System.IO.Path.GetTempFileName(), System.IO.Path.GetExtension(doc.FileName));
            //        System.IO.File.WriteAllBytes(filename, doc.Data);
            //        ProcessStartInfo gsProcessInfo = new ProcessStartInfo();
            //        gsProcessInfo.Verb = "open";
            //        gsProcessInfo.WindowStyle = ProcessWindowStyle.Normal;
            //        gsProcessInfo.UseShellExecute = true;
            //        gsProcessInfo.FileName = filename;
            //        Process.Start(gsProcessInfo);
            //    }
            //}
            //else
            //    MessageBox.Show("Document does nto exist!");
            return false;
        }

        public event OnGetWatermark OnGetWaterMark;

        protected override void OnDragEnd(Type entity, CoreTable table, DragEventArgs e)
        {
            if (entity == typeof(Document))
            {
                var refresh = false;

                var docIDS = table.Rows.Select(x => x.Get<Document, Guid>(x => x.ID)).ToArray();

                var columns = new Columns<Document>(x => x.ID);
                foreach (var column in VisibleColumns)
                {
                    if (column.ColumnName.StartsWith("DocumentLink."))
                    {
                        columns.Add(string.Join('.', column.ColumnName.Split('.').Skip(1)));
                    }
                }
                var docs = new Client<Document>()
                    .Query(
                        new Filter<Document>(x => x.ID).InList(docIDS),
                        columns);

                foreach (var doc in docs.ToObjects<Document>())
                {
                    var entityDocument = new TDocument();
                    entityDocument.EntityLink.ID = Item.ID;
                    entityDocument.DocumentLink.ID = doc.ID;
                    entityDocument.DocumentLink.Synchronise(doc);
                    SaveItem(entityDocument);
                    refresh = true;
                }
                if (refresh)
                {
                    Refresh(false, true);
                }
            }
            else
            {
                base.OnDragEnd(entity, table, e);
            }
        }

        protected override void DoAdd(bool OpenEditorOnDirectEdit = false)
        {
            var dlg = new OpenFileDialog();
            dlg.Multiselect = true;
            if (dlg.ShowDialog() == true)
            {
                using (new WaitCursor())
                {
                    var docs = new List<Document>();
                    foreach (var filename in dlg.FileNames)
                    {
                        // Create a Document
                        var doc = new Document();
                        doc.FileName = Path.GetFileName(filename).ToLower();
                        doc.TimeStamp = new FileInfo(dlg.FileName).LastWriteTime;
                        doc.Data = File.ReadAllBytes(filename);
                        doc.CRC = CoreUtils.CalculateCRC(doc.Data);
                        docs.Add(doc);
                    }

                    if (docs.Any())
                    {
                        new Client<Document>().Save(docs, "Initial Upload");
                        foreach (var doc in docs)
                        {
                            var newitem = CreateItem();
                            var prop = (IEntityLink)otherproperty.GetValue(newitem);
                            prop.ID = doc.ID;
                            prop.Synchronise(doc);
                            SaveItem(newitem);
                        }
                    }
                }

                Refresh(false, true);
            }
        }
    }
}