using System;
using System.Collections.Generic;
using System.Text;
using WindowsApplication1.MCService;
using System.Net;
using System.Drawing;
using System.Diagnostics;
using System.Windows.Forms;

namespace WindowsApplication1
{
    public class MCServerCore
    {
        private string SessionID;
        private IMapCenterServiceservice MC;
        private TSoapGetAvailableImageFormats__mcsResult gaifRes;
        private TSoapGetProjections__mcsResult gpRes;
        private TSoapGetDefaultLayers__mcsResult gdlRes;
        private TSoapRoutePlannerGetAvailableRoadTypes__mcsResult rpgartRes;
        private TSoapGetTiledMapLayers__mcsResult gtmlRes;
        private const int DefaultProjection = 6;
        private const int DefaultImageFormat = 0;

        public MCServerCore()
        {
            // utworzenie sesji
            TSoapCreateSessionID__mcsResult scsRes;

            MC = new IMapCenterServiceservice();
            MC.Credentials = new NetworkCredential("user", "user");
            scsRes = MC.CreateSessionID(); Check(scsRes.SoapResult);
            SessionID = scsRes.SessionID;

            gaifRes = MC.GetAvailableImageFormats(); Check(gaifRes.SoapResult);
            gpRes = MC.GetProjections(); Check(gpRes.SoapResult);
            gdlRes = MC.GetDefaultLayers(SessionID); Check(gdlRes.SoapResult);
            rpgartRes = MC.RoutePlannerGetAvailableRoadTypes(SessionID); Check(rpgartRes.SoapResult);
            gtmlRes = MC.GetTiledMapLayers(SessionID);
        }

        ~MCServerCore()
        {
            MC.DropSession(SessionID);
        }

        public void Check(int Result)
        {
            if (Result <= 0)
            {
                throw new System.ApplicationException(
                    string.Format("Server call failed with result: {0}", Result));
            };
        }

        public void KeepSession()
        {
            Check(MC.KeepSession(SessionID));
        }

        public Image GetMapFromPoint(TSoapTLongLatPoint point, double alt, int width, int height)
        {
            double Left, Right, Bottom, Top;
            Left = 0;
            Right = 0;
            Bottom = 0;
            Top = 0;
            return GetMapFromPoint(point, alt, width, height,
                ref Left, ref Right, ref Bottom, ref Top);
        }

        public Image GetMapFromPoint(TSoapTLongLatPoint point, double alt, int width, int height,
            ref double Left, ref double Right, ref double Bottom, ref double Top)
        {
            TSoapRenderMapOnImageByPoint__mcsResult rmoibpRes;
            TSoapTImageRenderParams RenderParams = new TSoapTImageRenderParams();

            RenderParams.Antialiasing = true;
            RenderParams.DPI = 96;

            rmoibpRes = MC.RenderMapOnImageByPoint(SessionID,
                gaifRes.ImageFormats[DefaultImageFormat], point, alt, 0, 0,
                gpRes.Projections[DefaultProjection],
                "", width, height, gdlRes.MapLayers, RenderParams); Check(rmoibpRes.SoapResult);

            Left = rmoibpRes.BitmapLeftUpCorner.Longitude;
            Right = rmoibpRes.BitmapRightUpCorner.Longitude;
            Bottom = rmoibpRes.BitmapLeftDownCorner.Latitude;
            Top = rmoibpRes.BitmapRightDownCorner.Latitude;
            return Image.FromStream(new System.IO.MemoryStream(rmoibpRes.BitmapImage));
        }

        public void SearchInitialize(bool AsciiSearch)
        {
            Check(MC.SearchInitialize(SessionID, AsciiSearch));
        }

        public void SearchGetCountryList(ref string[] Arr)
        {
            TSoapSearchGetCountryList__mcsResult ssgclRes;
            ssgclRes = MC.SearchGetCountryList(SessionID); Check(ssgclRes.SoapResult);
            Arr = ssgclRes.CountryNames;
        }

        public void SearchGetItemKindList(ref string[] Arr)
        {
            TSoapSearchGetItemKindList__mcsResult ssgiklRes;
            ssgiklRes = MC.SearchGetItemKindList(SessionID); Check(ssgiklRes.SoapResult);
            Arr = ssgiklRes.ItemKindNames;
        }

