using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace PXP.Crawler.API.Model
{
    [Serializable]
    public class ProjectDomain : IDisposable
    {
        internal AppDomain domain;
        internal Project project;

        public ProjectDomain(Project proj)
        {
            project = proj;
        }

        public void Unload()
        {
            Debug.WriteLine("Domain Unload: " + project.name);

            if (domain != null)
                AppDomain.Unload(domain);
            domain = null;
        }

        public void Reload()
        {
            Unload();

            Init();
        }

        public bool Init()
        {
            project.Log("Project domain init...");

            project.WriteAsmData();

            AppDomainSetup domSetup = new AppDomainSetup(); //AppDomain.CurrentDomain.SetupInformation;

            domSetup.ApplicationBase = PluginManager.Current.refresPath;
            domSetup.ShadowCopyFiles = "true";
            
            //string pbp = PluginManager.Current.refresPath + "ProjectsBin";
            //domSetup.PrivateBinPath = pbp;
            string aName = "PDom_" + project.guid.ToString();
            domain = AppDomain.CreateDomain(aName, null, domSetup);


            //domain.Load(AssemblyName.GetAssemblyName("Microsoft.CSharp.dll"));
            //AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(domain_AssemblyResolve);
            domain.AssemblyResolve += new ResolveEventHandler(asmResolve);            
            domain.AssemblyLoad += new AssemblyLoadEventHandler(domain_AssemblyLoad);
            /*domain.Load("Microsoft.CSharp.dll");
            domain.Load("System.dll");
            domain.Load("System.Core.dll");
            domain.Load("System.Data.dll");
            domain.Load("System.Data.DataSetExtensions.dll");
            domain.Load("System.Drawing.dll");
            domain.Load("System.Windows.Forms.dll");
            domain.Load("System.Xml.dll");
            domain.Load("System.Xml.Linq.dll");*/
            domain.Load(AssemblyName.GetAssemblyName("Skybound.Gecko.dll"));

            domain.Load(AssemblyName.GetAssemblyName("DevExpress.Data.v14.1.dll"));
            domain.Load(AssemblyName.GetAssemblyName("DevExpress.Printing.v14.1.Core.dll"));
            domain.Load(AssemblyName.GetAssemblyName("DevExpress.Utils.v14.1.dll"));
            domain.Load(AssemblyName.GetAssemblyName("DevExpress.XtraBars.v14.1.dll"));
            domain.Load(AssemblyName.GetAssemblyName("DevExpress.XtraEditors.v14.1.dll"));
            domain.Load(AssemblyName.GetAssemblyName("DevExpress.XtraGrid.v14.1.dll"));
            domain.Load(AssemblyName.GetAssemblyName("DevExpress.XtraLayout.v14.1.dll"));
            domain.Load(AssemblyName.GetAssemblyName("DevExpress.XtraPrinting.v14.1.dll"));
            domain.Load(AssemblyName.GetAssemblyName("DevExpress.XtraTreeList.v14.1.dll"));
            domain.Load(AssemblyName.GetAssemblyName("DevExpress.XtraVerticalGrid.v14.1.dll"));
            domain.Load(AssemblyName.GetAssemblyName("PXP.Crawler.API.dll"));

            domain.Load(AssemblyName.GetAssemblyName("ScintillaNET.dll"));

            PluginManager.Current.InitializeDomain(this);

            if (project.assemblyData.Length > 0)
            {
                string an = "PBIN_" + project.guid;
                AssemblyName asmName = AssemblyName.GetAssemblyName(an + ".dll");
                asmName.Name = an;
                try
                {
                    domain.Load(asmName);
                }
                catch (FileNotFoundException fnfExc)
                {
                    project.Log("Assembly not found: " + an + ".dll");
                }
            }
                //domain.Load();
            //string pbPath = Application.ExecutablePath.Substring(0, Application.ExecutablePath.LastIndexOf('\\')) + "\\PBIN_" + project.guid.ToString() + ".dll";
            //project.assemblyData

            return true;
        }

        private Assembly asmResolve(object sender, ResolveEventArgs args)
        {
            string dllName = args.Name.Contains(',') ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll", "");

            if (dllName.EndsWith("resources"))
                return null;

            dllName += ".dll";

            string exePath = Application.ExecutablePath.Substring(0, Application.ExecutablePath.LastIndexOf('\\')) + "\\";
            string plugsPath = exePath + "Plugins\\";

            if (File.Exists(plugsPath + dllName))
            {
                return PluginManager.LoadAssembly(plugsPath + dllName);
            }

            if (!File.Exists(exePath + dllName))
                return null;

            return PluginManager.LoadAssembly(exePath + dllName);
        }

        private void domain_AssemblyLoad(object sender, AssemblyLoadEventArgs args)
        {
            if (args.LoadedAssembly.FullName.StartsWith("PBIN"))
            {
                project.Log("Assembly Loaded: " + args.LoadedAssembly.FullName);
            }
        }

        public void Dispose()
        {
            Unload();
        }

    }
}