using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Windows.ApplicationModel.Resources.Core;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using System.Collections.Specialized;
using System.Threading.Tasks;
using Windows.Storage;

// Das von dieser Datei definierte Datenmodell dient als repräsentatives Beispiel für ein Modell
// mit starker Typisierung, das Benachrichtigungen unterstützt, wenn Member hinzugefügt, entfernt oder geändert werden. Die gewählten
// Eigenschaftennamen stimmen mit Datenbindungen in den Standardelementvorlagen überein.
//
// Anwendungen können dieses Modell als Startpunkt verwenden und darauf aufbauen. Es kann jedoch auch komplett verworfen und
// durch ein anderes den Anforderungen entsprechendes Modell ersetzt werden

namespace EAT_IT.Data
{
    /// <summary>
    /// Basisklasse für <see cref="SampleDataItem"/> und <see cref="SampleDataGroup"/>, die
    /// die gemeinsamen Eigenschaften für beides definiert.
    /// </summary>
    [Windows.Foundation.Metadata.WebHostHidden]
    public abstract class SampleDataCommon : EAT_IT.Common.BindableBase
    {
        private static Uri _baseUri = new Uri("ms-appx:///");

        public SampleDataCommon(String uniqueId, String title, String subtitle, String imagePath, String description)
        {
            this._uniqueId = uniqueId;
            this._title = title;
            this._subtitle = subtitle;
            this._description = description;
            this._imagePath = imagePath;
        }

        private string _uniqueId = string.Empty;
        public string UniqueId
        {
            get { return this._uniqueId; }
            set { this.SetProperty(ref this._uniqueId, value); }
        }

        private string _title = string.Empty;
        public string Title
        {
            get { return this._title; }
            set { this.SetProperty(ref this._title, value); }
        }

        private string _subtitle = string.Empty;
        public string Subtitle
        {
            get { return this._subtitle; }
            set { this.SetProperty(ref this._subtitle, value); }
        }

        private string _description = string.Empty;
        public string Description
        {
            get { return this._description; }
            set { this.SetProperty(ref this._description, value); }
        }

        private ImageSource _image = null;
        private String _imagePath = null;
        public ImageSource Image
        {
            get
            {
                if (this._image == null && this._imagePath != null)
                {
                    this._image = new BitmapImage(new Uri(SampleDataCommon._baseUri, this._imagePath));
                }
                return this._image;
            }

            set
            {
                this._imagePath = null;
                this.SetProperty(ref this._image, value);
            }
        }

        public void SetImage(String path)
        {
            this._image = null;
            this._imagePath = path;
            this.OnPropertyChanged("Image");
        }

        public override string ToString()
        {
            return this.Title;
        }
    }

    /// <summary>
    /// Generisches Elementdatenmodell
    /// </summary>
    public class SampleDataItem : SampleDataCommon
    { 
        // Hier haben wir zusätzlich dataname und rating benötigt und hinzugefügt.
        public SampleDataItem(String uniqueId, String dataname, String title, String subtitle, Double rating, String imagePath, String description, String content, SampleDataGroup group)
            : base(uniqueId, title, subtitle, imagePath, description)
        {
            this._content = content;
            this._group = group;
            this._rating = rating;
            this._dataname = dataname;
        }

        private string _dataname = string.Empty;
        public string Dataname
        {
            get { return this._dataname; }
            set { this.SetProperty(ref this._dataname, value); }
        }

        private double _rating = 0;
        public double Rating
        {
            get { return this._rating; }
            set { this.SetProperty(ref this._rating, value); }
        }

        private string _content = string.Empty;
        public string Content
        {
            get { return this._content; }
            set { this.SetProperty(ref this._content, value); }
        }

        private SampleDataGroup _group;
        public SampleDataGroup Group
        {
            get { return this._group; }
            set { this.SetProperty(ref this._group, value); }
        }
    }

    /// <summary>
    /// Generisches Gruppendatenmodell
    /// </summary>
    public class SampleDataGroup : SampleDataCommon
    {
        public SampleDataGroup(String uniqueId, String title, String subtitle, String imagePath, String description)
            : base(uniqueId, title, subtitle, imagePath, description)
        {
            Items.CollectionChanged += ItemsCollectionChanged;
        }