        public int SearchSelectCities(int Country, string City,
            string ZIP, string Adm1, string Adm2, string Adm3)
        {
            TSoapSearchSelectCities__mcsResult ssscRes;
            ssscRes = MC.SearchSelectCities(SessionID, Country, City, ZIP, Adm1, Adm2, Adm3);
            Check(ssscRes.SoapResult);
            return ssscRes.ResultCount;
        }

        public void SearchGetCityList(int First, int Count,
            ref string[] Cities, ref string[][] AdmNames)
        {
            TSoapSearchGetCityList__mcsResult ssgclRes;
            ssgclRes = MC.SearchGetCityList(SessionID, First, Count); Check(ssgclRes.SoapResult);
            Cities = ssgclRes.CityNames;
            AdmNames = ssgclRes.CityAdmAbbrev;
        }

        public int SearchSelectItems(int City, int Kind, string Object)
        {
            TSoapSearchSelectItems__mcsResult sssiRes;
            sssiRes = MC.SearchSelectItems(SessionID, City, Kind, Object); Check(sssiRes.SoapResult);
            return sssiRes.ResultCount;
        }

        public void SearchGetItemsList(int First, int Count, ref string[] Names)
        {
            TSoapSearchGetItemsList__mcsResult ssgilRes;
            ssgilRes = MC.SearchGetItemsList(SessionID, First, Count); Check(ssgilRes.SoapResult);
            Names = ssgilRes.ItemNames;
        }

        public void AddCityToSelection(int City, ref TSoapTLongLatPoint MidPoint)
        {
            TSoapSearchAddCityToSelection__mcsResult ssactsRes;
            ssactsRes = MC.SearchAddCityToSelection(SessionID, City); Check(ssactsRes.SoapResult);
            MidPoint = ssactsRes.MidPoint;
        }

        public void AddObjectToSelection(int Object, ref TSoapTLongLatPoint MidPoint)
        {
            TSoapSearchAddObjectToSelection__mcsResult ssaotsRes;
            ssaotsRes = MC.SearchAddObjectToSelection(SessionID, Object); Check(ssaotsRes.SoapResult);
            MidPoint = ssaotsRes.MidPoint;
        }

        public int Geocode(string Country, string County, string District, string City,
            string ZIP, string Street, string StreetNum, ref TSoapTLongLatPoint MidPoint)
        {
            TSoapTGeocodePointInfo[] Input = new TSoapTGeocodePointInfo[1];
            TSoapGeocode__mcsResult sgRes;

            Input[0] = new TSoapTGeocodePointInfo();
            Input[0].Country = Country;
            Input[0].County = County;
            Input[0].District = District;
            Input[0].City = City;
            Input[0].Zip = ZIP;
            Input[0].Street = Street;
            Input[0].StreetNumber = StreetNum;
            sgRes = MC.Geocode(SessionID, false, Input);
            if (sgRes.GeocodeLevel[0] != 0)
                MidPoint = sgRes.Positions[0];
            else
                MidPoint = null;
            return sgRes.GeocodeLevel[0];
        }

        public void LocalizeObjectAdd(int ID, string Name, bool Connected, int IconID)
        {
            TSoapTFontParameters Font = new TSoapTFontParameters();
            Font.Name = "Arial";
            Font.Size = 10;
            Check(MC.LocalizeObjectAdd(SessionID, ID, Name, true, IconID, IconID != -1, 0, 0x0000FF, 1, 5, false, Connected, Connected, Font));
        }

        public void LocalizeObjectPositionAdd(int ID, double Lon, double Lat, double NumField1, double NumField2, string StrField1)
        {
            double[] NumFields = new double[2];
            string[] StrFields = new string[1];
            NumFields[0] = NumField1;
            NumFields[1] = NumField2;
            StrFields[0] = StrField1;
            TSoapTLongLatPoint Mid = new TSoapTLongLatPoint();
            Mid.Longitude = Lon;
            Mid.Latitude = Lat;
            TSoapTFontParameters Font = new TSoapTFontParameters();
            Font.Name = "Times New Roman";
            Font.Size = 14;

            Check(MC.LocalizeObjectPositionAdd(SessionID, ID, NumFields, StrFields, Mid, 0, "", true, true, 0, false, 0, Font));
        }

