using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Txgy.EWS.Client.FocalMechanism.Model;
using Txgy.Microseismic.BaseLib.Models;
using FMStation = Txgy.EWS.Client.FocalMechanism.Model.FMStation;

namespace Txgy.EWS.Client.FocalMechanism.Core
{
    /// <summary>
    /// 倾滑
    /// </summary>
    public class CrossLineFactory : Factory
    {

        public CrossLine[] cross { get; set; }

        public CrossLineFactory(Model.FmGrid g) : base(g)
        {
            cross = new CrossLine[90];
        }
        /// <summary>
        /// 判断是否为倾滑
        /// </summary>
        /// <param name="map"></param>
        /// <returns></returns>
        public ComputationResult generateResult(FMMap map)
        {
            ComputationResult r = null;
            CrossLine cl = computeCross(map);
            if (cl != null)
            {
                r = new ComputationResult();
                r.graph = cl;
                r.Direction = cl.Lines[0].angle;
                r.FocalType = FocalMechanismType.dipSlip;
                map.T = FocalMechanismType.dipSlip;
            }
            return r;
        }

        private CrossLine computeCross(FMMap map)
        {
            for (int i = 0; i < 90; i++)
            {
                List<double> l = new List<double>();
                for (int j = 0; j < map.posStation.Count; j++)
                {
                    int fj = grid.StationList.ToList<FMStation>().FindIndex(fi => fi.Name == map.posStation[j]);
                    if (fj == -1) continue;
                     l.Add(0 - this.grid.distance[i + 90, fj]);
                }
                for (int j = 0; j < map.negStation.Count; j++)
                {
                    int fj = grid.StationList.ToList<FMStation>().FindIndex(fi => fi.Name == map.negStation[j]);
                    if (fj == -1) continue;
                    l.Add(0 - this.grid.distance[i + 90, fj]);
                }
                l.Sort();

                CrossLine c = null;
                for (int j = 0; j < l.Count - 1; j++)
                {
                    c = getCross((l[j] + l[j + 1]) / 2, i, map);
                    if (c != null)
                    {
                        c.horDiff = l[j+1] - l[j];
                        //Select the crossline with the biggest min diff
                        if (cross[i]==null || Math.Min(c.horDiff, c.verDiff) > Math.Min(cross[i].horDiff, cross[i].verDiff))
                        {
                            cross[i] = c;
                        }
                    }
                }
            }
            int firstAngle = -1, maxAngle = -1, tempA = 0;
            for (int i = 1; i < 180; i++)
            {
                if (cross[i % 90] != null && cross[(i - 1) % 90] == null)
                {
                    firstAngle = i;
                }
                if (cross[i % 90] == null && cross[(i - 1) % 90] != null)
                {
                    if (firstAngle != -1)
                    {
                        int diff = i - 1 - firstAngle;
                        if (diff > maxAngle)
                        {
                            tempA = firstAngle + diff / 2;
                            maxAngle = diff;
                        }
                        firstAngle = -1;
                    }
                }
            }
            if (tempA >= 90) tempA -= 90;
            if (cross[tempA] == null) return null;
            return cross[tempA];
        }

        private CrossLine getCross(double x, int angle, FMMap map)
        {
            if(angle>=90) return null;

            double posleftMax = int.MinValue;
            double posrightMax = int.MinValue;
            double posleftMin = int.MaxValue;
            double posrightMin = int.MaxValue;
            double negleftMax = int.MinValue;
            double negrightMax = int.MinValue;
            double negleftMin = int.MaxValue;
            double negrightMin = int.MaxValue;

            for (int i = 0; i < map.posStation.Count; i++)
            {
                int fj = grid.StationList.ToList<FMStation>().FindIndex(fi => fi.Name == map.posStation[i]);
                if (fj == -1) continue;
                double xpos = 0 - this.grid.distance[angle + 90, fj];
                double ypos = this.grid.distance[angle, fj];
                if (xpos <= x)
                {
                    posleftMax = Math.Max(posleftMax, ypos);
                    posleftMin = Math.Min(posleftMin, ypos);
                }
                else
                {
                    posrightMax = Math.Max(posrightMax, ypos);
                    posrightMin = Math.Min(posrightMin, ypos);
                }
            }

            for (int i = 0; i < map.negStation.Count; i++)
            {
                int fj = grid.StationList.ToList<FMStation>().FindIndex(fi => fi.Name == map.negStation[i]);
                if (fj == -1) continue;
                double xpos = 0 - this.grid.distance[angle + 90, fj];
                double ypos = this.grid.distance[angle, fj];
                if (xpos <= x)
                {
                    negleftMax = Math.Max(negleftMax, ypos);
                    negleftMin = Math.Min(negleftMin, ypos);
                }
                else
                {
                    negrightMax = Math.Max(negrightMax, ypos);
                    negrightMin = Math.Min(negrightMin, ypos);
                }
            }
            //one of the area is empty. It can be discript as polygon
            if (posleftMax < posleftMin || negleftMax < negleftMin || posrightMax < posrightMin || negrightMax < negrightMin) return null;

            if (posleftMax <= posrightMin && posleftMax <= negleftMin && negrightMax <= posrightMin && negrightMax <= negleftMin)
            {
                double up = Math.Min(posrightMin, negleftMin);
                double down = Math.Max(posleftMax, negrightMax);
                var c = new CrossLine(x, (up + down) / 2, angle);
                c.verDiff = up - down;
                return c;
            }
            if (negleftMax <= negrightMin && negleftMax <= posleftMin && posrightMax <= negrightMin && posrightMax <= posleftMin)
            {
                double up = Math.Min(negrightMin, posleftMin);
                double down = Math.Max(negleftMax, posrightMax);
                var c = new CrossLine(x, (up + down) / 2, angle);
                c.verDiff = up - down;
                return c;
            }
            return null;
        }
    }
}
