using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Caching;
using MapAround.Caching;
using MapAround.DataProviders;
using MapAround.Geometry;
using MapAround.Mapping;
using MapAround.Web;
using MapAround.Web.Wms;

namespace WebExample.Map
{
    /// <summary>
    /// Summary description for WMSHandler
    /// </summary>
    public class WMSHandler : IHttpHandler
    {

        public const string SessionWorkspaceKeyPrefix = "maphandling_mapworkspace_";
        public const string TileCacheKeyPrefix = "DemoTileCache";
        private string MapFolder;
        
        private MapWorkspace mapWs = null;
      

        private HttpContext httpContext;

        public void ProcessRequest(HttpContext context)
        {
            httpContext = context;
            //Receiving the path to the Workspace.
            var WorkspaceFilePath = System.IO.Path.Combine(httpContext.Server.MapPath("~"), "workspace.xml");
            //Receiving the path to the directory with map data.
            MapFolder = System.IO.Path.Combine(httpContext.Server.MapPath("~"), "..", "..", "data");

            mapWs = new MapWorkspace();
            mapWs.XmlRepresentation = File.ReadAllText(WorkspaceFilePath);
            mapWs.Map.RenderingSettings.AntiAliasGeometry = true;
            mapWs.Map.RenderingSettings.AntiAliasText = true;




            foreach (LayerBase l in mapWs.Map.Layers)
            {
                //In this example, we use only vector layers. But MapAround also supports raster layers.
                FeatureLayer fl = l as FeatureLayer;
                if (fl != null)
                {
                    fl.DataSourceNeeded += LayerDataSourceNeeded;
                    fl.DataSourceReadyToRelease += LayerDataSourceReadyToRelease;

                    if (!fl.AreFeaturesAutoLoadable)
                        fl.LoadFeatures();
                }

            }

            mapWs.Map.FeatureRenderer.SelectionColor = ColorTranslator.FromHtml("#0000FF");

            BoundingRectangle bbox = new BoundingRectangle();
            if (context.Request.Params.AllKeys.Contains("BBOX", StringComparer.InvariantCultureIgnoreCase))
            {
                bbox = QueryStringDataExtractor.GetBBox(httpContext.Request.QueryString["BBOX"]);
            }


            if (context.Request.Params.AllKeys.Contains("LAYERS", StringComparer.InvariantCultureIgnoreCase))
            {
                string[] layersAliases = context.Request.Params["LAYERS"].Split(',');
                foreach (LayerBase l in mapWs.Map.Layers)
                    l.Visible = layersAliases.Contains(l.Alias);
            }


            IMapServer server = new WMSServer(new WmsServiceDescription("MapAround Demo", ""));
            server.ImageQuality = 95;
            server.Map = mapWs.Map;
            server.GutterSize = 180;
            server.BeforeRenderNewImage += server_BeforeRenderNewImage;

            FileTileCacheAccessor tileCacheAccessor =
                new FileTileCacheAccessor(Path.Combine(HttpContext.Current.Server.MapPath("~"), "map\\cache"));
            tileCacheAccessor.Prefix = TileCacheKeyPrefix;
            server.TileCacheAccessor = tileCacheAccessor;


            string mime = string.Empty;
            context.Response.Clear();

            server.GetResponse(context.Request.Params, context.Response.OutputStream, out mime);


            context.Response.ContentType = mime;
            context.Response.Cache.SetCacheability(HttpCacheability.Public);
            context.Response.Cache.SetMaxAge(new TimeSpan(24, 0, 0));



            server.BeforeRenderNewImage -= server_BeforeRenderNewImage;

            context.Response.End();
        }





        private void LayerDataSourceNeeded(object sender, MapAround.Mapping.FeatureDataSourceEventArgs e)
        {
            FeatureLayer l = sender as FeatureLayer;
            string featuresFilePath = string.Empty;
            switch (l.DataProviderRegName)
            {

                //Determining which data source is required for the layer
                case "MapAround.DataProviders.ShapeFileSpatialDataProvider":
                    l.AreFeaturesAutoLoadable = true;
                    //Initializing all the settings necessary for the current data source.
                    ShapeFileSpatialDataProvider shapeP = new ShapeFileSpatialDataProvider(); 
                    shapeP.AttributesEncoding = Encoding.UTF8;
                    shapeP.FileName = GetFeaturesFilePath(l.DataProviderParameters["file_name"]);
                    shapeP.ProcessAttributes = true;   
                    WebCacheAccessor wca = new WebCacheAccessor(httpContext.Cache);
                    wca.ExpirationTimeout = new TimeSpan(24, 0, 0);
                    shapeP.CacheAccessor = wca;
                    e.Provider = shapeP;
                    break;
                default:
                    throw new Exception("Map data provider not found: \"" + l.DataProviderRegName + "\"");
            }
        }

        private string GetFeaturesFilePath(string fileNameParameter)
        {
            string featuresFilePath = string.Empty;

            if (string.IsNullOrEmpty(fileNameParameter))
                throw new ArgumentException("Empty or null", "fileNameParameter");

            if (!fileNameParameter.Contains("\\"))
                featuresFilePath = Path.Combine(MapFolder, Path.GetFileName(fileNameParameter));
            else
                featuresFilePath = fileNameParameter;
             featuresFilePath = System.IO.Path.GetFullPath(featuresFilePath);
            if (!File.Exists(featuresFilePath))
                throw new Exception("File not found: " + featuresFilePath);

            return featuresFilePath;
        }


        private void LayerDataSourceReadyToRelease(object sender, MapAround.Mapping.FeatureDataSourceEventArgs e)
        {
            FeatureLayer l = sender as FeatureLayer;

            switch (l.DataProviderRegName)
            {

                //There is no need for special action to Release the current data source.
                case "MapAround.DataProviders.ShapeFileSpatialDataProvider":
                    break;

               

                default:
                    throw new Exception("Map data provider not found: \"" + l.DataProviderRegName + "\"");
            }
        }

       

        private void server_BeforeRenderNewImage(object sender, RenderNewImageEventArgs e)
        {
            BoundingRectangle bbox = QueryStringDataExtractor.GetBBox(httpContext.Request.QueryString["BBOX"]);
            Size displaySize = QueryStringDataExtractor.GetDisplaySize(httpContext.Request.QueryString["WIDTH"], httpContext.Request.QueryString["HEIGHT"]);
            double mapScale = displaySize.Width / bbox.Width;

            mapWs.Map.LoadFeatures(mapScale, mapWs.Map.MapViewBoxFromPresentationViewBox(e.BboxWithGutters));
            mapWs.Map.LoadRasters(mapScale, mapWs.Map.MapViewBoxFromPresentationViewBox(e.BboxWithGutters));
        }

       

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}