        public void LocalizeNumFieldsAdd(string Name, bool ShowOnInfo)
        {
            Check(MC.LocalizeNumFieldsAdd(SessionID, Name, ShowOnInfo));
        }

        public void LocalizeStrFieldsAdd(string Name, bool ShowOnInfo)
        {
            Check(MC.LocalizeStrFieldsAdd(SessionID, Name, ShowOnInfo));
        }

        public void LocalizeIconAdd(string FileName, int ID)
        {
            System.IO.FileStream IconFile = new System.IO.FileStream(FileName, System.IO.FileMode.Open);
            byte[] IconData = new byte[IconFile.Length];

            IconFile.Read(IconData, 0, (int)IconFile.Length);

            TSoapTIconProperties IconProps = new TSoapTIconProperties();
            IconProps.IconID = ID;
            IconProps.IconFormat = gaifRes.ImageFormats[0];
            IconProps.IsTransparent = true;
            IconProps.TransparentColor = 0xFFFFFF;

            Check(MC.LocalizeIconAdd(SessionID, IconProps, IconData));
        }

        public void RoutePlannerEntryAdd(double Lon, double Lat)
        {
            TSoapRoutePlannerEntryAdd__mcsResult srpeaRes;
            TSoapTLongLatPoint Mid = new TSoapTLongLatPoint();
            Mid.Longitude = Lon;
            Mid.Latitude = Lat;
            srpeaRes = MC.RoutePlannerEntryAdd(SessionID, Mid, 0); Check(srpeaRes.SoapResult);
        }

        public void RoutePlannerCalculateRoute(int RouteType)
        {
            TSoapRoutePlannerCalculateRoute__mcsResult srpcrRes;
            srpcrRes = MC.RoutePlannerCalculateRoute(SessionID, RouteType, false, false, false, false, true);
        }

        public void RouteOptimizerOptimizeRoute(int RouteType)
        {
            TSoapRouteOptimizerOptimizeRoute__mcsResult sroorRes;
            sroorRes = MC.RouteOptimizerOptimizeRoute(SessionID, RouteType, 4, false, true, false, false, false, false, true);
            if (sroorRes.SoapResult != 1)
                MessageBox.Show("Błąd:" + sroorRes.SoapResult);
        }

        public void ConvertScreenToMap(int x1, int y1, int x2, int y2,
            double MidLon, double MidLat, double Alt, int Width, int Height,
            ref double outlon1, ref double outlat1, ref double outlon2, ref double outlat2)
        {
            TSoapTPoint[] ScreenPoints = new TSoapTPoint[2];
            ScreenPoints[0] = new TSoapTPoint();
            ScreenPoints[1] = new TSoapTPoint();
            ScreenPoints[0].X = x1;
            ScreenPoints[0].Y = y1;
            ScreenPoints[1].X = x2;
            ScreenPoints[1].Y = y2;

            TSoapTLongLatPoint Mid = new TSoapTLongLatPoint();
            Mid.Longitude = MidLon;
            Mid.Latitude = MidLat;

            TSoapConvertScreenToMap__mcsResult scstmRes;
            TSoapTImageRenderParams RenderParams = new TSoapTImageRenderParams();
            RenderParams.DPI = 96;

            scstmRes = MC.ConvertScreenToMap(SessionID, Mid, Alt, 0, 0,
                gpRes.Projections[DefaultProjection], "", Width, Height, RenderParams, ScreenPoints);
            Check(scstmRes.SoapResult);
            Debug.Assert(scstmRes.MapPoints.Length == 2);
            outlon1 = scstmRes.MapPoints[0].Longitude;
            outlat1 = scstmRes.MapPoints[0].Latitude;
            outlon2 = scstmRes.MapPoints[1].Longitude;
            outlat2 = scstmRes.MapPoints[1].Latitude;
        }

