﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Globalization;
using System.IO;
using System.Net;
using System.Net.NetworkInformation;
using System.Threading;
using System.Windows.Forms;
using System.Xml;
using Demo.WindowsForms.CustomMarkers;
using GMap.NET;
using GMap.NET.MapProviders;
using GMap.NET.WindowsForms;
using GMap.NET.WindowsForms.Markers;
using GMap.NET.WindowsForms.ToolTips;
using System.IO.Ports;
using System.Data;
using System.Text;

namespace Demo.WindowsForms
{
    public partial class MainForm : Form
    {
        // layers
        readonly GMapOverlay top = new GMapOverlay();
        internal readonly GMapOverlay objects = new GMapOverlay("objects");
        internal readonly GMapOverlay routes = new GMapOverlay("routes");

        // current marker
        GMarkerGoogle currentMarker;

        // etc
        readonly Random rnd = new Random();
        readonly DescendingComparer ComparerIpStatus = new DescendingComparer();
        GMapMarkerRect CurentRectMarker = null;
        string mobileGpsLog = string.Empty;
        bool isMouseDown = false;
        PointLatLng start;
        PointLatLng end;
        TimeSpan unixTime;
        GMapRoute currentRoute = null;
        bool UserAcceptedLicenseOnce = false;

        public MainForm()
        {
            InitializeComponent();
            unixTime = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0));

            if (!DesignMode)
            {
                // add your custom map db provider
                //GMap.NET.CacheProviders.MySQLPureImageCache ch = new GMap.NET.CacheProviders.MySQLPureImageCache();
                //ch.ConnectionString = @"server=sql2008;User Id=trolis;Persist Security Info=True;database=gmapnetcache;password=trolis;";
                //MainMap.Manager.SecondaryCache = ch;

                // set your proxy here if need
                //GMapProvider.WebProxy = new WebProxy("10.2.0.100", 8080);
                //GMapProvider.WebProxy.Credentials = new NetworkCredential("ogrenci@bilgeadam.com", "bilgeada");

                // set cache mode only if no internet avaible
                if (!Stuff.PingNetwork("pingtest.net"))
                {
                    MainMap.Manager.Mode = AccessMode.CacheOnly;
                    MessageBox.Show("No internet connection available, going to CacheOnly mode.", "GMap.NET - Demo.WindowsForms", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }

                // config map - MDKEdit - init values ??
                MainMap.MapProvider = GMapProviders.OpenStreetMap;
                MainMap.Position = new PointLatLng(39.751248, -83.809848);
                MainMap.MinZoom = 0;
                MainMap.MaxZoom = 24;
                MainMap.Zoom = 15;

                //MainMap.ScaleMode = ScaleModes.Fractional;

                /// map events
                MainMap.OnTileLoadStart += new TileLoadStart(MainMap_OnTileLoadStart);
                MainMap.OnTileLoadComplete += new TileLoadComplete(MainMap_OnTileLoadComplete);

                MainMap.OnMapZoomChanged += new MapZoomChanged(MainMap_OnMapZoomChanged);
                MainMap.OnMapTypeChanged += new MapTypeChanged(MainMap_OnMapTypeChanged);

                MainMap.OnMarkerClick += new MarkerClick(MainMap_OnMarkerClick);
                MainMap.OnMarkerEnter += new MarkerEnter(MainMap_OnMarkerEnter);
                MainMap.OnMarkerLeave += new MarkerLeave(MainMap_OnMarkerLeave);

                MainMap.OnRouteEnter += new RouteEnter(MainMap_OnRouteEnter);
                MainMap.OnRouteLeave += new RouteLeave(MainMap_OnRouteLeave);

                MainMap.Manager.OnTileCacheComplete += new TileCacheComplete(OnTileCacheComplete);
                MainMap.Manager.OnTileCacheStart += new TileCacheStart(OnTileCacheStart);
                MainMap.Manager.OnTileCacheProgress += new TileCacheProgress(OnTileCacheProgress);
                

                MainMap.MouseMove += new MouseEventHandler(MainMap_MouseMove);
                MainMap.MouseDown += new MouseEventHandler(MainMap_MouseDown);
                MainMap.MouseUp += new MouseEventHandler(MainMap_MouseUp);

                // get map types
#if !MONO   // mono doesn't handle it, so we 'lost' provider list ;]
                comboBoxMapType.ValueMember = "Name";
                comboBoxMapType.DataSource = GMapProviders.List;
                comboBoxMapType.SelectedItem = MainMap.MapProvider;
#endif
                // acccess mode
                comboBoxMode.DataSource = Enum.GetValues(typeof(AccessMode));
                comboBoxMode.SelectedItem = MainMap.Manager.Mode;

                // get position
                textBoxLat.Text = MainMap.Position.Lat.ToString(CultureInfo.InvariantCulture);
                textBoxLng.Text = MainMap.Position.Lng.ToString(CultureInfo.InvariantCulture);

                // get cache modes
                checkBoxUseRouteCache.Checked = MainMap.Manager.UseRouteCache;

                // get zoom  
                trackBarZoomLevel.Minimum = MainMap.MinZoom * 100;
                trackBarZoomLevel.Maximum = MainMap.MaxZoom * 100;
                trackBarZoomLevel.TickFrequency = 100;

#if DEBUG
                xboxGrid.Checked = true;
#endif

                ToolStripManager.Renderer = new BSE.Windows.Forms.Office2007Renderer();

                /// add custom layers  
                MainMap.Overlays.Add(routes);
                MainMap.Overlays.Add(objects);
                MainMap.Overlays.Add(top);

                routes.Routes.CollectionChanged += new GMap.NET.ObjectModel.NotifyCollectionChangedEventHandler(Routes_CollectionChanged);
                objects.Markers.CollectionChanged += new GMap.NET.ObjectModel.NotifyCollectionChangedEventHandler(Markers_CollectionChanged);


                // set current marker
                currentMarker = new GMarkerGoogle(MainMap.Position, GMarkerGoogleType.arrow);
                currentMarker.IsHitTestVisible = false;
                currentMarker.ToolTipText = "Current Marker";
                top.Markers.Add(currentMarker);

                if (objects.Markers.Count > 0)
                {
                    MainMap.ZoomAndCenterMarkers(null);
                }

                try
                {
                    GMapOverlay overlay = DeepClone<GMapOverlay>(objects);
                    Debug.WriteLine("ISerializable status for markers: OK");

                    GMapOverlay overlay3 = DeepClone<GMapOverlay>(routes);
                    Debug.WriteLine("ISerializable status for routes: OK");
                }
                catch (Exception ex)
                {
                    Debug.WriteLine("ISerializable failure: " + ex.Message);

#if DEBUG
                    if (Debugger.IsAttached)
                    {
                        Debugger.Break();
                    }
#endif
                }
            }
        }

