using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using MetadataExtractor;
using MetadataExtractor.Formats.Exif;
using Soletude.Stagsi.Plugins;

namespace TestSortPlugin
{
    public class TestSort: IImageSorterV1
    {
        public string Title { get { return title; } set { title = value; } }
        public Action<IImageSortingV1> Generator { get { return generator; } set { generator = value; } }
        public bool ParallelGeneration { get { return parallelGeneration; } set { parallelGeneration = value; } }

        private static string DateTimeFormat = "yy-MM-dd HH:mm:ss";

        // We init this once so that if the function is repeatedly called
        // it isn't stressing the garbage man.
        private static Regex r = new Regex(":");
        private string title = "Test Sorter";
        private Action<IImageSortingV1> generator = DoGenerate;
        private bool parallelGeneration = true;

        // Retrieves the datetime without loading the whole image.
        public static DateTime GetDateTakenFromImage(string path)
        {
            using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
            using (Image myImage = Image.FromStream(fs, false, false))
            {
                PropertyItem propItem = null;
                try
                {
                    propItem = myImage.GetPropertyItem(36867);
                }
                catch
                {
                    try
                    {
                        propItem = myImage.GetPropertyItem(306);
                    }
                    catch
                    {
                    }
                }
                if (propItem != null)
                {
                    string dateTaken = r.Replace(Encoding.UTF8.GetString(propItem.Value), "-", 2);
                    return DateTime.Parse(dateTaken);
                }
                else
                    return new FileInfo(path).LastWriteTime;
            }
        }

        public static void StagsiPlugin(IPluginService service)
        {
            service.RegisterImageSorterV1(Sort, new TestSort());
        }

        private static void DoGenerate(IImageSortingV1 obj)
        {
            try
            {
                // Read all metadata from the image.
                var metadirectories = ImageMetadataReader.ReadMetadata(obj.FilePath);
                if (metadirectories != null)
                {
                    // Find the so-called EXIF "SubIFD" (which may be null).
                    var subIfdDirectory = metadirectories.OfType<ExifSubIfdDirectory>().FirstOrDefault();

                    DateTime? parsedDateTime = null;
                    if (subIfdDirectory != null)
                    {
                        // Read datetime.
                        string datetime = null;
                        if (subIfdDirectory != null)
                        {
                            datetime = subIfdDirectory.GetString(ExifDirectoryBase.TagDateTimeOriginal);
                        }
                        if (datetime == null && subIfdDirectory != null)
                        {
                            datetime = subIfdDirectory.GetString(ExifDirectoryBase.TagDateTime);
                        }

                        if (datetime != null)
                        {
                            parsedDateTime = DateTaken(datetime);
                        }
                    }

                    if (parsedDateTime == null)
                    {
                        // Try another method to get photo date.
                        parsedDateTime = GetDateTakenFromImage(obj.FilePath);
                    }

                    obj.Generated = new MemoryStream(Encoding.UTF8.GetBytes(
                        parsedDateTime.Value.ToString(DateTimeFormat)));
                }
            }
            catch
            {
                // Ignore errors in MetadataExtractor.
            }
        }

        public static DateTime? DateTaken(string exifDate)
        {
            string[] parts = exifDate.Split(':', ' ');
            int year = int.Parse(parts[0]);
            int month = int.Parse(parts[1]);
            int day = int.Parse(parts[2]);
            int hour = int.Parse(parts[3]);
            int minute = int.Parse(parts[4]);
            int second = int.Parse(parts[5]);

            return new DateTime(year, month, day, hour, minute, second);
        }

        private static List<IImageSortingV1> Sort(List<IImageSortingV1> list)
        {
            var nList = new Dictionary<IImageSortingV1, long>();
            foreach (var v in list)
            {
                var s = v.Generated;
                if (s == null)
                {
                    continue;
                }

                var reader = new StreamReader(v.Generated);
                var text = reader.ReadToEnd();
                reader.Dispose();

                DateTime dt;
                if (DateTime.TryParseExact(text, DateTimeFormat,
                    Thread.CurrentThread.CurrentUICulture,
                    DateTimeStyles.None, out dt))
                {
                    nList.Add(v, dt.Ticks);
                }
            }

            return nList.OrderBy(c => c.Value).Select(d => d.Key).ToList();
        }
    }
}
// ref: MetadataExtractor.dll