using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;

namespace IronIntel.Contractor.Shape
{
    public static class ShapeFileParser
    {
        private static void ParsePoints(BinaryReader binaryReader, MapPoints points)
        {
            while (binaryReader.PeekChar() != -1)
            {
                binaryReader.ReadUInt32();
                binaryReader.ReadInt32();
                int shapeType = binaryReader.ReadInt32();

                MapPoint p = new MapPoint();
                p.Longitude = binaryReader.ReadDouble();
                p.Latitude = binaryReader.ReadDouble();
                points.Points.Add(p);

                if (shapeType == 11)//PointZ
                {
                    binaryReader.ReadDouble();//Z
                    binaryReader.ReadDouble();//M
                }
                else if (shapeType == 21)//PointM
                {
                    binaryReader.ReadDouble();//M
                }
            }
        }

        private static void ParsePolylines(BinaryReader binaryReader, List<Polyline> polylines)
        {
            while (binaryReader.PeekChar() != -1)
            {
                Polyline polyling = new Polyline();
                polylines.Add(polyling);

                binaryReader.ReadUInt32();
                binaryReader.ReadInt32();
                int shapeType = binaryReader.ReadInt32();

                polyling.TopLeft = new MapPoint();
                polyling.BottomRight = new MapPoint();
                polyling.TopLeft.Longitude = binaryReader.ReadDouble();
                polyling.TopLeft.Latitude = binaryReader.ReadDouble();
                polyling.BottomRight.Longitude = binaryReader.ReadDouble();
                polyling.BottomRight.Latitude = binaryReader.ReadDouble();

                List<int> parts = new List<int>();//记录每条线的起始点索引
                int partCount = binaryReader.ReadInt32();
                int pointCount = binaryReader.ReadInt32();
                for (int i = 0; i < partCount; i++)
                {
                    int part = new int();
                    part = binaryReader.ReadInt32();
                    parts.Add(part);
                }

                MapPoints ring = null;
                int partIndex = 0;
                for (int j = 0; j < pointCount; j++)
                {
                    if (partIndex < parts.Count && parts[partIndex] == j)
                    {
                        ring = new MapPoints();
                        polyling.Parts.Add(ring);
                    }
                    MapPoint mp = new MapPoint();
                    mp.Longitude = binaryReader.ReadDouble();
                    mp.Latitude = binaryReader.ReadDouble();
                    ring.Points.Add(mp);
                }

                if (shapeType == 13)//PolylineZ
                {
                    binaryReader.ReadDouble();//Zmin
                    binaryReader.ReadDouble();//Zmax
                    for (int j = 0; j < pointCount; j++)
                    {
                        binaryReader.ReadDouble();//Zarray
                    }

                    binaryReader.ReadDouble();//Mmin
                    binaryReader.ReadDouble();//Mmax
                    for (int j = 0; j < pointCount; j++)
                    {
                        binaryReader.ReadDouble();//Marray
                    }
                }
                else if (shapeType == 23)//PolylineM
                {
                    binaryReader.ReadDouble();//Mmin
                    binaryReader.ReadDouble();//Mmax
                    for (int j = 0; j < pointCount; j++)
                    {
                        binaryReader.ReadDouble();//Marray
                    }
                }
            }
        }

        private static void ParsePolygons(BinaryReader binaryReader, List<Polygon> ls)
        {
            while (binaryReader.PeekChar() != -1)
            {
                binaryReader.ReadUInt32();
                binaryReader.ReadInt32();
                int shapeType = binaryReader.ReadInt32();

                Polygon p = new Polygon();
                p.TopLeft = new MapPoint();
                p.BottomRight = new MapPoint();
                p.TopLeft.Longitude = binaryReader.ReadDouble();
                p.TopLeft.Latitude = binaryReader.ReadDouble();
                p.BottomRight.Longitude = binaryReader.ReadDouble();
                p.BottomRight.Latitude = binaryReader.ReadDouble();

                List<int> parts = new List<int>();//记录每个区域的起始点索引
                int partCount = binaryReader.ReadInt32();
                int pointCount = binaryReader.ReadInt32();
                for (int j = 0; j < partCount; j++)
                {
                    int part = binaryReader.ReadInt32();
                    parts.Add(part);
                }

                MapPoints ring = null;
                int partIndex = 0;
                for (int j = 0; j < pointCount; j++)
                {
                    if (partIndex < parts.Count && parts[partIndex] == j)
                    {
                        ring = new MapPoints();
                        p.Rings.Add(ring);
                        partIndex++;
                    }
                    MapPoint mp = new MapPoint();
                    mp.Longitude = binaryReader.ReadDouble();
                    mp.Latitude = binaryReader.ReadDouble();
                    ring.Points.Add(mp);
                }

                ls.Add(p);

                if (shapeType == 15)//PolygonZ
                {
                    binaryReader.ReadDouble();//Zmin
                    binaryReader.ReadDouble();//Zmax
                    for (int j = 0; j < pointCount; j++)
                    {
                        binaryReader.ReadDouble();//Zarray
                    }

                    binaryReader.ReadDouble();//Mmin
                    binaryReader.ReadDouble();//Mmax
                    for (int j = 0; j < pointCount; j++)
                    {
                        binaryReader.ReadDouble();//Marray
                    }
                }
                else if (shapeType == 25)//PolygonM
                {
                    binaryReader.ReadDouble();//Mmin
                    binaryReader.ReadDouble();//Mmax
                    for (int j = 0; j < pointCount; j++)
                    {
                        binaryReader.ReadDouble();//Marray
                    }
                }
            }
        }

