using ESRI.ArcGIS.Geometry;
using KGIS.Framework.AE;
using NetTopologySuite.IO;
using System;
using System.Text;
namespace Kingo.PluginServiceInterface
{
    public static class GeometryConvertHelper
    {
        public static IGeometryFactory3 GeometryFactory3 { get; set; }
        /// 
        /// IGeometry转WKT
        /// 
        /// 
        /// 
        public static string ConvertIGeoemtryToWKT(IGeometry geometry)
        {
            return ConvertWKBToWKT(ConvertGeometryToWKB(geometry));
        }
        /// 
        /// IGeometry转WKB
        /// 
        /// 
        /// 
        public static byte[] ConvertGeometryToWKB(IGeometry geometry)
        {
            //IWkb wkb = geometry as IWkb;
            ITopologicalOperator oper = geometry as ITopologicalOperator;
            oper.Simplify();
            if (GeometryFactory3 == null)
            {
                GeometryFactory3 = new GeometryEnvironment() as IGeometryFactory3;
            }
            byte[] b = GeometryFactory3.CreateWkbVariantFromGeometry(geometry) as byte[];
            return b;
        }
        /// 
        /// WKT转IGeometry
        /// 
        /// 
        /// 
        public static IGeometry ConvertWKTToIGeometry(string wkt)
        {
            //return ConvertWKBToIGeometry(ConvertWKTToWKB(wkt));
            IGeometry geometry = null;
            try
            {
                geometry = ConvertWKBToIGeometry(ConvertWKTToWKB(wkt));
                IPolygon polygon = geometry as IPolygon;
                if (polygon == null)
                {
                    IPolyline line = geometry as IPolyline;
                    return line;
                }
                IArea area = geometry as IArea;
                if (!polygon.IsEmpty && area != null && area.Area < 0)
                {
                    polygon.ReverseOrientation();
                }
                else
                {
                    geometry = ConvertWKBToIGeometry(ConvertWKTToWKB(wkt));
                }
            }
            catch (Exception ex)
            {
                throw new Exception("WKT转IGeometry异常:" + ex.Message);
            }
            return geometry;
        }
        /// 
        /// WKB转WKT
        /// 
        /// 
        /// 
        public static string ConvertWKBToWKT(byte[] wkb)
        {
            try
            {
                WKTWriter writer = new WKTWriter();
                WKBReader reader = new WKBReader();
                return writer.Write(reader.Read(wkb));
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }
        /// 
        /// WKT转WKB
        /// 
        /// 
        /// 
        public static byte[] ConvertWKTToWKB(string wkt)
        {
            try
            {
                WKBWriter writer = new WKBWriter();
                WKTReader reader = new WKTReader();
                return writer.Write(reader.Read(wkt));
            }
            catch (Exception ex)
            {
                throw new Exception("WKT格式转WKB异常:" + ex.Message);
            }
        }
        /// 
        /// WKB转IGeometry
        /// 
        /// 
        /// 
        public static IGeometry ConvertWKBToIGeometry(byte[] wkb)
        {
            IGeometry geom;
            try
            {
                int countin = wkb.GetLength(0);
                if (GeometryFactory3 == null)
                {
                    GeometryFactory3 = new GeometryEnvironment() as IGeometryFactory3;
                }
                GeometryFactory3.CreateGeometryFromWkbVariant(wkb, out geom, out countin);
                return geom;
            }
            catch (Exception ex)
            {
                throw new Exception("WKB格式转IGeometry异常:" + ex.Message);
            }
        }
        /// 
        /// JSON图图形转IGeometry
        /// 
        /// 图形串
        /// 图形类型:点,线、面
        /// 输出图形坐标参考wkid,4490:CGCS2000球面坐标参考,默认输出CGCS2000球面坐标参考的json图形
        /// 是地理坐标参考
        /// 
        public static IGeometry ConverJsonToIGeoemtry(string jsonGeometry, esriGeometryType geometryType = esriGeometryType.esriGeometryPolygon, int wkid = 4490, bool isGeograhicCoordinateSystem = true, bool isSimplify = true)
        {
            try
            {
                using (ESRI.ArcGIS.ADF.ComReleaser comReleaser = new ESRI.ArcGIS.ADF.ComReleaser())
                {
                    ESRI.ArcGIS.esriSystem.IJSONReader reader = new ESRI.ArcGIS.esriSystem.JSONReaderClass();
                    comReleaser.ManageLifetime(reader);
                    reader.ReadFromString(jsonGeometry);
                    ESRI.ArcGIS.Geometry.JSONConverterGeometryClass jsonConverter = new JSONConverterGeometryClass();
                    comReleaser.ManageLifetime(jsonConverter);
                    IGeometry geometry = jsonConverter.ReadGeometry(reader, geometryType, false, false);
                    if (geometry == null || geometry.IsEmpty)
                    {
                        throw new Exception("转换后图形为空!");
                    }
                    //此处发现湖南抽取过来的图形Simplify之后图形变化较大,会删除节点,所以湖南暂时不执行图形简化操作
                    //四川单图斑边界套合检查返回的部分不套合图形Simplify之后会导致图形为空
                    if (!KGIS.Framework.Utils.SysConfigsOprator.GetAppsetingValueByKey("ArearName").Equals("43") && isSimplify)
                    {
                        ESRI.ArcGIS.Geometry.ITopologicalOperator topological = geometry as ESRI.ArcGIS.Geometry.ITopologicalOperator;
                        if (!topological.IsSimple)
                        {
                            topological.Simplify();
                        }
                    }
                    //IPointCollection geometryCollection = geometry as IPointCollection;
                    //int count = geometryCollection.PointCount;
                    //ESRI.ArcGIS.Geometry.ITopologicalOperator3 topological = geometry as ESRI.ArcGIS.Geometry.ITopologicalOperator3;
                    //esriNonSimpleReasonEnum reason = esriNonSimpleReasonEnum.esriNonSimpleOK;
                    //bool b = topological.get_IsSimpleEx(out reason);
                    //if (!b)
                    //{
                    //    topological.Simplify();
                    //}
                    //geometryCollection = geometry as IPointCollection;
                    //count = geometryCollection.PointCount;
                    ISpatialReference spatialReference = null;
                    if (isGeograhicCoordinateSystem)
                    {
                        spatialReference = GeoDBAPI.CreateGeographicCoordinateSystem(wkid);
                    }
                    else
                    {
                        spatialReference = GeoDBAPI.CreteSpatialReference(wkid);
                    }
                    if (wkid > 0)
                    {
                        if (geometry.SpatialReference == null)
                        {
                            geometry.SpatialReference = spatialReference;
                        }
                        else if (wkid != geometry.SpatialReference.FactoryCode)
                        {
                            geometry.Project(spatialReference);
                        }
                    }
                    return geometry;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// 
        /// JSON图图形转IGeometry
        /// 
        /// 图形串
        /// 图形类型:点,线、面
        /// 输出图形坐标参考wkid,4490:CGCS2000球面坐标参考,默认输出CGCS2000球面坐标参考的json图形
        /// 是地理坐标参考
        /// 
        public static IGeometry ConverJsonToIGeoemtry(string jsonGeometry, ISpatialReference spatialReference, esriGeometryType geometryType = esriGeometryType.esriGeometryPolygon, bool isSimple = true)
        {
            try
            {
                using (ESRI.ArcGIS.ADF.ComReleaser comReleaser = new ESRI.ArcGIS.ADF.ComReleaser())
                {
                    ESRI.ArcGIS.esriSystem.IJSONReader reader = new ESRI.ArcGIS.esriSystem.JSONReaderClass();
                    comReleaser.ManageLifetime(reader);
                    reader.ReadFromString(jsonGeometry);
                    ESRI.ArcGIS.Geometry.JSONConverterGeometryClass jsonConverter = new JSONConverterGeometryClass();
                    comReleaser.ManageLifetime(jsonConverter);
                    IGeometry geometry = jsonConverter.ReadGeometry(reader, geometryType, false, false);
                    if (geometry == null || geometry.IsEmpty)
                    {
                        throw new Exception("转换后图形为空!");
                    }
                    if (geometry.SpatialReference == null)
                    {
                        if (spatialReference != null)
                        {
                            double tolerance = (spatialReference as ISpatialReferenceTolerance).XYTolerance;
                            if (tolerance < 0.0001)
                            {
                                geometry.SpatialReference = CreateGeographicCoordinateSystem(4490, 0.0000000001);
                            }
                            else
                            {
                                geometry.SpatialReference = CreateGeographicCoordinateSystem(4490, 0.000000001);
                            }
                        }
                        else
                        {
                            geometry.SpatialReference = CreateGeographicCoordinateSystem(4490, 0.000000001);
                        }
                    }
                    if (spatialReference != null)
                    {
                        geometry.Project(spatialReference);
                    }
                    if (geometryType == esriGeometryType.esriGeometryPolygon)
                    {
                        double area = (geometry as IArea).Area;
                        if (area < 0)//面积小于0说明环的方向不对,坐标点顺序要反转一下
                        {
                            (geometry as IPolygon).ReverseOrientation();
                        }
                    }
                    if (isSimple)
                    {
                        ESRI.ArcGIS.Geometry.ITopologicalOperator topological = geometry as ESRI.ArcGIS.Geometry.ITopologicalOperator;
                        if (!topological.IsSimple)
                        {
                            topological.Simplify();
                        }
                    }
                    return geometry;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// 
        /// IGeometry转JSON字符串
        /// 
        /// 待转换图形
        /// 坐标参考wkid,4490:CGCS2000球面坐标参考,默认输出CGCS2000球面坐标参考的json图形
        /// 是地理坐标参考
        /// 
        public static string ConverIGometryToJson(IGeometry geometry, int wkid = 4490, bool isGeograhicCoordinateSystem = true)
        {
            try
            {
                if (geometry == null || geometry.IsEmpty || geometry.SpatialReference == null)
                {
                    throw new Exception("图形或坐标参考为空,无法转换!");
                }
                if (wkid > 0)
                {
                    if (isGeograhicCoordinateSystem)
                    {
                        geometry.Project(GeoDBAPI.CreateGeographicCoordinateSystem(wkid));
                    }
                    else
                    {
                        geometry.Project(GeoDBAPI.CreteSpatialReference(wkid));
                    }
                }
                using (ESRI.ArcGIS.ADF.ComReleaser comReleaser = new ESRI.ArcGIS.ADF.ComReleaser())
                {
                    ESRI.ArcGIS.Geometry.JSONConverterGeometryClass jsonConverter = new JSONConverterGeometryClass();
                    comReleaser.ManageLifetime(jsonConverter);
                    ESRI.ArcGIS.esriSystem.IJSONWriter jsonWriter = new ESRI.ArcGIS.esriSystem.JSONWriterClass();
                    jsonWriter.WriteToString();
                    comReleaser.ManageLifetime(jsonWriter);
                    jsonConverter.WriteGeometry(jsonWriter, null, geometry, false);
                    return Encoding.UTF8.GetString(jsonWriter.GetStringBuffer());
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// 
        /// IGeometry转JSON字符串:坐标参考wkid,4490
        /// 
        /// 待转换图形
        /// 
        public static string ConverIGometryToJson(IGeometry geometry, bool prj4490)
        {
            try
            {
                if (geometry == null || geometry.IsEmpty || geometry.SpatialReference == null)
                {
                    throw new Exception("图形或坐标参考为空,无法转换!");
                }
                if (prj4490)
                {
                    ISpatialReferenceTolerance spatialReferenceTolerance = geometry.SpatialReference as ISpatialReferenceTolerance;
                    if (spatialReferenceTolerance.XYTolerance < 0.0001)
                    {
                        geometry.Project(CreateGeographicCoordinateSystem(4490, 0.0000000001));
                    }
                    else
                    {
                        geometry.Project(CreateGeographicCoordinateSystem(4490, 0.000000001));
                    }
                }
                using (ESRI.ArcGIS.ADF.ComReleaser comReleaser = new ESRI.ArcGIS.ADF.ComReleaser())
                {
                    ESRI.ArcGIS.Geometry.JSONConverterGeometryClass jsonConverter = new JSONConverterGeometryClass();
                    comReleaser.ManageLifetime(jsonConverter);
                    ESRI.ArcGIS.esriSystem.IJSONWriter jsonWriter = new ESRI.ArcGIS.esriSystem.JSONWriterClass();
                    jsonWriter.WriteToString();
                    comReleaser.ManageLifetime(jsonWriter);
                    jsonConverter.WriteGeometry(jsonWriter, null, geometry, false);
                    return Encoding.UTF8.GetString(jsonWriter.GetStringBuffer());
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// 
        /// 根据坐标WKID创建地理坐标参考
        /// 
        /// WKID
        /// 容差
        /// 
        public static ISpatialReference CreateGeographicCoordinateSystem(int WKID, double pTolerance)
        {
            ISpatialReference pSpatialReference = null;
            ISpatialReferenceFactory2 pSpatialRefFac = null;
            try
            {
                pSpatialRefFac = new SpatialReferenceEnvironmentClass();
                pSpatialReference = pSpatialRefFac.CreateGeographicCoordinateSystem(WKID);
                (pSpatialReference as ISpatialReferenceResolution).set_XYResolution(true, pTolerance / 10);
                (pSpatialReference as ISpatialReferenceResolution).set_ZResolution(true, pTolerance / 10);
                (pSpatialReference as ISpatialReferenceResolution).MResolution = (pTolerance / 10);
                (pSpatialReference as ISpatialReferenceTolerance).XYTolerance = pTolerance;
                (pSpatialReference as ISpatialReferenceTolerance).ZTolerance = pTolerance;
                (pSpatialReference as ISpatialReferenceTolerance).MTolerance = pTolerance;
                return pSpatialReference;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (pSpatialRefFac != null)
                {
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(pSpatialRefFac);
                }
            }
        }
    }
}