        public string DegeocodeAtPoint(double Lon, double Lat, double Alt)
        {
            TSoapTLongLatPoint Mid = new TSoapTLongLatPoint();
            Mid.Longitude = Lon;
            Mid.Latitude = Lat;

            string Res = "";
            TSoapGetDegeocodeLayers__mcsResult sgdlRes;
            sgdlRes = MC.GetDegeocodeLayers(SessionID);

            TSoapDegeocodeAtPoint__mcsResult sdapRes;
            sdapRes = MC.DegeocodeAtPoint(SessionID, Mid, Alt, 0, 0,
                gpRes.Projections[6], "", Mid, 400, 10, sgdlRes.DegeocodeLayers,
                true, false);
            Check(sdapRes.SoapResult);
            Res += "Degeocode result:\r\n";
            Res += String.Format(" Country: {0}\r\n", sdapRes.AreaName0);
            Res += String.Format(" Adm. level 2: {0}\r\n", sdapRes.AreaName1);
            Res += String.Format(" Adm. level 3: {0}\r\n", sdapRes.AreaName2);
            Res += String.Format(" Adm. level 4: {0}\r\n", sdapRes.AreaName3);
            Res += String.Format(" ZIP: {0}\r\n", sdapRes.Zip);
            foreach (TSoapTDegeocodeCityElementResult S in sdapRes.City)
                Res += String.Format(" City: {0}\r\n", S.Name);

            foreach (TSoapTDegeocodeRoadElementResult S in sdapRes.Road)
                Res += String.Format(" Road: {0} ({1,2:f}km)\r\n", S.Name, S.FoundLength / 1000);
            foreach (TSoapTDegeocodeRoadElementResult S in sdapRes.InternationalRoad)
                Res += String.Format(" International road: {0}\r\n", S.Name);
            foreach (TSoapTDegeocodeAtPointResult S in sdapRes.Natural)
                Res += String.Format(" Natural: {0} - {1}\r\n", S.Category, S.Name);
            foreach (TSoapTDegeocodeAtPointDatabaseResult S in sdapRes.DatabaseElements)
                Res += String.Format(" Database elements: {0} - {1}\r\n", S.Category, S.Name);
            foreach (TSoapTDegeocodeAtPointResult S in sdapRes.OtherMapElements)
                Res += String.Format(" Other map elements: {0} - {1}  ({2,2:f}km)\r\n",
                    S.Category, S.Name, S.FoundLength / 1000);

            return Res;
        }

        public string RoutePlannerGetRouteSummary()
        {
            TSoapRoutePlannerGetRouteSummary__mcsResult srpgrs;
            srpgrs = MC.RoutePlannerGetRouteSummary(SessionID, false);
            Check(srpgrs.SoapResult);
            string Res = "";
            Res += string.Format("Total route length: {0,2:f}km\r\n", srpgrs.TotalRouteLength / 1000);
            Res += string.Format("Total route time: {0,2:f} day(s)\r\n", srpgrs.TotalRouteTime);
            Res += string.Format("Total route cost: {0,2:f}\r\n", srpgrs.TotalRouteCost);
            Res += string.Format("Total fuel cost: {0,2:f}\r\n", srpgrs.TotalFuelCost);

            return Res;
        }

        public void RoutePlannerGetRouteItinerary(ListView List)
        {
            TSoapRoutePlannerGetRouteItinerary__mcsResult srpgriRes;
            srpgriRes = MC.RoutePlannerGetRouteItinerary(SessionID);

            foreach (TSoapTRouteItinerary R in srpgriRes.RouteItinerary)
            {
                // type name0 name1 lon lat distance time cost
                ListViewItem Item = new ListViewItem();
                Item.Text = string.Format("{0}", R.ItineraryType);
                Item.SubItems.Add(R.ItineraryName0);
                Item.SubItems.Add(R.ItineraryName1);
                Item.SubItems.Add(string.Format("{0,2:f}", R.EntryPosition.Longitude));
                Item.SubItems.Add(string.Format("{0,2:f}", R.EntryPosition.Latitude));
                Item.SubItems.Add(string.Format("{0,2:f}", R.EntryDistance / 1000));
                Item.SubItems.Add(string.Format("{0,2:f}", R.EntryTime));
                Item.SubItems.Add(string.Format("{0,2:f}", R.EntryCost));

                List.Items.Add(Item);
            }
        }

