using Microsoft.Owin;
using Microsoft.Owin.Cors;
using Owin;
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Dispatcher;
using System.Collections.Generic;
using System.IO;
using WebApi.Models;
using System.Configuration;
using C1.Web.Api.Image;
using C1.Web.Api.BarCode;
using C1.Web.Api.Storage;
using C1.Web.Api.DataEngine;
using C1.Web.Api.Excel;
using C1.Web.Api.Report;
using C1.Web.Api.Pdf;
using WebApi.Controllers;

[assembly: OwinStartup(typeof(WebApi.Startup))]

namespace WebApi
{
    /// <summary>
    /// Owin startup class.
    /// </summary>
    public class Startup
    {
        private readonly HttpConfiguration config = GlobalConfiguration.Configuration;

        public void Configuration(IAppBuilder app)
        {
            // Tracing support
            //config.EnableSystemDiagnosticsTracing();

            // CORS supports - does not apply to <form>
            app.UseCors(CorsOptions.AllowAll);
            
            // Web Api
            RegisterRoutes(config);
            app.UseWebApi(config);

            // Anything unhandled
            app.Run(context =>
            {
                context.Response.Redirect(context.Request.PathBase + "/default.html");
                return Task.FromResult(0);
            });

            app.UseStorageProviders()
                .AddDiskStorage("ExcelRoot", GetFullRoot("ExcelRoot"))
                .AddDiskStorage("PdfRoot", GetFullRoot("PdfRoot"));

            app.UseReportProviders()
                .AddFlexReportDiskStorage("ReportsRoot", GetFullRoot("ReportsRoot"))
                .AddSsrsReportHost("c1ssrs", "http://ssrs.componentone.com:8000/ReportServer", new System.Net.NetworkCredential("ssrs_demo", "bjqveS5gh89BH1Q"));

            var clientId = ConfigurationManager.AppSettings["ClientId"];
            var username = ConfigurationManager.AppSettings["UserName"];
            var password = ConfigurationManager.AppSettings["Password"];
            app.AddOneDriveStorage("OneDrive", clientId, "onedrive.readonly", username, password);

            app.UseDataProviders()
                .AddItemsSource("Sales", () => Sale.GetData(10).ToList())
                .AddItemsSource("Orders", () => CustomerOrder.GetOrderData(20).ToList())
                .Add("Nwind", new SqlDataProvider(ConfigurationManager.ConnectionStrings["Nwind"].ConnectionString));

            app.UseDataEngineProviders()
                .AddDataEngine("complex10", () =>
                {
                    return ProductData.GetData(100000);
                })
                .AddDataEngine("complex50", () =>
                {
                    return ProductData.GetData(500000);
                })
                .AddDataEngine("complex100", () =>
                {
                    return ProductData.GetData(1000000);
                })
                .AddDataSource("dataset10", () => ProductData.GetData(100000).ToList())
                .AddDataSource("dataset50", () => ProductData.GetData(500000).ToList())
                .AddDataSource("dataset100", () => ProductData.GetData(1000000).ToList())
                .AddCube("cube",
                    @"Data Source=http://ssrs.componentone.com/OLAP/msmdpump.dll;Provider=msolap;Initial Catalog=AdventureWorksDW2012Multidimensional",
                    "Adventure Works");

            CacheDataEngineDataKey(app);
        }

        private void CacheDataEngineDataKey(IAppBuilder app)
        {
            var providerManager = app.UseDataEngineProviders();
            foreach(var key in providerManager.Items.Keys)
            {
                C1Controller.DataEngineKeys.Add(new DataEngineKey {
                    Name = key
                });
            }
        }

        private static string GetFullRoot(string root)
        {
            var applicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
            var fullRoot = Path.GetFullPath(Path.Combine(applicationBase, root));
            if (!fullRoot.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal))
            {
                // When we do matches in GetFullPath, we want to only match full directory names.
                fullRoot += Path.DirectorySeparatorChar;
            }
            return fullRoot;
        }

        private static void RegisterRoutes(HttpConfiguration config)
        {
            // Use APIs defined in the C1 library
            config.Services.Replace(typeof(IAssembliesResolver), new CustomAssembliesResolver());

            // Attribute Routes
            config.MapHttpAttributeRoutes(new CustomDirectRouteProvider());

            // default route
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            config.Services.Replace(typeof(IHttpControllerTypeResolver), new ReportsControllerTypeResolver());
        }
    }

    internal class CustomAssembliesResolver : DefaultAssembliesResolver
    {
        public override ICollection<System.Reflection.Assembly> GetAssemblies()
        {
            var assemblies = base.GetAssemblies();
            var customControllersAssembly = typeof(ExcelController).Assembly;
            if (!assemblies.Contains(customControllersAssembly))
            {
                assemblies.Add(customControllersAssembly);
            }

            customControllersAssembly = typeof(ReportController).Assembly;
            if (!assemblies.Contains(customControllersAssembly))
            {
                assemblies.Add(customControllersAssembly);
            }

            customControllersAssembly = typeof(ImageController).Assembly;
            if (!assemblies.Contains(customControllersAssembly))
            {
                assemblies.Add(customControllersAssembly);
            }

            customControllersAssembly = typeof(BarCodeController).Assembly;
            if (!assemblies.Contains(customControllersAssembly))
            {
                assemblies.Add(customControllersAssembly);
            }

            customControllersAssembly = typeof(StorageController).Assembly;
            if (!assemblies.Contains(customControllersAssembly))
            {
                assemblies.Add(customControllersAssembly);
            }

            customControllersAssembly = typeof(DataEngineController).Assembly;
            if (!assemblies.Contains(customControllersAssembly))
            {
                assemblies.Add(customControllersAssembly);
            }

            customControllersAssembly = typeof(PdfController).Assembly;
            if (!assemblies.Contains(customControllersAssembly))
            {
                assemblies.Add(customControllersAssembly);
            }

            return assemblies;
        }
    }
}