        //runs during init - MDKfunctional
        public T DeepClone<T>(T obj)
        {
            using (var ms = new System.IO.MemoryStream())
            {
                var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

                formatter.Serialize(ms, obj);

                ms.Position = 0;

                return (T)formatter.Deserialize(ms);
            }
        }

        // runs on form load  - MDKfunctional
        private void MainForm_Load(object sender, EventArgs e)
        {
            trackBarZoomLevel.Value = (int)MainMap.Zoom * 100;
            Activate();
            TopMost = true;
            TopMost = false;

            PrepareGraphs();
        }

        //updates the count of markers - MDKfunctional
        void Markers_CollectionChanged(object sender, GMap.NET.ObjectModel.NotifyCollectionChangedEventArgs e)
        {
            //textBoxMarkerCount.Text = objects.Markers.Count.ToString();
        }

        //updates the count of routes - MDKfunctional
        void Routes_CollectionChanged(object sender, GMap.NET.ObjectModel.NotifyCollectionChangedEventArgs e)
        {
            textBoxrouteCount.Text = routes.Routes.Count.ToString();
        }

        #region -- map events --

        // details unknown- MDKfunctional
        void OnTileCacheComplete()
        {
            Debug.WriteLine("OnTileCacheComplete");
            long size = 0;
            int db = 0;
            try
            {
                DirectoryInfo di = new DirectoryInfo(MainMap.CacheLocation);
                var dbs = di.GetFiles("*.gmdb", SearchOption.AllDirectories);
                foreach (var d in dbs)
                {
                    size += d.Length;
                    db++;
                }
            }
            catch
            {
            }

            if (!IsDisposed)
            {
                MethodInvoker m = delegate
                {
                    textBoxCacheSize.Text = string.Format(CultureInfo.InvariantCulture, "{0} db in {1:00} MB", db, size / (1024.0 * 1024.0));
                    textBoxCacheStatus.Text = "all tiles saved!";
                };
                Invoke(m);
            }
        }

        //details unknown - MDKfunctional
        void OnTileCacheStart()
        {
            Debug.WriteLine("OnTileCacheStart");

            if (!IsDisposed)
            {
                MethodInvoker m = delegate
                {
                    textBoxCacheStatus.Text = "saving tiles...";
                };
                // MDKEdit
                //Invoke(m);
            }
        }

        //details unknown - MDKfunctional
        void OnTileCacheProgress(int left)
        {
            if (!IsDisposed)
            {
                MethodInvoker m = delegate
                {
                    textBoxCacheStatus.Text = left + " tile to save...";
                };
                Invoke(m);
            }
        }

        //runs when cursor leaves a marker - MDKfunctional
        void MainMap_OnMarkerLeave(GMapMarker item)
        {
            if (item is GMapMarkerRect)
            {
                CurentRectMarker = null;

                GMapMarkerRect rc = item as GMapMarkerRect;
                rc.Pen.Color = Color.Blue;

                Debug.WriteLine("OnMarkerLeave: " + item.Position);
            }
        }

        //runs when cursor enters a marker - MDKfunctional
        void MainMap_OnMarkerEnter(GMapMarker item)
        {
            if (item is GMapMarkerRect)
            {
                GMapMarkerRect rc = item as GMapMarkerRect;
                rc.Pen.Color = Color.Red;

                CurentRectMarker = rc;

                Debug.WriteLine("OnMarkerEnter: " + item.Position);
            }
        }

        //runs when cursor leaves a route - MDKfunctional
        void MainMap_OnRouteLeave(GMapRoute item)
        {
            currentRoute = null;
            item.Stroke.Color = Color.MidnightBlue;
            Debug.WriteLine("OnRouteLeave: " + item.Name);
        }

        //runs when cursor enters a route - MDKfunctional
        void MainMap_OnRouteEnter(GMapRoute item)
        {
            currentRoute = item;
            item.Stroke.Color = Color.Red;
            Debug.WriteLine("OnRouteEnter: " + item.Name);
        }

        // - MDKfunctional
        void MainMap_OnMapTypeChanged(GMapProvider type)
        {
            comboBoxMapType.SelectedItem = type;

            trackBarZoomLevel.Minimum = MainMap.MinZoom * 100;
            trackBarZoomLevel.Maximum = MainMap.MaxZoom * 100;
        }

        //updates current marker coordinate dislpay - MDKfunctional
        void MainMap_MouseUp(object sender, MouseEventArgs e)
        {
            // MDKAdd
            textBoxLatCurrent.Text = currentMarker.Position.Lat.ToString();
            textBoxLngCurrent.Text = currentMarker.Position.Lng.ToString();
            if (e.Button == MouseButtons.Left)
            {
                isMouseDown = false;
            }
        }

        // - MDKfunctional
        void MainMap_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                isMouseDown = true;