        public void RoutePlannerDriverParamsSet()
        {
            TSoapTDriverParams Params = new TSoapTDriverParams();
            Params.JourneyStartTime = 8 / 24;
            Params.DayWorkTime = 8 / 24;
            Params.ContinuousWorkTime = 5 / 24;
            Params.BreakTime = 0.5 / 24;
            Params.CostPerKilometer = 5;
            Params.CostPerHour = 10;
            Check(MC.RoutePlannerDriverParamsSet(SessionID, Params));
        }

        public void RoutePlannerVehicleParamsSet()
        {
            TSoapTVehicleParams Params = new TSoapTVehicleParams();
            Params.VehicleType = 0;
            Params.IgnoreFuel = false;
            Params.FixedCost = 10;
            Params.CostPerKilometer = 1;
            Params.CostPerHour = 1;
            Params.TollRoadPerKilometer = 2;
            Params.TankCapacity = 40;
            Params.FuelCost = 4;
            Params.RefuelTime = 0.5 / 24;
            Params.VehicleWeight = 0;
            Params.VehicleLength = 0;
            Params.VehicleHeight = 0;
            Params.VehicleWidth = 0;
            Params.VehicleCapacity = 0;
            Params.VehicleLoadCapacity = 0;
            Params.ShippingTime = 2 / 24;
            Params.BorderPassTime = 5 / 24;
            Check(MC.RoutePlannerVehicleParamsSet(SessionID, Params));
        }

        public void RoutePlannerRoadParamsSet(int RoadType, bool UseRoad, double Speed, double Combustion)
        {
            TSoapTRoadParams[] Params = new TSoapTRoadParams[1];
            Params[0] = new TSoapTRoadParams();
            Params[0].RoadType = rpgartRes.RoadTypes[RoadType];
            Params[0].Use = UseRoad;
            Params[0].Speed = Speed;
            Params[0].Combustion = Combustion;

            Check(MC.RoutePlannerRoadParamsSet(SessionID, Params));
        }

        public void RenderTiledMap(int PosX, int PosY, int Zoom, ref byte[][] ImageData)
        {
            TSoapTTiledMapParams RenderParams = new TSoapTTiledMapParams();
            RenderParams.Antialiasing = true;

            TSoapRenderTiledMap__mcsResult srtmRes;
            srtmRes = MC.RenderTiledMap(SessionID, gaifRes.ImageFormats[DefaultImageFormat],
                PosX, PosY, Zoom, RenderParams, gtmlRes.TiledMapLayers);
            Check(srtmRes.SoapResult);
            ImageData = srtmRes.BitmapImages;
        }
        
        public void XY2LL(int xtile, int xpos, int ytile, int ypos, int zoom, ref double lon, ref double lat)
        {
            double x1, y1;
            x1 = xtile * 256 + xpos;
            x1 = x1 * (2 * Math.PI) / (256 << zoom);
            lon = (x1 - Math.PI) * 180 / Math.PI;
            y1 = ytile * 256 + ypos;
            y1 = y1 * (2 * Math.PI) / (256 << zoom);
            y1 = (Math.PI - y1);
            if (y1 > 0)
                y1 = 2 * Math.Atan(Math.Exp(y1)) - Math.PI / 2;
            else
                y1 = -(2 * Math.Atan(Math.Exp(-y1)) - Math.PI / 2);
            lat = y1 * 180 / Math.PI;
        }

        public void LL2XY(double lon, double lat, int zoom, ref double x2, ref double x3, ref double y2, ref double y3)
        {
            double lon1, lat1, x1, y1;
            lon1 = lon * (Math.PI / 180);
            x1 = ((lon1 + Math.PI) / (2 * Math.PI)) * (256 << zoom);
            x2 = Math.Floor(Math.Floor(x1) / 256);
            x3 = Math.Floor(Math.Floor(x1) % 256);

            lat1 = lat * (Math.PI / 180);
            y1 = Math.Tan((Math.PI / 4) + (lat1 / 2));
            if (y1 < 0)
            {
                y1 = Math.Log(-y1);
            }
            else
            {
                y1 = Math.Log(y1);
            }
            y1 = (Math.PI - y1) * (256 << zoom) / (2 * Math.PI);
            y2 = Math.Floor(Math.Floor(y1) / 256);
            y3 = Math.Floor(Math.Floor(y1) % 256);
        }

    }
}