        /// <summary>
        /// 解析.shp文件
        /// </summary>
        /// <param name="fileName"></param>
        public static void ParseFromShapeFile(string fileName, Shape shape)
        {
            using (FileStream fileStream = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                ParseFromShapeFile(fileStream, shape);
            }
        }

        /// <summary>
        ///  解析.shp文件
        /// </summary>
        /// <param name="buffer">.shp文件数据</param>
        /// <param name="shape"></param>
        public static void ParseFromShapeFile(byte[] buffer, Shape shape)
        {
            using (MemoryStream ms = new MemoryStream(buffer, false))
            {
                ParseFromShapeFile(ms, shape);
            }
        }

        /// <summary>
        /// 解析.shp文件
        /// </summary>
        /// <param name="fs">装载.shp文件数据的流</param>
        public static void ParseFromShapeFile(Stream fs, Shape shape)
        {
            fs.Seek(0, SeekOrigin.Begin);
            using (BinaryReader binaryReader = new BinaryReader(fs))
            {
                binaryReader.ReadBytes(24);

                int FileLength = binaryReader.ReadInt32();//<0代表数据长度未知
                int FileBanben = binaryReader.ReadInt32();
                int ShapeType = binaryReader.ReadInt32();

                double xmin = binaryReader.ReadDouble();
                double ymax = -1 * binaryReader.ReadDouble();
                double xmax = binaryReader.ReadDouble();
                double ymin = -1 * binaryReader.ReadDouble();
                double width = xmax - xmin;
                double height = ymax - ymin;

                binaryReader.ReadBytes(32);

                switch (ShapeType)
                {
                    case 1://Point
                    case 11://PointZ
                    case 21://PointM
                        MapPoints points = new MapPoints();
                        shape.Points.Add(points);
                        ParsePoints(binaryReader, points);
                        break;
                    case 3://PolyLine
                    case 13://PolyLineZ
                    case 23://PolyLineM
                        ParsePolylines(binaryReader, shape.Polylines);
                        break;
                    case 5://Polygon
                    case 15://PolygonZ
                    case 25://PolygonM
                        ParsePolygons(binaryReader, shape.Polygons);
                        break;
                }
            }
        }

        /// <summary>
        /// 从zip文件当中解析.shp
        /// </summary>
        /// <param name="stream">装载.zip文件内容的流</param>
        /// <param name="shape"></param>
        public static void ParseFromZipFile(Stream stream, Shape shape)
        {
            const string EXT = ".shp";
            //using (ZipInputStream s = new ZipInputStream(stream))
            //{
            //    ZipEntry zipentry = s.GetNextEntry();
            //    while (zipentry != null)
            //    {
            //        if (zipentry.IsDirectory)
            //        {
            //            zipentry = s.GetNextEntry();
            //            continue;
            //        }
            //        string ext = Path.GetExtension(zipentry.FileName);
            //        if (string.Compare(ext, EXT, true) == 0)
            //        {
            //            Stream shpStream = new MemoryStream();
            //            int size = 0;
            //            byte[] data = new byte[2048];
            //            while (true)
            //            {
            //                size = s.Read(data, 0, data.Length);
            //                if (size > 0)
            //                {
            //                    shpStream.Write(data, 0, size);
            //                }
            //                else
            //                {
            //                    break;
            //                }
            //            }
            //            ParseFromShapeFile(shpStream, shape);
            //        }
            //        zipentry = s.GetNextEntry();
            //    }//while
            //}
        }

        /// <summary>
        /// 从.zip文件当中解析.shp
        /// </summary>
        /// <param name="buffer">.zip文件数据</param>
        /// <param name="shape"></param>
        public static void ParseFromZipFile(byte[] buffer, Shape shape)
        {
            using (MemoryStream ms = new MemoryStream(buffer, false))
            {
                ParseFromZipFile(ms, shape);
            }
        }

        /// <summary>
        /// 从.zip文件当中解析.shp
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="shape"></param>
        public static void ParseFromZipFile(string filename, Shape shape)
        {
            using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                ParseFromZipFile(fs, shape);
            }
        }
    }

}