using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xaml;
using System.IO.Compression;
using System.Diagnostics;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Core;
using KlassenBIB;

namespace Database
{
    public class Datenbank
    {
        public const string pfad = "./";
        public string projekt;
        public static readonly Datenbank instance = new Datenbank();
        public static Datenbank Instance
        {
            get
            {
                return instance;
            }
        }

        public KlassenBIB.Projekt loadedProjekt = null;

        private string projektpfad = string.Empty;
        public bool LoadProjekt(string projekt, string projektpfad)
        {
            this.projekt = projekt;
            //UnPackProject("18-850","willyteufelchen");
            //PackSystem("./projekte/18-850.zip", "./projekte/18-850","willyteufelchen");

            string filepath = Path.Combine(projektpfad, string.Format("{0}.xaml", projekt));
            this.projektpfad = filepath;
            if (File.Exists(filepath))
                loadedProjekt = XamlServices.Load(filepath) as KlassenBIB.Projekt;
            else
                loadedProjekt = new KlassenBIB.Projekt();
            return true;
        }

        public bool InitProjekt(Projekt projekt,string projektpfad)
        {
            this.projektpfad = Path.Combine(projektpfad,string.Format("{0}.xaml",projekt.Nummer));
            loadedProjekt = projekt;
            SaveProjekt();
            return true;
        }

        private void UnPackProject(string projekt, string password = "")
        {
            if (!Directory.Exists("./temp")) Directory.CreateDirectory("./temp");

            ZipFile zf = null;
            try
            {
                FileStream fs = File.OpenRead(Path.Combine("projekte", string.Format("{0}.zip", projekt)));
                zf = new ZipFile(fs);
                if (!password.Equals("")) zf.Password = password;
                foreach(ZipEntry zipEntry in zf)
                {
                    if (!zipEntry.IsFile) continue;
                    string entryFileName = zipEntry.Name;
                    byte[] buffer = new byte[4096];
                    Stream zipStream = zf.GetInputStream(zipEntry);

                    string fullZipToPath = Path.Combine("./temp/", entryFileName);
                    string directoryName = Path.GetDirectoryName(fullZipToPath);
                    if (directoryName.Length > 0) Directory.CreateDirectory(directoryName);
                    using (FileStream streamWriter = File.Create(fullZipToPath))
                    {
                        StreamUtils.Copy(zipStream, streamWriter, buffer);
                    }
                }
            }
            finally
            {
                if(zf != null)
                {
                    zf.IsStreamOwner = true;
                    zf.Close();
                }
            }
        }

        public bool CreateProjekt(string projektnummer)
        {
            string filepath = Path.Combine(pfad, projektnummer);
            if (File.Exists(filepath)) return false;

            using (MemoryStream memoryStream = new MemoryStream())
            {
                using (ZipArchive archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
                {
                    var demoFile = archive.CreateEntry("daten/foo.txt");
                    using (var entryStream = demoFile.Open())
                    {
                        XamlServices.Save(entryStream, loadedProjekt);
                    }
                }

                using (var fileStream = new FileStream("./test.zip", FileMode.Create))
                {
                    memoryStream.Seek(0, SeekOrigin.Begin);
                    memoryStream.CopyTo(fileStream);
                }
            }

                return true;
        }

        private void PackSystem(string outPathName, string folderName, string password = "")
        {
            FileStream fsOut = File.Create(outPathName);
            ZipOutputStream zipStream = new ZipOutputStream(fsOut);

            zipStream.SetLevel(3);

            if (!password.Equals("")) zipStream.Password = password;

            int folderOffset = folderName.Length +(folderName.EndsWith("\\") ? 0 : 1);
            CompressFolder(folderName, zipStream, folderOffset);
            zipStream.IsStreamOwner = true;
            zipStream.Close();
        }

        private void CompressFolder(string path, ZipOutputStream zipStream, int folderOffset)
        {
            string[] files = Directory.GetFiles(path);
            foreach(string filename in files)
            {
                FileInfo fi = new FileInfo(filename);
                string entryName = filename.Substring(folderOffset);
                entryName = ZipEntry.CleanName(entryName);
                ZipEntry newEntry = new ZipEntry(entryName);
                newEntry.DateTime = fi.LastWriteTime;
                newEntry.Size = fi.Length;
                zipStream.PutNextEntry(newEntry);
                byte[] buffer = new byte[4096];
                using (FileStream streamReader = File.OpenRead(filename))
                {
                    StreamUtils.Copy(streamReader, zipStream, buffer);
                }
                zipStream.CloseEntry();
            }
            string[] folders = Directory.GetDirectories(path);
            foreach(string folder in folders)
            {
                CompressFolder(folder, zipStream, folderOffset);
            }
        }

        public void Test()
        {

            
            using (MemoryStream memoryStream = new MemoryStream())
            {
                using (var fileStream = new FileStream("./test.zip", FileMode.Open))
                {
                    fileStream.Seek(0, SeekOrigin.Begin);
                    fileStream.CopyTo(memoryStream);
                }
                using (ZipArchive archive = new ZipArchive(memoryStream, ZipArchiveMode.Update, true))
                {
                    ZipArchiveEntry test = archive.CreateEntry("./datas/test.txt");
                    Debugger.Break();
                }

                    Debugger.Break();
            }
        }

        public void SaveProjekt()
        {
            XamlServices.Save(projektpfad, loadedProjekt);
        }
    }
}