        private void ItemsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            // Stellt aus zwei Gründen eine Teilmenge der vollständigen Elementauflistung zum Binden aus einer GroupedItemsPage
            // bereit: GridView virtualisiert keine großen Elementauflistungen, und das
            // Benutzererlebnis wird beim Navigieren durch Gruppen mit einer großen Anzahl von Elementen
            // verbessert.
            //
            // Maximal zwölf Elemente werden angezeigt, da dies zu gefüllten Rasterspalten führt,
            // unabhängig davon, ob 1, 2, 3, 4 oder 6 Zeilen angezeigt werden.

            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    if (e.NewStartingIndex < 12)
                    {
                        TopItems.Insert(e.NewStartingIndex, Items[e.NewStartingIndex]);
                        if (TopItems.Count > 12)
                        {
                            TopItems.RemoveAt(12);
                        }
                    }
                    break;
                case NotifyCollectionChangedAction.Move:
                    if (e.OldStartingIndex < 12 && e.NewStartingIndex < 12)
                    {
                        TopItems.Move(e.OldStartingIndex, e.NewStartingIndex);
                    }
                    else if (e.OldStartingIndex < 12)
                    {
                        TopItems.RemoveAt(e.OldStartingIndex);
                        TopItems.Add(Items[11]);
                    }
                    else if (e.NewStartingIndex < 12)
                    {
                        TopItems.Insert(e.NewStartingIndex, Items[e.NewStartingIndex]);
                        TopItems.RemoveAt(12);
                    }
                    break;
                case NotifyCollectionChangedAction.Remove:
                    if (e.OldStartingIndex < 12)
                    {
                        TopItems.RemoveAt(e.OldStartingIndex);
                        if (Items.Count >= 12)
                        {
                            TopItems.Add(Items[11]);
                        }
                    }
                    break;
                case NotifyCollectionChangedAction.Replace:
                    if (e.OldStartingIndex < 12)
                    {
                        TopItems[e.OldStartingIndex] = Items[e.OldStartingIndex];
                    }
                    break;
                case NotifyCollectionChangedAction.Reset:
                    TopItems.Clear();
                    while (TopItems.Count < Items.Count && TopItems.Count < 12)
                    {
                        TopItems.Add(Items[TopItems.Count]);
                    }
                    break;
            }
        }

        private ObservableCollection<SampleDataItem> _items = new ObservableCollection<SampleDataItem>();
        public ObservableCollection<SampleDataItem> Items
        {
            get { return this._items; }
        }

        private ObservableCollection<SampleDataItem> _topItem = new ObservableCollection<SampleDataItem>();
        public ObservableCollection<SampleDataItem> TopItems
        {
            get { return this._topItem; }
        }
    }

    /// <summary>
    /// Erstellt eine Auflistung von Gruppen und Elementen mit hartcodiertem Inhalt.
    /// 
    /// SampleDataSource wird üblicherweise mit Platzhalterdaten und nicht mit Daten der Liveproduktion
    /// initialisiert, die Beispieldaten werden zur Entwurfszeit und zur Laufzeit bereitgestellt.
    /// </summary>
    public sealed class SampleDataSource
    {
        public List<string> OpenedData=new List<string>();
        SampleDataGroup group2;
        SampleDataGroup group1;
        private static SampleDataSource _sampleDataSource = new SampleDataSource();
        Rezept rezept = new Rezept();
        MyRecipe MeinRezept = new MyRecipe();

        private ObservableCollection<SampleDataGroup> _allGroups = new ObservableCollection<SampleDataGroup>();
        public ObservableCollection<SampleDataGroup> AllGroups
        {
            get { return this._allGroups; }
        }

        public static void AddDateiname(string dateiname)
        {
            _sampleDataSource.OpenedData.Add(dateiname);
        }

        //Falls ein neues rezept erstellt wird, wird diese Methode benutzt.
        public static void NewSave(MyRecipe MeinRezept)
        {
            int i = _sampleDataSource.group2.Items.Count;
        _sampleDataSource.group2.Items.Add(new SampleDataItem("Group-2-Item-" + i+1,
                    MeinRezept.Dateiname,
                    MeinRezept.Titel,
                    MeinRezept.Schwierigkeit,
                    MeinRezept.Rating,
                    MeinRezept.ImagePfad,
                    MeinRezept.Kurzbeschreibung,
                    _sampleDataSource.BeschreibungfuerNeuGespeichertes(MeinRezept),
                    _sampleDataSource.group2));
                    _sampleDataSource.OpenedData.Add(MeinRezept.Dateiname);
                
        }

        public static Rezept GetRezept()
        {

            return _sampleDataSource.rezept;
        }

        //Diese Methode wird aufgerufen um beim speichern ein Item hinzuzufügen, damit nach dem drücken des Speichernbuttons
        //das Item direkt in den eigenen Rezepten auftaucht und man die App nicht erst neu starten muss
        public static void AddItem(SampleDataItem Item, string dataname)
        {
            Item.Dataname = dataname;
            _sampleDataSource.group2.Items.Add(Item);
        }

        //Diese Methode wird beim löschen von Rezepten aus den eigenen Rezepten aufgerufen
        public static async Task RemoveItem(int index)
        {
            _sampleDataSource.group2.Items.RemoveAt(index);
            StorageFile store = await ApplicationData.Current.LocalFolder.CreateFileAsync(_sampleDataSource.OpenedData[index], Windows.Storage.CreationCollisionOption.ReplaceExisting);
            await store.DeleteAsync();
            _sampleDataSource.OpenedData.RemoveAt(index);
        }

        public static ObservableCollection<SampleDataItem> GetGroups()
        {
            return _sampleDataSource.group2.Items;
        }

        public static IEnumerable<SampleDataGroup> GetGroups(string uniqueId)
        {
            if (!uniqueId.Equals("AllGroups")) throw new ArgumentException("Only 'AllGroups' is supported as a collection of groups");

            return _sampleDataSource.AllGroups;
        }



        public static SampleDataGroup GetGroup(string uniqueId)
        {
            // Einfache lineare Suche ist bei kleinen DataSets akzeptabel.
            var matches = _sampleDataSource.AllGroups.Where((group) => group.UniqueId.Equals(uniqueId));
            if (matches.Count() == 1) return matches.First();
            return null;
        }

        public static SampleDataItem GetItem(string uniqueId)
        {
            // Einfache lineare Suche ist bei kleinen DataSets akzeptabel.
            var matches = _sampleDataSource.AllGroups.SelectMany(group => group.Items).Where((item) => item.UniqueId.Equals(uniqueId));
            if (matches.Count() == 1) return matches.First();
            return null;
        }

        public SampleDataSource()
        {

// Nachfolgend werden zwei SampleDataGroups erzeugt. Wir haben diese beibehalten, da sie sich sehr gut dem Zweck der App anpassen lassen.
// In der group1 werden die Tagesgerichte abgelegt, die group2 enthält als Items die gespeicherten Rezepte (aus der Opener-Methode)
            rezept.MachRezept().ContinueWith(task =>
{
    group1 = new SampleDataGroup("Tagesgerichte",
            "CookIt",
            "Rezept des Tages",
            "Assets/Tagesgerichte.jpg",
            "Rezept des Tages");
    group1.Items.Add(new SampleDataItem("Group-1-Item-1",
        "",
            rezept.Titel[0],
            "Schwierigkeit: " + rezept.Schwierigkeit[0],
            3,
            rezept.ImageURLs[0],
            rezept.Kurzbeschreibung[0],
            BeschreibungsLayout(0, rezept),
            group1));
    group1.Items.Add(new SampleDataItem("Group-1-Item-2",
            "",
            rezept.Titel[1],
            "Schwierigkeit: " + rezept.Schwierigkeit[1],
            3,
            rezept.ImageURLs[1],
            rezept.Kurzbeschreibung[1],
            BeschreibungsLayout(1, rezept),
            group1));
    group1.Items.Add(new SampleDataItem("Group-1-Item-3",
            "",
            rezept.Titel[2],
            "Schwierigkeit: " + rezept.Schwierigkeit[2],
            3,
            rezept.ImageURLs[2],
            rezept.Kurzbeschreibung[2],
            BeschreibungsLayout(2, rezept),
            group1));
    group1.Items.Add(new SampleDataItem("Group-1-Item-4",
            "",
            rezept.Titel[3],
            "Schwierigkeit: " + rezept.Schwierigkeit[3],
            3,
            rezept.ImageURLs[3],
            rezept.Kurzbeschreibung[3],
            BeschreibungsLayout(3, rezept),
            group1));
    group1.Items.Add(new SampleDataItem("Group-1-Item-5",
            "",
            rezept.Titel[4],
            "Schwierigkeit: " + rezept.Schwierigkeit[4],
            3,
            rezept.ImageURLs[4],
            rezept.Kurzbeschreibung[4],
            BeschreibungsLayout(4, rezept),
            group1));
    group1.Items.Add(new SampleDataItem("Group-1-Item-6",
            "",
            rezept.Titel[5],
            "Schwierigkeit: " + rezept.Schwierigkeit[5],
            3,
            rezept.ImageURLs[5],
            rezept.Kurzbeschreibung[5],
            BeschreibungsLayout(5, rezept),
            group1));
    group1.Items.Add(new SampleDataItem("Group-1-Item-7",
            "",
            rezept.Titel[6],
            "Schwierigkeit: " + rezept.Schwierigkeit[6],
            3,
            rezept.ImageURLs[6],
            rezept.Kurzbeschreibung[6],
            BeschreibungsLayout(6, rezept),
            group1));
    this.AllGroups.Add(group1);
}, TaskScheduler.FromCurrentSynchronizationContext());
            group2 = new SampleDataGroup("EigeneRezepte",
            "Eigene Rezepte",
            "Eigene Kreationen genießen",
            "Assets/Eigene Rezepte.jpg",
            "");
            Opener().ContinueWith(task =>
            {

            }, TaskScheduler.FromCurrentSynchronizationContext());

        }

        // Der Opener öffnet die bereits vorhandenen Daten mit der korrekten Endung und fügt sie der Gruppe 2 hinzu.

        private async Task Opener()
        {
            int i = 0;
            var RezeptFiles = await ApplicationData.Current.LocalFolder.GetFilesAsync();
            foreach (var element in RezeptFiles)
            {
                i++;
                var irgendwas = element.Name;
                if (element.Name.ToString().Contains(".EAT"))
                {
                    MeinRezept = await rezept.Opener(element.Name.ToString());
                    group2.Items.Add(new SampleDataItem("Group-2-Item-" + i,
                    MeinRezept.Dateiname,
                    MeinRezept.Titel,
                    MeinRezept.Schwierigkeit,
                    MeinRezept.Rating,
                    MeinRezept.ImagePfad,
                    MeinRezept.Kurzbeschreibung,
                    BeschreibungsLayoutFuerGespeicherte(MeinRezept),
                    group2));
                    OpenedData.Add(MeinRezept.Dateiname);
                }
            }
            this.AllGroups.Add(group2);

        }

        // Die folgenden Methoden sorgen nur dafür, dass die Zutaten und die Beschreibung schön ausgerichtet und angezeigt werden.

        string BeschreibungsLayout(int Itemnumber, Rezept rezept)
        {
            string Inhalt = "";
            int i = 0;
            while (i < rezept.Zutaten[Itemnumber].Count)
            {
                if (rezept.Zutatenmenge[Itemnumber][i] != 0)
                    Inhalt += "\t" + rezept.Zutatenmenge[Itemnumber][i] + " " + rezept.Zutateneinheit[Itemnumber][i] + "\t" + rezept.Zutaten[Itemnumber][i] + "\n";
                else
                    Inhalt += "\t" + rezept.Zutateneinheit[Itemnumber][i] + "\t" + rezept.Zutaten[Itemnumber][i] + "\n";


                i++;
            }
            Inhalt += "\n\n" + rezept.Zubereitung[Itemnumber];
            return Inhalt;

        }
        string BeschreibungsLayoutFuerGespeicherte(MyRecipe rezept)
        {
            string Inhalt = "";
            int i = 0;
            while (i < rezept.Zutaten.Count)
            {

                    if (rezept.Zutatenmenge.Count != 0)
                    {
                        if (rezept.Zutatenmenge[i] != 0)
                            Inhalt += "\t" + rezept.Zutatenmenge[i] + " " + rezept.Zutateneinheit[i] + "\t" + rezept.Zutaten[i] + "\n";
                    }

                    if (rezept.Zutateneinheit.Count != 0)
                    {
                        if (rezept.Zutateneinheit[i] != null)
                            Inhalt += "\t" + rezept.Zutateneinheit[i] + "\t" + rezept.Zutaten[i] + "\n";
                    }
                

                    else
                    Inhalt += "\t" + rezept.Zutaten[i];

                i++;
            }
            Inhalt += "\n\n" + rezept.Zubereitung;
            return Inhalt;

        }
        string BeschreibungfuerNeuGespeichertes(MyRecipe rezept)
        { 
        string Inhalt = "";
            int i = 0;
            while (i < rezept.Zutaten.Count)
            {
                Inhalt += "\t" + rezept.Zutaten[i];

                i++;
            }
            Inhalt += "\n\n\n" + rezept.Zubereitung;
            return Inhalt;
        }
    }
}
