using System;
using System.Collections.Generic;
using System.Linq;
using Caliburn.Micro;
using FDOT.GIS.Client;
using FDOT.GIS.Client.Commands;
using FDOT.GIS.Client.Domain;
using FDOT.GIS.Client.Domain.Gis;
using FDOT.GIS.Client.Helpers;
using FDOT.GIS.DataContracts;
using FDOT.GIS.DataContracts.Enums;

namespace FDOT.GIS.Framework.Samples.Commands
{
    public class Identify : ResultBase
    {
        private readonly DataContracts.Geometry _geometry;
        private readonly string _featureTypeName;

        public Identify(DataContracts.Geometry geometry, string featureTypeName)
        { 
            _geometry = geometry;
            _featureTypeName = featureTypeName;
        }

        public IDictionary<FeatureType, ICollection<Feature>> Result { get; internal set; }

        public override void Execute(ActionExecutionContext context)
        {
            try
            {
                ExecuteIdentify(_geometry, _featureTypeName, r =>
                {
                    Log.Info("ExecuteIdentify complete, returned [{0}] results.", r.Count);
                    Result = r;
                    Success();
                });

                //VirtualApplicationManager.Current.QueryManager.ExecuteIdentify(_geometry, r =>
                //{
                //    Log.Info("ExecuteIdentify complete, returned [{0}] results.", r.Count);
                //    Result = r;
                //    Success();
                //});
            }
            catch (Exception ex)
            {
                Log.Error(ex);
                Failure(ex);
            }
        }


        public void ExecuteIdentify(DataContracts.Geometry geometry, string featureTypeName, Action<IDictionary<FeatureType, ICollection<Feature>>> callback)
        {
            Log.Info("ExecuteIdentify called for feature type [{0}].", featureTypeName);

            IEnumerable<DisplayLayer> layers = MapHandler.QueryableLayers.Where(x => x.Name.Equals(featureTypeName));
            Log.Info("Found [{0}] layers matched by feature type name - [{1}].", layers.Count(), string.Join(", ", layers.Select(x => x.Layer.Id)));

            var options = new IdentifyOptions
            {
                Geometry = geometry,
                GeometryType = GeometryTypes.Point,
                ImageDisplay = new ImageDisplay
                {
                    Dpi = (int)MapHandler.CurrentMap.Resolution,
                    Height = (int)MapHandler.CurrentMap.ActualHeight,
                    Width = (int)MapHandler.CurrentMap.ActualWidth
                },
                Tolerance = 5,
                ReturnGeometry = true,
                LayerOptions = new LayersOptions
                {
                    IdentifyLayerLevel = IdentifyLayerLevels.All,
                    LayerIds = layers.Select(x => x.Layer.Id).ToList()
                },
                MapExtent = GeometryTranslator.TranslateEnvelope(MapHandler.GetExtent()),
                SpatialReference = new SpatialReference { WellKnownId = MapHandler.CurrentMap.SpatialReference.WKID.ToString() }
            };

            
            IEnumerable<MapServiceDataSource> registeredDataSources = VirtualApplicationManager.Current.QueryManager.RegisteredDataSources.Cast<MapServiceDataSource>();
            Log.Info("Found [{0}] registered data sources of type [MapServiceDataSource].", registeredDataSources.Count());
            
            if (registeredDataSources.Any())
            {               
                string mapServiceName = registeredDataSources.First().Id;

                MapService mapService = VirtualApplicationManager.Current.MapServices.FirstOrDefault(x => x.Name.Equals(mapServiceName));
                Log.Info("Using map service [{0}] with url [{1}] from first registered data source.", mapServiceName, mapService.Url);

                if (mapService != null)
                {
                    var client = ServiceClients.GetQueryServiceClient();
                    client.IdentifyCompressedCompleted += (s, e) => 
                                                          e.Result.Decompress<FindOperationResults>(r =>
                                                          {
                                                              Log.Info("FindOperationResults decompressed - contains [{0}] items.", r.Results.Count());
                                                              var features = r.ConvertToFeatures(registeredDataSources.First().FeatureTypes);
                                                              Log.Info("Results converted to features - contains [{0}] features.", features.SelectMany(x=>x.Value).Count());
                                                              callback(features);
                                                          });

                    Log.Info("Calling query service.");
                    client.IdentifyCompressedAsync(options, mapService.Url);
                }
            }

        }
    }
}