                if (currentMarker.IsVisible)
                {
                    currentMarker.Position = MainMap.FromLocalToLatLng(e.X, e.Y);
                    // MDKAdd
                    textBoxLatCurrent.Text = currentMarker.Position.Lat.ToString();
                    textBoxLngCurrent.Text = currentMarker.Position.Lng.ToString();

                    var px = MainMap.MapProvider.Projection.FromLatLngToPixel(currentMarker.Position.Lat, currentMarker.Position.Lng, (int)MainMap.Zoom);
                    var tile = MainMap.MapProvider.Projection.FromPixelToTileXY(px);

                    Debug.WriteLine("MouseDown: geo: " + currentMarker.Position + " | px: " + px + " | tile: " + tile);
                }
            }
        }

        // move current marker with left holding - MDKfunctional
        void MainMap_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left && isMouseDown)
            {
                if (CurentRectMarker == null)
                {
                    if (currentMarker.IsVisible)
                    {
                        // MDKAdd
                        textBoxLatCurrent.Text = currentMarker.Position.Lat.ToString();
                        textBoxLngCurrent.Text = currentMarker.Position.Lng.ToString();

                        currentMarker.Position = MainMap.FromLocalToLatLng(e.X, e.Y);
                    }
                }
                else // move rect marker
                {
                    PointLatLng pnew = MainMap.FromLocalToLatLng(e.X, e.Y);

                    int? pIndex = (int?)CurentRectMarker.Tag;
                    if (pIndex.HasValue)
                    {
                        //if (pIndex < polygon.Points.Count)
                        //{
                        //    polygon.Points[pIndex.Value] = pnew;
                        //    MainMap.UpdatePolygonLocalPosition(polygon);
                        //}
                    }

                    if (currentMarker.IsVisible)
                    {
                        currentMarker.Position = pnew;
                        // MDKAdd
                        textBoxLatCurrent.Text = currentMarker.Position.Lat.ToString();
                        textBoxLngCurrent.Text = currentMarker.Position.Lng.ToString();
                    }
                    CurentRectMarker.Position = pnew;

                    if (CurentRectMarker.InnerMarker != null)
                    {
                        CurentRectMarker.InnerMarker.Position = pnew;
                    }
                }

                MainMap.Refresh(); // force instant invalidation
                // MDKAdd
                textBoxLatCurrent.Refresh();
                textBoxLngCurrent.Refresh();
            }
        }

        // MapZoomChanged - MDKfunctional
        void MainMap_OnMapZoomChanged()
        {
            trackBarZoomLevel.Value = (int)(MainMap.Zoom * 100.0);
            textBoxZoomCurrent.Text = MainMap.Zoom.ToString();
        }

        // click on a marker - MDKfunctional
        void MainMap_OnMarkerClick(GMapMarker item, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                if (item is GMapMarkerRect)
                {
                    GeoCoderStatusCode status;
                    var pos = GMapProviders.GoogleMap.GetPlacemark(item.Position, out status);
                    if (status == GeoCoderStatusCode.G_GEO_SUCCESS && pos != null)
                    {
                        GMapMarkerRect v = item as GMapMarkerRect;
                        {
                            v.ToolTipText = pos.Value.Address;
                        }
                        MainMap.Invalidate(false);
                    }
                }
                else
                {
                    //if (item.Tag != null)
                    //{
                    //    if (currentTransport != null)
                    //    {
                    //        currentTransport.ToolTipMode = MarkerTooltipMode.OnMouseOver;
                    //        currentTransport = null;
                    //    }
                    //    currentTransport = item;
                    //    currentTransport.ToolTipMode = MarkerTooltipMode.OnMouseOver;
                    //}
                }
            }
        }

        // loader start loading tiles - MDKfunctional
        void MainMap_OnTileLoadStart()
        {
            MethodInvoker m = delegate()
            {
                panelMenu.Text = "Menu: loading tiles...";
            };
            try
            {
                BeginInvoke(m);
            }
            catch
            {
            }
        }

        // loader end loading tiles  - MDKfunctional
        void MainMap_OnTileLoadComplete(long ElapsedMilliseconds)
        {
            MainMap.ElapsedMilliseconds = ElapsedMilliseconds;

            MethodInvoker m = delegate()
            {
                panelMenu.Text = "Menu, last load in " + MainMap.ElapsedMilliseconds + "ms";

                textBoxMemory.Text = string.Format(CultureInfo.InvariantCulture, "{0:0.00} MB of {1:0.00} MB", MainMap.Manager.MemoryCache.Size, MainMap.Manager.MemoryCache.Capacity);
            };
            try
            {
                BeginInvoke(m);
            }
            catch
            {
            }
        }

        #endregion

        #region -- menu panels expanders --
        // - MDKfunctional
        private void xPanderPanel1_Click(object sender, EventArgs e)
        {
            xPanderPanelList1.Expand(xPanderPanelMain);
        }

        // - MDKfunctional
        private void xPanderPanelCache_Click(object sender, EventArgs e)
        {
            xPanderPanelList1.Expand(xPanderPanelCache);
        }

        // - MDKfunctional
        private void xPanderPanelInfo_Click(object sender, EventArgs e)
        {
            xPanderPanelList1.Expand(xPanderPanelInfo);
        }
        #endregion

        #region -- ui events --

        // change map type - MDKfunctional
        private void comboBoxMapType_DropDownClosed(object sender, EventArgs e)
        {
            if (!UserAcceptedLicenseOnce)
            {
                if (File.Exists(AppDomain.CurrentDomain.BaseDirectory + Path.DirectorySeparatorChar + "License.txt"))
                {
                    string ctn = File.ReadAllText(AppDomain.CurrentDomain.BaseDirectory + Path.DirectorySeparatorChar + "License.txt");
                    int li = ctn.IndexOf("License");
                    string txt = ctn.Substring(li);

                    var d = new Demo.WindowsForms.Forms.Message();
                    d.richTextBox1.Text = txt;

                    if (DialogResult.Yes == d.ShowDialog())
                    {
                        UserAcceptedLicenseOnce = true;
                        this.Text += " - license accepted by " + Environment.UserName + " at " + DateTime.Now;
                    }
                }
                else
                {
                    // user deleted License.txt ;}
                    UserAcceptedLicenseOnce = true;
                }
            }

            if (UserAcceptedLicenseOnce)
            {
                MainMap.MapProvider = comboBoxMapType.SelectedItem as GMapProvider;
            }
            else
            {
                MainMap.MapProvider = GMapProviders.OpenStreetMap;
                comboBoxMapType.SelectedItem = MainMap.MapProvider;
            }
        }

        // change mdoe - MDKfunctional
        private void comboBoxMode_DropDownClosed(object sender, EventArgs e)
        {
            MainMap.Manager.Mode = (AccessMode)comboBoxMode.SelectedValue;
            MainMap.ReloadMap();
        }

        // zoom - MDKfunctional
        private void trackBar1_ValueChanged(object sender, EventArgs e)
        {
            MainMap.Zoom = trackBarZoomLevel.Value / 100.0;
        }

        // go to coordinates- MDKfunctional
        private void btnGoToCoords_Click(object sender, EventArgs e)
        {
            try
            {
                double lat = double.Parse(textBoxLat.Text, CultureInfo.InvariantCulture);
                double lng = double.Parse(textBoxLng.Text, CultureInfo.InvariantCulture);

                MainMap.Position = new PointLatLng(lat, lng);
            }
            catch (Exception ex)
            {
                MessageBox.Show("incorrect coordinate format: " + ex.Message);
            }
        }

        // reload map - MDKfunctional
        private void btnReload_Click(object sender, EventArgs e)
        {
            MainMap.ReloadMap();
        }

        // cache config - MDKfunctional
        private void checkBoxUseCache_CheckedChanged(object sender, EventArgs e)
        {
            MainMap.Manager.UseRouteCache = checkBoxUseRouteCache.Checked;
            MainMap.Manager.UseGeocoderCache = checkBoxUseRouteCache.Checked;
            MainMap.Manager.UsePlacemarkCache = checkBoxUseRouteCache.Checked;
            MainMap.Manager.UseDirectionsCache = checkBoxUseRouteCache.Checked;
        }

        // set route start  - MDKfunctional
        bool hasStartMarker = false;
        private void buttonSetStart_Click(object sender, EventArgs e)
        {
            start = currentMarker.Position;
            // - MDKAdd
            GMarkerGoogle m = new GMarkerGoogle(currentMarker.Position, GMarkerGoogleType.green_small);
            
            //prevent multiple start markers from existing
            if(hasStartMarker){
                objects.Markers.RemoveAt(0);
            }

            //add the marker
            m.ToolTipText = "Start";
            m.ToolTipMode = MarkerTooltipMode.OnMouseOver;
            objects.Markers.Insert(0, m);

            hasStartMarker = true;
        }

        // set route end - MDKfunctional
        bool hasEndMarker = false;
        private void buttonSetEnd_Click(object sender, EventArgs e)
        {
            end = currentMarker.Position;
            // - MDKAdd
            GMarkerGoogle m = new GMarkerGoogle(currentMarker.Position, GMarkerGoogleType.red_small);

            //prevent multiple start markers from existing
            if (hasEndMarker)
            {
                objects.Markers.RemoveAt(1);
            }
            m.ToolTipText = "End";
            m.ToolTipMode = MarkerTooltipMode.OnMouseOver;

            //add the marker
            if (hasStartMarker)
            {
                objects.Markers.Insert(1, m);
            }
            else
            {
                objects.Markers.Insert(0, m);
            }
            hasEndMarker = true;
        }

        // add route - MDKfunctional
        private void btnAddRoute_Click(object sender, EventArgs e)
        {
            RoutingProvider rp = MainMap.MapProvider as RoutingProvider;
            if (rp == null)
            {
                rp = GMapProviders.GoogleMap; // use google if provider does not implement routing
            }

            MapRoute route = rp.GetRoute(start, end, false, false, (int)MainMap.Zoom);
            if (route != null)
            {
                // add route
                GMapRoute r = new GMapRoute(route.Points, route.Name);
                r.IsHitTestVisible = true;
                routes.Routes.Add(r);

                // add route start/end marks
                GMapMarker m1 = new GMarkerGoogle(start, GMarkerGoogleType.green_big_go);
                m1.ToolTipText = "Start: " + route.Name;
                m1.ToolTipMode = MarkerTooltipMode.OnMouseOver;

                GMapMarker m2 = new GMarkerGoogle(end, GMarkerGoogleType.red_big_stop);
                m2.ToolTipText = "End: " + end.ToString();
                m2.ToolTipMode = MarkerTooltipMode.OnMouseOver;

                objects.Markers.Add(m1);
                objects.Markers.Add(m2);
            }
        }

        // add marker on current position - MDKfunctional
        private void addUserMarker(object sender, EventArgs e)
        {
            GMarkerGoogle m = new GMarkerGoogle(currentMarker.Position, GMarkerGoogleType.blue_small);

            m.ToolTipText = "User";
            m.ToolTipMode = MarkerTooltipMode.OnMouseOver;
            objects.Markers.Add(m);
        }

        // add marker from APRS transmission - MDKEdit - TODO: Function not needed; addUserMarker() replaces it ??
        private void addMarkerFromButton(object sender, EventArgs e)
        {
            GMarkerGoogle m = new GMarkerGoogle(currentMarker.Position, GMarkerGoogleType.blue_small);

            m.ToolTipText = "Tracker";
            m.ToolTipMode = MarkerTooltipMode.OnMouseOver;
            objects.Markers.Add(m);
        }

        // clear routes - MDKfunctional
        private void btnClearRoutes_Click(object sender, EventArgs e)
        {
            routes.Routes.Clear();

            //remove start/end markes of this route
            string markerText = "";
            int count = objects.Markers.Count;
            for (int i = count-1; i >= 0; i--)
            {
                markerText = objects.Markers[i].ToolTipText.ToString();
                if (markerText.StartsWith("Start"))
                {
                    objects.Markers.RemoveAt(i);
                }
                else if (markerText.StartsWith("End"))
                {
                    objects.Markers.RemoveAt(i); 
                    //objects.Markers[i].Dispose();
                }                
            }
            hasEndMarker = false;
            hasStartMarker = false;
        }

        // clear markers - MDKfunctional
        private void btnClearMarkers_Click(object sender, EventArgs e)
        {
            //preserve stert/end markes of this route
            string markerText = ""; 
            int count = objects.Markers.Count;
            for (int i = (count - 1); i >= 0; i--)
            {
                markerText = objects.Markers[i].ToolTipText.ToString();
                if (markerText.StartsWith("User"))
                {
                    objects.Markers.RemoveAt(i); 
                }
            }
        }

        //clears all markers and routes - MDKfunctional
        private void btnClearAll_Click(object sender, EventArgs e)
        {
            objects.Markers.Clear();
            routes.Routes.Clear();
            hasEndMarker = false;
            hasStartMarker = false;
        }

        // show current marker - MDKfunctional
        private void checkBoxCurrentMarker_CheckedChanged(object sender, EventArgs e)
        {
            currentMarker.IsVisible = xboxCurrentMarker.Checked;
        }

        // can drag - MDKfunctional
        private void checkBoxCanDrag_CheckedChanged(object sender, EventArgs e)
        {
            MainMap.CanDragMap = xboxCanDrag.Checked;
        }

        // zoom to max for markers - MDKfunctional
        private void button7_Click(object sender, EventArgs e)
        {
            MainMap.ZoomAndCenterMarkers("objects");
        }

        // saves current map view - MDKfunctional
        private void btnSaveView_Click(object sender, EventArgs e)
        {
            try
            {
                using (SaveFileDialog sfd = new SaveFileDialog())
                {
                    sfd.Filter = "PNG (*.png)|*.png";
                    sfd.FileName = "GMap.NET image";

                    Image tmpImage = MainMap.ToImage();
                    if (tmpImage != null)
                    {
                        using (tmpImage)
                        {
                            if (sfd.ShowDialog() == DialogResult.OK)
                            {
                                tmpImage.Save(sfd.FileName);

                                MessageBox.Show("Image saved: " + sfd.FileName, "GMap.NET", MessageBoxButtons.OK, MessageBoxIcon.Information);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Image failed to save: " + ex.Message, "GMap.NET", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        // debug tile grid - MDKfunctional
        private void showGridlines(object sender, EventArgs e)
        {
            MainMap.ShowTileGridLines = xboxGrid.Checked;
        }

        // saves image of selected area - MDKfunctional
        private void btnGetStatic_Click(object sender, EventArgs e)
        {
            StaticImage st = new StaticImage(this);
            st.Owner = this;
            st.Show();
        }

        // key-up events - MDKfunctional
        private void MainForm_KeyUp(object sender, KeyEventArgs e)
        {
            int offset = -22;

            if (e.KeyCode == Keys.Left)
            {
                MainMap.Offset(-offset, 0);
            }
            else if (e.KeyCode == Keys.Right)
            {
                MainMap.Offset(offset, 0);
            }
            else if (e.KeyCode == Keys.Up)
            {
                MainMap.Offset(0, -offset);
            }
            else if (e.KeyCode == Keys.Down)
            {
                MainMap.Offset(0, offset);
            }
            else if (e.KeyCode == Keys.Delete)
            {

                if (currentRoute != null)
                {
                    routes.Routes.Remove(currentRoute);
                    currentRoute = null;
                }

                if (CurentRectMarker != null)
                {
                    objects.Markers.Remove(CurentRectMarker);

                    if (CurentRectMarker.InnerMarker != null)
                    {
                        objects.Markers.Remove(CurentRectMarker.InnerMarker);
                    }
                    CurentRectMarker = null;

                    //RegeneratePolygon();
                }
            }
            else if (e.KeyCode == Keys.Escape)
            {
                MainMap.Bearing = 0;

                //if (currentTransport != null && !MainMap.IsMouseOverMarker)
                //{
                //    currentTransport.ToolTipMode = MarkerTooltipMode.OnMouseOver;
                //    currentTransport = null;
                //}
            }
        }

        // key-press events - MDKfunctional
        private void MainForm_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (MainMap.Focused)
            {
                if (e.KeyChar == '+')
                {
                    MainMap.Zoom = ((int)MainMap.Zoom) + 1;
                }
                else if (e.KeyChar == '-')
                {
                    MainMap.Zoom = ((int)(MainMap.Zoom + 0.99)) - 1;
                }
                else if (e.KeyChar == 'a')
                {
                    MainMap.Bearing--;
                }
                else if (e.KeyChar == 'z')
                {
                    MainMap.Bearing++;
                }
            }
        }

        //changes zoom - MDKfunctional
        private void buttonZoomUp_Click(object sender, EventArgs e)
        {
            MainMap.Zoom = ((int)MainMap.Zoom) + 1;
        }

        //changes zoom - MDKfunctional
        private void buttonZoomDown_Click(object sender, EventArgs e)
        {
            MainMap.Zoom = ((int)(MainMap.Zoom + 0.99)) - 1;
        }



        #endregion

        #region -- caching --

        // import map data - MDKfunctional
        private void btnCacheImport_Click(object sender, EventArgs e)
        {
            MainMap.ShowImportDialog();
        }

        // export map data - MDKfunctional
        private void btnCacheExport_Click(object sender, EventArgs e)
        {
            MainMap.ShowExportDialog();
        }

        // prefetch - MDKfunctional
        private void btnCachePrefetch_Click(object sender, EventArgs e)
        {
            RectLatLng area = MainMap.SelectedArea;
            if (!area.IsEmpty)
            {
                int zoom = (int)MainMap.Zoom;
                DialogResult res = MessageBox.Show("Ready ripp at Zoom = " + zoom + " and greater?", "GMap.NET Cache", MessageBoxButtons.YesNoCancel);
                if (res == DialogResult.Yes)
                {
                    for (int i = zoom; i <= 17; i++)
                    {
                        using (TilePrefetcher obj = new TilePrefetcher())
                        {
                            obj.Owner = this;
                            obj.ShowCompleteMessage = false;
                            obj.Start(area, i, MainMap.MapProvider, 100);
                        }
                    }
                }
            }
            else
            {
                MessageBox.Show("Select map area holding ALT", "GMap.NET", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        // clear cache - MDKfunctional
        private void btnCacheClear_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Are You sure?", "Clear GMap.NET cache?", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK)
            {
                try
                {
                    MainMap.Manager.PrimaryCache.DeleteOlderThan(DateTime.Now, null);
                    MessageBox.Show("Done. Cache is clear.");
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

        // open disk cache location - MDKfunctional
        private void btnCacheLocationOpen_Click(object sender, EventArgs e)
        {
            try
            {
                string argument = "/select, \"" + MainMap.CacheLocation + "TileDBv5\"";
                System.Diagnostics.Process.Start("explorer.exe", argument);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Failed to open: " + ex.Message, "GMap.NET", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        #endregion

        #region chart click events

        //this method clears the background of all charts
        private void ResetChartColors()
        {
            chrtTopLeft.BackColor = Color.LightGray;
            chrtTopRight.BackColor = Color.LightGray;
            chrtBottomLeft.BackColor = Color.LightGray;
            chrtBottomRight.BackColor = Color.LightGray;
        }

        ///TODO: check min/max/average with real data

        //highlight Top Left chart on click and set text box values based on this chart
        private void chrtTopLeft_Click(object sender, EventArgs e)
        {
            ResetChartColors();
            chrtTopLeft.BackColor = Color.Gray;
            tboxChartData.Text = "Altitude";
            tboxCurrent.Text = tboxAtmoAltitude.Text;
            tboxAverage.Text = (velocitySum / chrtBottomRight.Series.FindByName("altitudeTrend").Points.Count).ToString();
            tboxMax.Text = chrtBottomRight.Series.FindByName("altitudeTrend").Points.FindMaxByValue().ToString();
            tboxMin.Text = chrtBottomRight.Series.FindByName("altitudeTrend").Points.FindMinByValue().ToString();
        }

        //highlight Top Right chart on click and set text box values based on this chart
        private void chrtTopRight_Click(object sender, EventArgs e)
        {
            ResetChartColors();
            chrtTopRight.BackColor = Color.Gray;
            tboxChartData.Text = "Humidity";
            tboxCurrent.Text = tboxAtmoHumidity.Text;
            tboxAverage.Text = (humiditySum / chrtBottomRight.Series.FindByName("humidityTrend").Points.Count).ToString();
            tboxMax.Text = chrtBottomRight.Series.FindByName("humidityTrend").Points.FindMaxByValue().ToString();
            tboxMin.Text = chrtBottomRight.Series.FindByName("humidityTrend").Points.FindMinByValue().ToString();
        }

        //highlight Bottom Left chart on click and set text box values based on this chart
        private void chrtBottomLeft_Click(object sender, EventArgs e)
        {
            ResetChartColors();
            chrtBottomLeft.BackColor = Color.Gray;
            tboxChartData.Text = "Pressure";
            tboxCurrent.Text = tboxAtmoPressure.Text;
            tboxAverage.Text = (pressureSum / chrtBottomRight.Series.FindByName("pressureTrend").Points.Count).ToString();
            tboxMax.Text = chrtBottomRight.Series.FindByName("pressureTrend").Points.FindMaxByValue().ToString();
            tboxMin.Text = chrtBottomRight.Series.FindByName("pressureTrend").Points.FindMinByValue().ToString();
        }

        //highlight Bottom Right chart on click and set text box values based on this chart
        private void chrtBottomRight_Click(object sender, EventArgs e)
        {
            ResetChartColors();
            chrtBottomRight.BackColor = Color.Gray;
            tboxChartData.Text = "Velocity";
            tboxCurrent.Text = tboxMasterVelocity.Text;
            tboxAverage.Text = (velocitySum / chrtBottomRight.Series.FindByName("velocityTrend").Points.Count).ToString();
            tboxMax.Text = chrtBottomRight.Series.FindByName("velocityTrend").Points.FindMaxByValue().ToString();
            tboxMin.Text = chrtBottomRight.Series.FindByName("velocityTrend").Points.FindMinByValue().ToString();
        }

        #endregion

        #region transmission handling

        //variable declarations
        string latitude;
        string longitude;
        bool firstTransmissionDatum = false;
        double velocitySum = 0;
        double humiditySum = 0;
        double altitudeSum = 0;
        double pressureSum = 0;
        
        //runs on init 
        public void PrepareGraphs(){

            //set up for graphs MDKEdit
            // http://www.youtube.com/watch?v=zTod4-Fg6Ew - split containers
            // http://www.youtube.com/watch?v=bMXtgPk875I - chart controls

            chrtTopLeft.ChartAreas.Add("altitudeArea");
            chrtTopLeft.Series.Add("altitudeTrend");

            chrtTopRight.ChartAreas.Add("humidityArea");
            chrtTopRight.Series.Add("humidityTrend");

            chrtBottomLeft.Series.Add("pressureTrend");
            chrtBottomLeft.ChartAreas.Add("pressureArea");

            chrtBottomRight.ChartAreas.Add("velocityArea");
            chrtBottomRight.Series.Add("velocityTrend");

            // declare all series, data points to be modified dynamically at run

            //---------prep altitude area BEGIN 
            chrtTopLeft.Series["altitudeTrend"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
            chrtTopLeft.Series["altitudeTrend"].Color = Color.Green;
            System.Windows.Forms.DataVisualization.Charting.AxisName.X.Equals("Time");
            System.Windows.Forms.DataVisualization.Charting.AxisName.Y.Equals("Altitude");
            
            ///required initial value
            chrtTopLeft.Series["altitudeTrend"].Points.AddXY(0, 140);
            //---------prep altitude area END 


            //-----------prep humidity area BEGIN
            chrtTopRight.Series["humidityTrend"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
            chrtTopRight.Series["humidityTrend"].Color = Color.Red;
            System.Windows.Forms.DataVisualization.Charting.AxisName.X.Equals("Time");
            System.Windows.Forms.DataVisualization.Charting.AxisName.Y.Equals("Humidity");

            ///required initial value
            chrtTopRight.Series["humidityTrend"].Points.AddXY(0, 50);
            //-----------prep humidity area END


            //-----------prep pressure area BEGIN
            chrtBottomLeft.Series["pressureTrend"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
            chrtBottomLeft.Series["pressureTrend"].Color = Color.Blue;
            System.Windows.Forms.DataVisualization.Charting.AxisName.X.Equals("Time");
            System.Windows.Forms.DataVisualization.Charting.AxisName.Y.Equals("Pressure");

            ///required initial value
            chrtBottomLeft.Series["pressureTrend"].Points.AddXY(0, 100000);
            //-----------prep pressure area END


            //----------prep velocity area BEGIN
            chrtBottomRight.Series["velocityTrend"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
            chrtBottomRight.Series["velocityTrend"].Color = Color.Green;
            System.Windows.Forms.DataVisualization.Charting.AxisName.X.Equals("Time");
            System.Windows.Forms.DataVisualization.Charting.AxisName.Y.Equals("Altitude");

            ///required initial value
            chrtBottomRight.Series["velocityTrend"].Points.AddXY(0, 0);
            //----------prep velocity area END

            //put chart displays in a ready state
            ResetChartColors();
        }
        
        //parses transmissions and saves data to CSV file
        public void ParseIncomingData(string rawDataReceived)
        {
            //check to see if data should be processed
            if (!cboxCollectData.Checked )
            {
                AddTextDelegate("Transmission not saved: " + rawDataReceived +"\r\n");
                return;
            }
            else if (!rawDataReceived.StartsWith("KD8TDF"))
            {
                AddTextDelegate("Foreign transmission: " + rawDataReceived + "\r\n");
                return;
            }

            /* sample stansmissions
             * KD8TDF-9>APRS,WIDE2-1:/191950zN/WO/ T79 S00 V H99.99 _ |
             * KD8TDF-9>APRS,WIDE2-1:/151916z3944.87N/08348.75WO005/0.013 SV:09 A-30.5 B45.64 C99542
             */

            //find and store latitude string
            int indexStart = rawDataReceived.IndexOf("z");
            int indexEnd = rawDataReceived.IndexOf("N/");
            latitude = rawDataReceived.Substring(indexStart + 1, indexEnd - indexStart - 1);

            //find and store longitude string
            indexStart = rawDataReceived.IndexOf("N/");
            indexEnd = rawDataReceived.IndexOf("WO");
            longitude = rawDataReceived.Substring(indexStart + 2, indexEnd - indexStart - 2);
            
            //remove APRS overhead from string
            string transmissionCommentField = rawDataReceived.Substring(rawDataReceived.IndexOf(" ") + 1); 

            //place each datum in its own variable
            string[] dataTransmission;
            dataTransmission = transmissionCommentField.Split('~');

            //variables for processing datums
            string typeCode;
            string data;
            string csvData = "";
            string testString = "";

            //loop through all datums in the transmission and send them to the chart builder
            for (int i = 1; i < dataTransmission.Length; i++)
            {
                if (i == 1)
                {
                    firstTransmissionDatum = true;
                }
                else
                {
                    firstTransmissionDatum = false;
                }

                //remove unwanted characters
                dataTransmission[i] = dataTransmission[i].Trim();

                //zero not always trasmitted properly so add '0.0' to any transmission with no data
                if (dataTransmission[i].Length == 1) 
                {
                    dataTransmission[i] += "0";
                }
                
                //pull out data and data type and send to processing function
                typeCode = dataTransmission[i].Substring(0, 1);
                if (typeCode != "e")
                {
                    testString = dataTransmission[i].Substring(1);
                    data = dataTransmission[i].Substring(1);
                    processTransmissionDatum(typeCode, data);

                    //append data to string for CSV write
                    csvData += typeCode + data + ",";
                }
                else
                {
                    AddTextDelegate("Error Message: " + dataTransmission[i].Substring(1) + "\r\n");
                }
            }

            //handle case of no GPS fix
            if (latitude == "" || longitude == "")
            {
                AddTextDelegate("No GPS fix: ");
            }
            else
            {
                //marker added here so extra accuracy can be added
                addTrackerMarker(latitude, longitude);
            }

            //display transmission in message box
            AddTextDelegate(rawDataReceived + "\r\n");

            //write the data to CSV file
            WriteToCSV(csvData);
        }

        //method to process data from transmissions (usually chart inserts)
        private void processTransmissionDatum(string dataType, string data)
        {
            //TODO: add inserts for all charts. altitude is finished and is a template
            ///data types organized by listing in google doc
            //MASTER MODULE DATA VALUES
            ChartDelegate(dataType, data);

        }

        //write the data to CSV file -- usually seniordesign-ui\Demo.WindowsForms\bin\Debug
        private void WriteToCSV(string data)
        {
            string path = Directory.GetCurrentDirectory();
            string filename = path+"\\TransmissionData" + unixTime.Milliseconds + ".csv";
            using (StreamWriter writer = new StreamWriter(filename, true))
            {
                writer.WriteLine(data);
            }
        }
        
        //must change lat/long coords to properly place map marker
        float conv_coords(float in_coords)
        {
            //Initialize the location.
            float f = in_coords;
            // Get the first two digits by turning f into an integer, then doing an integer divide by 100;
            // firsttowdigits should be 77 at this point.
            int firsttwodigits = ((int)f) / 100;                               //This assumes that f < 10000.
            float nexttwodigits = f - (float)(firsttwodigits * 100);
            float theFinalAnswer = (float)(firsttwodigits + nexttwodigits / 60.0);
            return theFinalAnswer;
        }

        // add marker from an APRS transmission - MDKEdit
        private void addTrackerMarker(string lat, string lng)
        {

            double latitude = double.Parse(lat), longitude = double.Parse(lng);
            PointLatLng APRSloc = new PointLatLng();
            APRSloc.Lat = conv_coords((float)latitude);
            APRSloc.Lng = conv_coords((float)longitude)*-1;

            GMarkerGoogle m = new GMarkerGoogle(APRSloc, GMarkerGoogleType.blue_small);

            m.ToolTipText = "Tracker";
            m.ToolTipMode = MarkerTooltipMode.OnMouseOver;
            objects.Markers.Add(m);
        }

        //places text in the message box
        delegate void SetTextDelegate(string value);
        public void AddTextDelegate(string value)
        {
            if (InvokeRequired)
            {
                Invoke(new SetTextDelegate(AddTextDelegate), value);
            }
            else
            {
                tboxMessageBox.AppendText(value);// += value;
                textBoxMarkerCount.Text = objects.Markers.Count.ToString();
            }
        }

        //this is where most of the transmission processing is done
        delegate void ChartDataDelegate(string dataType, string data);
        public void ChartDelegate(string dataType, string data)
        {
            if (InvokeRequired)
            {
                Invoke(new ChartDataDelegate(ChartDelegate), dataType, data);
            }
            else
            {
                if (firstTransmissionDatum)
                {
                    ClearTboxColor();
                }
                ///UNIVERSAL DATA TYPES
                if (dataType.Equals("t"))  //board temperature
                {
                    string dataString = data.ToString();
                    if (dataString.StartsWith("9")) //Master Module
                    {
                        tboxMasterBoardTemp.Text = dataString.Substring(1);
                        tboxMasterBoardTemp.BackColor = Color.Chartreuse;
                    }
                    else if (dataString.StartsWith("0")) //Atmo Module
                    {
                        tboxAtmoBoardTemp.Text = dataString.Substring(1);
                        tboxAtmoBoardTemp.BackColor = Color.Chartreuse;
                    }
                    else if (dataString.StartsWith("1")) //Geiger Module
                    {
                        tboxGeigerBoardTemp.Text = dataString.Substring(1);
                        tboxGeigerBoardTemp.BackColor = Color.Chartreuse;
                    }
                    else if (dataString.StartsWith("2")) //Camera Module
                    {
                        tboxCameraBoardTemp.Text = dataString.Substring(1);
                        tboxCameraBoardTemp.BackColor = Color.Chartreuse;
                    }
                }
                else if (dataType.Equals("l"))  //battery level
                {
                    string dataString = data.ToString();
                    if (dataString.StartsWith("9")) //Master Module
                    {
                        tboxMasterBatteryLevel.Text = dataString.Substring(1);
                        tboxMasterBatteryLevel.BackColor = Color.Chartreuse;
                    }
                    else if (dataString.StartsWith("0")) //Atmo Module
                    {
                        tboxAtmoBatteryLevel.Text = dataString.Substring(1);
                        tboxAtmoBatteryLevel.BackColor = Color.Chartreuse;
                    }
                    else if (dataString.StartsWith("1"))  //Geiger Module
                    {
                        tboxGeigerBatteryLevel.Text = dataString.Substring(1);
                        tboxGeigerBatteryLevel.BackColor = Color.Chartreuse;
                    }
                    else if (dataString.StartsWith("2")) //Camera Module
                    {
                        tboxCameraBatteryLevel.Text = dataString.Substring(1);
                        tboxCameraBatteryLevel.BackColor = Color.Chartreuse;
                    }
                }
                else if (dataType.Equals("i")) //Info Message
                {
                    AddTextDelegate("Info: " + data + "\r\n");
                }
                
                ///MASTER MODULE DATA TYPES
                else if (dataType.Equals("_"))  //latitude extra accuracy
                {
                    //TODO: check math and decimal placement
                    latitude += data.ToString();
                    tboxMasterLatitude.Text = latitude;
                    tboxMasterLatitude.BackColor = Color.Chartreuse;
                }
                else if (dataType.Equals("|"))  //longitude extra accuracy
                {
                    //TODO: check math and decimal placement
                    longitude += data.ToString();
                    tboxMasterLongitude.Text = longitude;
                    tboxMasterLongitude.BackColor = Color.Chartreuse;
                }
                else if (dataType.Equals("h"))  //HDOP
                {
                    tboxMasterHDOP.Text = data.ToString();
                    tboxMasterHDOP.BackColor = Color.Chartreuse;
                }
                else if (dataType.Equals("v"))  //Velocity
                {
                    chrtBottomRight.Series.FindByName("velocityTrend").Points.AddY(double.Parse(data));
                    velocitySum += double.Parse(data);
                    tboxMasterVelocity.Text = data.ToString();
                    tboxMasterVelocity.BackColor = Color.Chartreuse;
                }
                else if (dataType.Equals("s"))  //satellites in view
                {
                    tboxMasterSatellites.Text = data.ToString();
                    tboxMasterSatellites.BackColor = Color.Chartreuse;
                }

                ///ATMOSPHERIC MODULE DATA VALUES
                else if (dataType.Equals("C"))  //Air Temperature
                {
                    tboxAtmoAirTemp.Text = data.ToString();
                    tboxAtmoAirTemp.BackColor = Color.Chartreuse;
                }
                else if (dataType.Equals("L"))  //Ambient Light
                {
                    tboxAtmoLight.Text = data.ToString();
                    tboxAtmoLight.BackColor = Color.Chartreuse;
                }
                else if (dataType.Equals("H"))  //Humidity
                {
                    chrtTopRight.Series.FindByName("humidityTrend").Points.AddY(double.Parse(data));
                    humiditySum += double.Parse(data);
                    tboxAtmoHumidity.Text = data.ToString();
                    tboxAtmoHumidity.BackColor = Color.Chartreuse;
                }
                else if (dataType.Equals("P"))  //Pressure
                {
                    chrtBottomLeft.Series.FindByName("pressureTrend").Points.AddY(double.Parse(data));
                    pressureSum += double.Parse(data);
                    tboxAtmoPressure.Text = data.ToString();
                    tboxAtmoPressure.BackColor = Color.Chartreuse;
                }
                else if (dataType.Equals("A"))  //Altitude
                {
                    chrtTopLeft.Series.FindByName("altitudeTrend").Points.AddY(double.Parse(data));
                    altitudeSum += double.Parse(data);
                    tboxAtmoAltitude.Text = data.ToString();
                    tboxAtmoAltitude.BackColor = Color.Chartreuse;
                }
                
                ///GEIGER MODULE DATA VALUES
                else if (dataType.Equals("R"))  //radiation (CPM)
                {
                    tboxGeigerRads.Text = data.ToString();
                    tboxGeigerRads.BackColor = Color.Chartreuse;
                }

                /// CAMERA MODULE DATA VALUES

                //INVALID DATA TYPE
                else
                {
                    AddTextDelegate("Info: " + data + "\r\n");
                }
            }
        }

        private void ClearTboxColor()
        {
            //tboxAtmoHumidity.BorderStyle = BorderStyle.FixedSingle;
            tboxMasterBoardTemp.BackColor = Color.White;
            tboxAtmoBoardTemp.BackColor = Color.White;
            tboxGeigerBoardTemp.BackColor = Color.White;
            tboxCameraBoardTemp.BackColor = Color.White;
            tboxMasterBatteryLevel.BackColor = Color.White;
            tboxAtmoBatteryLevel.BackColor = Color.White;
            tboxGeigerBatteryLevel.BackColor = Color.White;
            tboxCameraBatteryLevel.BackColor = Color.White;
            tboxMasterLatitude.BackColor = Color.White;
            tboxMasterLongitude.BackColor = Color.White;
            tboxMasterHDOP.BackColor = Color.White;
            tboxMasterVelocity.BackColor = Color.White;
            tboxMasterSatellites.BackColor = Color.White;
            tboxAtmoAirTemp.BackColor = Color.White;
            tboxAtmoLight.BackColor = Color.White;
            tboxAtmoHumidity.BackColor = Color.White;
            tboxAtmoPressure.BackColor = Color.White;
            tboxAtmoAltitude.BackColor = Color.White;
            tboxGeigerRads.BackColor = Color.White;
            return;
        }

        #endregion

        #region testing
        
        //click event on the test button
        //currently simulates serial inputs
        string testData;
        int testIteration = 0;
        double testLat = 39.751248, testLng = -83.809848, testVelocity = 5.8, testAltitude = 100, testPressure = 700, testHumidity = 38;
        private void btnTest_Click(object sender, EventArgs e)
        {
            testLat += GetRandomNumber(-.005, .015);
            testLng += GetRandomNumber(-.005, .015);
            testVelocity += GetRandomNumber(1, 15);
            testAltitude += GetRandomNumber(50, 150);
            testPressure -= GetRandomNumber(10, 50);
            testHumidity -= GetRandomNumber(1, 3);

            switch (testIteration)
            {
                case 0:
                    testData = "KD8TDF-9>APRS,WIDE2-1:/151916z" + testLat + "N/" + testLng + "WO005/0.013 V" + testVelocity + " A" + testAltitude+" H"+testHumidity+" P"+testPressure;
                    ParseIncomingData(testData);
                    break;
                case 1:
                    testData = "KD8TDF-9>APRS,WIDE2-1:/151916z" + testLat + "N/" + testLng + "WO005/0.013 V" + testVelocity + " A" + testAltitude + " H" + testHumidity + " P" + testPressure;
                    ParseIncomingData(testData);
                    break;
                case 2:
                    testData = "KD8TDF-9>APRS,WIDE2-1:/151916z" + testLat + "N/" + testLng + "WO005/0.013 V" + testVelocity + " A" + testAltitude + " H" + testHumidity + " P" + testPressure;
                    ParseIncomingData(testData);
                    break;
                case 3:
                    testData = "KD8TDF-9>APRS,WIDE2-1:/151916z" + testLat + "N/" + testLng + "WO005/0.013 V" + testVelocity + " A" + testAltitude + " H" + testHumidity + " P" + testPressure;
                    ParseIncomingData(testData);
                    break;
                case 4:
                    testData = "KD8TDF-9>APRS,WIDE2-1:/151916z" + testLat + "N/" + testLng + "WO005/0.013 V" + testVelocity + " A" + testAltitude + " H" + testHumidity + " P" + testPressure;
                    ParseIncomingData(testData);
                    break;
                case 5:
                    testData = "KD8TDF-9>APRS,WIDE2-1:/151916z" + testLat + "N/" + testLng + "WO005/0.013 V" + testVelocity + " A" + testAltitude + " H" + testHumidity + " P" + testPressure;
                    ParseIncomingData(testData);
                    break;
                case 6:
                    testData = "KD8TDF-9>APRS,WIDE2-1:/151916z" + testLat + "N/" + testLng + "WO005/0.013 V" + testVelocity + " A" + testAltitude + " H" + testHumidity + " P" + testPressure;
                    ParseIncomingData(testData);
                    break;
                case 7:
                    testData = "KD8TDF-9>APRS,WIDE2-1:/151916z" + testLat + "N/" + testLng + "WO005/0.013 V" + testVelocity + " A" + testAltitude + " H" + testHumidity + " P" + testPressure;
                    ParseIncomingData(testData);
                    break;
                case 8:
                    testData = "KD8TDF-9>APRS,WIDE2-1:/151916z" + testLat + "N/" + testLng + "WO005/0.013 V" + testVelocity + " A" + testAltitude + " H" + testHumidity + " P" + testPressure;
                    ParseIncomingData(testData);
                    break;
                case 9:
                    testData = "KD8TDF-9>APRS,WIDE2-1:/151916z" + testLat + "N/" + testLng + "WO005/0.013 V" + testVelocity + " A" + testAltitude + " H" + testHumidity + " P" + testPressure;
                    ParseIncomingData(testData);
                    break;
                default:
                    break;
            }
            testIteration++;
        }

        public double GetRandomNumber(double minimum, double maximum)
        {
            Random random = new Random();
            return random.NextDouble() * (maximum - minimum) + minimum;
        }

        #endregion


    }
}
//TODO: CSV logging, offline caching
//weekly changes:   chart text display, map functionality[routes, layout, markers], find/remove unused code, 
//                  figured out caching but still needs to be tested
                  