private void ddlProjects_SelectedIndexChanged(object sender, EventArgs e)
        {
            // attempting to download the Google Maps Engine maps
            log.Debug("Attempting to populate the form with data.");
            try
            {
                // setup a new API object to query the Google Maps Engine API
                MapsEngine.API.GoogleMapsEngineAPI api = new MapsEngine.API.GoogleMapsEngineAPI(ref log);

                // retrieve a list of maps for the filtered project identifier
                maps = api.getMapsByProjectId(ext.getToken(), ((MapsEngine.DataModel.gme.Project) this.ddlProjects.SelectedItem).id);

                // sort the maps by name
                maps.Sort(delegate(MapsEngine.DataModel.gme.Map firstMap,
                                   MapsEngine.DataModel.gme.Map nextMap)
                {
                    return(firstMap.name.CompareTo(nextMap.name));
                });

                // set the datagrid data source as the newly downloaded maps
                log.Debug("Setting the maps object as the data source for the grid.");
                this.dataGridGlobeDirectory.DataSource = maps;

                // update the boolean value
                isRequestThroughAPI = true;
            }
            catch (System.Exception ex)
            {
                // an error occured, log
                log.Error(ex);
            }
        }
        /*
         * Loading the form data
         */
        private void GoogleMapsEngineDirectoryListing_Load(object sender, EventArgs e)
        {
            // attempting to download the Google Maps Engine projects for the user
            log.Debug("Attempting to populate the projects drop down list with data.");
            try
            {
                // setup a new API object to query the Google Maps Engine API
                MapsEngine.API.GoogleMapsEngineAPI api = new MapsEngine.API.GoogleMapsEngineAPI(ref log);

                // retrieve a list of projects for the user
                List <MapsEngine.DataModel.gme.Project> projects = api.getProjects(ext.getToken());

                // sort the projects by name
                projects.Sort(delegate(MapsEngine.DataModel.gme.Project firstProject,
                                       MapsEngine.DataModel.gme.Project nextProject)
                {
                    return(firstProject.name.CompareTo(nextProject.name));
                });

                // set the ddl data source as the newly downloaded project
                log.Debug("Setting the projects object as the data source for the drop down list.");
                this.ddlProjects.DataSource    = projects;
                this.ddlProjects.DisplayMember = "name";
                this.ddlProjects.ValueMember   = "id";

                // kick off the
                //ddlProjects_SelectedIndexChanged(null, null);
            }
            catch (System.Exception ex)
            {
                // an error occured, log
                log.Error(ex);
            }
        }
        // the constructor for the Feature Class Management class
        public GoogleMapsEngineFeatureClassManagement(MapsEngine.API.GoogleMapsEngineAPI api)
        {
            // initialize and configure log4net, reading from Xml .config file
            log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo("log4net.config"));

            log.Info("GoogleMapsEngineFeatureClassManagement initializing.");

            // retrieve a reference to the extension
            log.Debug("Retrieiving a reference to the extension object.");
            ext = GoogleMapsEngineToolsExtensionForArcGIS.GetExtension();

            // initiate the Google Maps Enigne API object
            log.Debug("Setting the GME API object.");
            this.api = api;

            // generate a worldwide polygon, for default (spatial geometry undetermined or undefined) assets
            log.Debug("Establishing a default worldwide polygon object.");
            IPoint pUL = new Point();

            pUL.X = -180;
            pUL.Y = 90;
            IPoint pLL = new Point();

            pLL.X = -180;
            pLL.Y = -90;
            IPoint pLR = new Point();

            pLR.X = 180;
            pLR.Y = -90;
            IPoint pUR = new Point();

            pUR.X = 180;
            pUR.Y = 90;

            // add the points to the point collection
            IPointCollection pPtColl = new Polygon();

            pPtColl.AddPoint(pUL, Type.Missing, Type.Missing);
            pPtColl.AddPoint(pUR, Type.Missing, Type.Missing);
            pPtColl.AddPoint(pLR, Type.Missing, Type.Missing);
            pPtColl.AddPoint(pLL, Type.Missing, Type.Missing);
            pPtColl.AddPoint(pUL, Type.Missing, Type.Missing);

            // define the polygon as a list of points, then close the polygon
            worldPolygon = (IPolygon)pPtColl;
            worldPolygon.Close();
        }
        // the constructor for the Feature Class Management class
        public GoogleMapsEngineFeatureClassManagement(MapsEngine.API.GoogleMapsEngineAPI api)
        {
            // initialize and configure log4net, reading from Xml .config file
            log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo("log4net.config"));

            log.Info("GoogleMapsEngineFeatureClassManagement initializing.");

            // retrieve a reference to the extension
            log.Debug("Retrieiving a reference to the extension object.");
            ext = GoogleMapsEngineToolsExtensionForArcGIS.GetExtension();

            // initiate the Google Maps Enigne API object
            log.Debug("Setting the GME API object.");
            this.api = api;

            // generate a worldwide polygon, for default (spatial geometry undetermined or undefined) assets
            log.Debug("Establishing a default worldwide polygon object.");
            IPoint pUL = new Point();
            pUL.X = -180;
            pUL.Y = 90;
            IPoint pLL = new Point();
            pLL.X = -180;
            pLL.Y = -90;
            IPoint pLR = new Point();
            pLR.X = 180;
            pLR.Y = -90;
            IPoint pUR = new Point();
            pUR.X = 180;
            pUR.Y = 90;

            // add the points to the point collection
            IPointCollection pPtColl = new Polygon();
            pPtColl.AddPoint(pUL, Type.Missing, Type.Missing);
            pPtColl.AddPoint(pUR, Type.Missing, Type.Missing);
            pPtColl.AddPoint(pLR, Type.Missing, Type.Missing);
            pPtColl.AddPoint(pLL, Type.Missing, Type.Missing);
            pPtColl.AddPoint(pUL, Type.Missing, Type.Missing);

            // define the polygon as a list of points, then close the polygon
            worldPolygon = (IPolygon)pPtColl;
            worldPolygon.Close();
        }
        /*
         * A function to handle the click event after the user clicks 'Add'
         */
        private void btnAdd_Click(object sender, EventArgs e)
        {
            // disable the button immediately
            this.btnAdd.Enabled = false;

            // create a download progress dialog and show it
            Dialogs.Processing.ProgressDialog downloadProgress = new Processing.ProgressDialog();
            downloadProgress.Show(this);

            // attempt to add the selected map to the user ArcGIS instance
            log.Debug("Attempting to create a new feature class and add it to the map.");
            try
            {
                // get the key out of the key/value pair object
                log.Debug("Fetching the user selected MapId from the DataGridView.");
                string MapId = ((MapsEngine.DataModel.gme.Map) this.dataGridGlobeDirectory.SelectedRows[0].DataBoundItem).id;
                log.Debug("MapId: " + MapId);

                // create a new empty Feature Class to hold the Google Maps Engine catalog results
                log.Debug("Creating a new empty feature class to hold the Google Maps Enigne catalog results");
                IFeatureClass fc = Extension.Data.GeodatabaseUtilities.createGoogleMapsEngineCatalogFeatureClass(ref log, ref ext);

                // publish a new download event to the extension
                ext.publishRaiseDownloadProgressChangeEvent(false, "Preparing to download map '" + MapId + "'.", 1, 0);

                // create a new reference to the Google Maps API.
                log.Debug("Creating a new instance of the Google Maps Engine API object.");
                MapsEngine.API.GoogleMapsEngineAPI api = new MapsEngine.API.GoogleMapsEngineAPI(ref log);

                // create a new map object to be defined by the API or MapRoot
                log.Debug("Creating a new empty Map object.");
                MapsEngine.DataModel.gme.Map map;

                // query Google Maps Engine for the layers within this map
                log.Debug("Fetching the Google Maps Engine layers for this map.");
                map = api.getMapById(ext.getToken(), MapId);

                // publish a new download event to the extension
                ext.publishRaiseDownloadProgressChangeEvent(false, "Building local geodatabase for map '" + MapId + "'.", 1, 0);

                // create a new Feature Class Management object
                Data.GoogleMapsEngineFeatureClassManagement fcMngmt = new Data.GoogleMapsEngineFeatureClassManagement(api);

                // populate a feature for every Google Maps Engine Map
                log.Debug("Populate the feature class with the specific MapId");
                fcMngmt.populateFCWithGoogleMapsEngineMap(ref fc, ref map);

                // publish a new download event to the extension
                ext.publishRaiseDownloadProgressChangeEvent(true, "Adding '" + MapId + "' layer to your map.", 1, 1);

                // add the new feature class to the map (auto selecting type "map")
                ext.addFeatureClassToMapAsLayer(ref fc, Properties.Resources.GeodatabaseUtilities_schema_LayerName
                                                , "" + Properties.Resources.GeodatabaseUtilities_schema_AssetType_Name + " = 'map'");

                // retrieve the Google Maps Engine WMS URL
                string url = Properties.Settings.Default.gme_wms_GetCapabilities;

                // replace the map identifier and auth token
                url = url.Replace("{mapId}", MapId);
                url = url.Replace("{authTokenPlusSlash}", ext.getToken().access_token + "/");

                // proactively add the viewable layer (WMS or WMTS) to the map
                ext.addWebMappingServiceToMap(new Uri(url));
            }
            catch (System.Exception ex)
            {
                // log error and warn user
                log.Error(ex);

                // hide the download progress, if it is visible
                downloadProgress.Hide();

                // warn the user of the error
                ext.displayErrorDialog(Properties.Resources.dialog_GoogleMapsEngineDirectoryListing_btnAdd_Click_unknownerror + "\n" + ex.Message);
            }

            // close the dialog immediately
            this.Close();
        }
        protected void uploadButtonClicked(String projectId, String name, String description, String tags, String aclName, String attribution)
        {
            try
            {
                // create a new Processing Dialog
                Dialogs.Processing.ProgressDialog processingDialog = new Processing.ProgressDialog();

                // check to see if the layer is valid
                // and destination is configured correctly
                if (isLayerValidated &&
                    projectId != null && projectId.Length > 0 &&
                    name != null && name.Length > 0 &&
                    aclName != null && aclName.Length > 0)
                {
                    // show the processing dialog
                    processingDialog.Show();

                    // create a reference to the Google Maps Engine API
                    MapsEngine.API.GoogleMapsEngineAPI api = new MapsEngine.API.GoogleMapsEngineAPI(ref log);

                    // establish a reference to the running ArcMap instance
                    ESRI.ArcGIS.ArcMapUI.IMxDocument mxDoc = (ESRI.ArcGIS.ArcMapUI.IMxDocument)ArcMap.Application.Document;

                    // retrieve a reference to the selected layer
                    ESRI.ArcGIS.Carto.ILayer selectedLayer = mxDoc.SelectedLayer;

                    // create a temporary working directory
                    System.IO.DirectoryInfo tempDir
                        = System.IO.Directory.CreateDirectory(ext.getLocalWorkspaceDirectory() + "\\" + System.Guid.NewGuid());

                    // determine what type of layer is selected
                    if (selectedLayer is ESRI.ArcGIS.Carto.IFeatureLayer)
                    {
                        // export a copy of the feature class to a "uploadable" Shapefile
                        // raise a processing notification
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Extracting a copy of '" + selectedLayer.Name + "' (feature class) for data upload.");
                        ExportLayerToShapefile(tempDir.FullName, selectedLayer.Name, selectedLayer);

                        processingDialog.Update();
                        processingDialog.Focus();

                        // create a list of files in the temp directory
                        List <String> filesNames = new List <String>();
                        for (int k = 0; k < tempDir.GetFiles().Count(); k++)
                        {
                            if (!tempDir.GetFiles()[k].Name.EndsWith(".lock"))
                            {
                                filesNames.Add(tempDir.GetFiles()[k].Name);
                            }
                        }

                        // create a Google Maps Engine asset record
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Requesting a new Google Maps Engine asset be created.");
                        MapsEngine.DataModel.gme.UploadingAsset uploadingAsset
                            = api.createVectorTableAssetForUploading(ext.getToken(),
                                                                     MapsEngine.API.GoogleMapsEngineAPI.AssetType.table,
                                                                     projectId,
                                                                     name,
                                                                     aclName,
                                                                     filesNames,
                                                                     description,
                                                                     tags.Split(",".ToCharArray()).ToList <String>(),
                                                                     "UTF-8");

                        // Initiate upload of file(s)
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Starting to upload files...");
                        api.uploadFilesToAsset(ext.getToken(), uploadingAsset.id, tempDir.GetFiles());

                        // launch a web browser
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Launching a web browser.");
                        System.Diagnostics.Process.Start("https://mapsengine.google.com/admin/#RepositoryPlace:cid=" + projectId + "&v=DETAIL_INFO&aid=" + uploadingAsset.id);
                    }
                    else if (selectedLayer is ESRI.ArcGIS.Carto.IRasterLayer)
                    {
                        // export a copy of the raster to a format that can be uploaded
                        // raise a processing notification
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Extracting a copy of '" + selectedLayer.Name + "' (raster) for data upload.");
                        ExportLayerToUploadableRaster(tempDir.FullName, tempDir.Name, selectedLayer);

                        processingDialog.Update();
                        processingDialog.Focus();

                        // create a list of files in the temp directory
                        List <String> filesNames = new List <String>();
                        for (int k = 0; k < tempDir.GetFiles().Count(); k++)
                        {
                            if (!tempDir.GetFiles()[k].Name.EndsWith(".lock"))
                            {
                                filesNames.Add(tempDir.GetFiles()[k].Name);
                            }
                        }

                        // create a Google Maps Engine asset record
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Requesting a new Google Maps Engine asset be created.");
                        MapsEngine.DataModel.gme.UploadingAsset uploadingAsset
                            = api.createRasterAssetForUploading(ext.getToken(),
                                                                projectId,
                                                                name,
                                                                aclName,
                                                                attribution, // attribution
                                                                filesNames,
                                                                description,
                                                                tags.Split(",".ToCharArray()).ToList <String>());

                        // Initiate upload of file(s)
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Starting to upload files...");
                        api.uploadFilesToAsset(ext.getToken(), uploadingAsset.id, tempDir.GetFiles());

                        // launch a web browser
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Launching a web browser.");
                        System.Diagnostics.Process.Start("https://mapsengine.google.com/admin/#RepositoryPlace:cid=" + projectId + "&v=DETAIL_INFO&aid=" + uploadingAsset.id);
                    }

                    // Delete temporary directory and containing files
                    // TODO: Remove temporary files, but can't remove them at the moment because they are in use by
                    // the ArcMap seesion.
                    //tempDir.Delete(true);

                    // close the processing dialog
                    ext.publishRaiseDownloadProgressChangeEvent(true, "Finished");
                    processingDialog.Close();
                }
                else
                {
                    // display an error dialog to the user
                    System.Windows.Forms.MessageBox.Show("The selected layer is invalid or the destination configuration has not been properly set.");
                }
            }
            catch (System.Exception ex)
            {
                // Ops.
                System.Windows.Forms.MessageBox.Show("An error occured. " + ex.Message);
            }

            // close the dialog
            this.Close();
        }
        protected void uploadButtonClicked(String projectId, String name, String description, String tags, String draftAccessList, String attribution, String acquisitionTime, String maskType)
        {
            // tags must not be null due to splits below or a null reference error occurs.
            // empty string handles properly.
            if (null == tags)
            {
                tags = "";
            }

            try
            {
                // create a new Processing Dialog
                Dialogs.Processing.ProgressDialog processingDialog = new Processing.ProgressDialog();

                // check to see if the layer is valid 
                // and destination is configured correctly
                if (isLayerValidated
                    && projectId != null && projectId.Length > 0
                    && name != null && name.Length > 0
                    && draftAccessList != null && draftAccessList.Length > 0
                    && uploadType.Equals("vector") || (uploadType.Equals("raster") && attribution != null && attribution.Length > 0))
                {
                    // show the processing dialog
                    processingDialog.Show();

                    // create a reference to the Google Maps Engine API
                    MapsEngine.API.GoogleMapsEngineAPI api = new MapsEngine.API.GoogleMapsEngineAPI(ref log);

                    // establish a reference to the running ArcMap instance
                    ESRI.ArcGIS.ArcMapUI.IMxDocument mxDoc = (ESRI.ArcGIS.ArcMapUI.IMxDocument)ArcMap.Application.Document;

                    // retrieve a reference to the selected layer
                    ESRI.ArcGIS.Carto.ILayer selectedLayer = mxDoc.SelectedLayer;

                    // create a temporary working directory
                    System.IO.DirectoryInfo tempDir
                        = System.IO.Directory.CreateDirectory(ext.getLocalWorkspaceDirectory() + "\\" + System.Guid.NewGuid());

                    // determine what type of layer is selected
                    if (selectedLayer is ESRI.ArcGIS.Carto.IFeatureLayer)
                    {
                        // export a copy of the feature class to a "uploadable" Shapefile
                        // raise a processing notification
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Extracting a copy of '" + selectedLayer.Name + "' (feature class) for data upload.");
                        ExportLayerToShapefile(tempDir.FullName, selectedLayer.Name, selectedLayer);

                        processingDialog.Update();
                        processingDialog.Focus();

                        // create a list of files in the temp directory
                        List<String> filesNames = new List<String>();
                        for (int k = 0; k < tempDir.GetFiles().Count(); k++)
                            if (!tempDir.GetFiles()[k].Name.EndsWith(".lock"))
                                filesNames.Add(tempDir.GetFiles()[k].Name);

                        // create a Google Maps Engine asset record
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Requesting a new Google Maps Engine asset be created.");
                        MapsEngine.DataModel.gme.UploadingAsset uploadingAsset
                            = api.createVectorTableAssetForUploading(ext.getToken(),
                            MapsEngine.API.GoogleMapsEngineAPI.AssetType.table,
                            projectId,
                            name,
                            draftAccessList,
                            filesNames,
                            description,
                            tags.Split(",".ToCharArray()).ToList<String>(),
                            "UTF-8");

                        // Initiate upload of file(s)
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Starting to upload files...");
                        api.uploadFilesToAsset(ext.getToken(), uploadingAsset.id, "tables", tempDir.GetFiles());

                        // launch a web browser
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Launching a web browser.");
                        System.Diagnostics.Process.Start("https://mapsengine.google.com/admin/#RepositoryPlace:cid=" + projectId +"&v=DETAIL_INFO&aid=" + uploadingAsset.id);
                    }
                    else if (selectedLayer is ESRI.ArcGIS.Carto.IRasterLayer)
                    {
                        // export a copy of the raster to a format that can be uploaded
                        // raise a processing notification
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Extracting a copy of '" + selectedLayer.Name + "' (raster) for data upload.");
                        ExportLayerToUploadableRaster(tempDir.FullName, selectedLayer.Name, selectedLayer);

                        processingDialog.Update();
                        processingDialog.Focus();

                        // create a list of files in the temp directory
                        List<String> filesNames = new List<String>();
                        for (int k = 0; k < tempDir.GetFiles().Count(); k++)
                            if (!tempDir.GetFiles()[k].Name.EndsWith(".lock"))
                                filesNames.Add(tempDir.GetFiles()[k].Name);

                        // create a Google Maps Engine asset record
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Requesting a new Google Maps Engine asset be created.");
                        MapsEngine.DataModel.gme.UploadingAsset uploadingAsset
                            = api.createRasterAssetForUploading(ext.getToken(),
                            projectId,
                            name,
                            draftAccessList,
                            attribution, // attribution
                            filesNames,
                            description,
                            tags.Split(",".ToCharArray()).ToList<String>(),
                            acquisitionTime,
                            maskType);

                        // Initiate upload of file(s)
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Starting to upload files...");
                        api.uploadFilesToAsset(ext.getToken(), uploadingAsset.id, "rasters", tempDir.GetFiles());

                        // launch a web browser
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Launching a web browser.");
                        System.Diagnostics.Process.Start("https://mapsengine.google.com/admin/#RepositoryPlace:cid="+ projectId +"&v=DETAIL_INFO&aid=" + uploadingAsset.id);
                    }

                    // Ask the user if the temporary files should be deleted
                    DialogResult dialogResult = MessageBox.Show(
                        String.Format(Properties.Resources.dialog_dataUpload_tempFileCleanupMessage,
                            tempDir.GetFiles().Count(), tempDir.FullName),
                        ext.getAddinName() + " Temporary File Clean-up", 
                        MessageBoxButtons.YesNo);

                    // if the user wishes to delete the temporary files, delete them
                    if (dialogResult == DialogResult.Yes)
                    {
                        try
                        {
                            // remove the temporary layer from the ArcMap session
                            ext.removeLayerByName((uploadType.Equals("vector") ? selectedLayer.Name : selectedLayer.Name + ".tif"), tempDir.FullName);

                            // Delete temporary directory and containing files
                            tempDir.Delete(true);
                        }
                        catch (Exception) { }
                    }

                    // close the processing dialog
                    ext.publishRaiseDownloadProgressChangeEvent(true, "Finished");
                    processingDialog.Close();
                }
                else
                {
                    // display an error dialog to the user
                    System.Windows.Forms.MessageBox.Show("The selected layer is invalid or the destination configuration has not been properly set.");
                }

            }
            catch (System.Exception ex)
            {
                // Ops.
                System.Windows.Forms.MessageBox.Show("An error occured. " + ex.Message);
            }

            // close the dialog
            this.Close();
        }
        protected void uploadButtonClicked(String projectId, String name, String description, String tags, String aclName, String attribution)
        {
            try
            {
                // create a new Processing Dialog
                Dialogs.Processing.ProgressDialog processingDialog = new Processing.ProgressDialog();

                // check to see if the layer is valid
                // and destination is configured correctly
                if (isLayerValidated
                    && projectId != null && projectId.Length > 0
                    && name != null && name.Length > 0
                    && aclName != null && aclName.Length > 0)
                {
                    // show the processing dialog
                    processingDialog.Show();

                    // create a reference to the Google Maps Engine API
                    MapsEngine.API.GoogleMapsEngineAPI api = new MapsEngine.API.GoogleMapsEngineAPI(ref log);

                    // establish a reference to the running ArcMap instance
                    ESRI.ArcGIS.ArcMapUI.IMxDocument mxDoc = (ESRI.ArcGIS.ArcMapUI.IMxDocument)ArcMap.Application.Document;

                    // retrieve a reference to the selected layer
                    ESRI.ArcGIS.Carto.ILayer selectedLayer = mxDoc.SelectedLayer;

                    // create a temporary working directory
                    System.IO.DirectoryInfo tempDir
                        = System.IO.Directory.CreateDirectory(ext.getLocalWorkspaceDirectory() + "\\" + System.Guid.NewGuid());

                    // determine what type of layer is selected
                    if (selectedLayer is ESRI.ArcGIS.Carto.IFeatureLayer)
                    {
                        // export a copy of the feature class to a "uploadable" Shapefile
                        // raise a processing notification
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Extracting a copy of '" + selectedLayer.Name + "' (feature class) for data upload.");
                        ExportLayerToShapefile(tempDir.FullName, selectedLayer.Name, selectedLayer);

                        processingDialog.Update();
                        processingDialog.Focus();

                        // create a list of files in the temp directory
                        List<String> filesNames = new List<String>();
                        for (int k = 0; k < tempDir.GetFiles().Count(); k++)
                            if (!tempDir.GetFiles()[k].Name.EndsWith(".lock"))
                                filesNames.Add(tempDir.GetFiles()[k].Name);

                        // create a Google Maps Engine asset record
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Requesting a new Google Maps Engine asset be created.");
                        MapsEngine.DataModel.gme.UploadingAsset uploadingAsset
                            = api.createVectorTableAssetForUploading(ext.getToken(),
                            MapsEngine.API.GoogleMapsEngineAPI.AssetType.table,
                            projectId,
                            name,
                            aclName,
                            filesNames,
                            description,
                            tags.Split(",".ToCharArray()).ToList<String>(),
                            "UTF-8");

                        // Initiate upload of file(s)
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Starting to upload files...");
                        api.uploadFilesToAsset(ext.getToken(), uploadingAsset.id, tempDir.GetFiles());

                        // launch a web browser
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Launching a web browser.");
                        System.Diagnostics.Process.Start("https://mapsengine.google.com/admin/#RepositoryPlace:cid=" + projectId +"&v=DETAIL_INFO&aid=" + uploadingAsset.id);
                    }
                    else if (selectedLayer is ESRI.ArcGIS.Carto.IRasterLayer)
                    {
                        // export a copy of the raster to a format that can be uploaded
                        // raise a processing notification
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Extracting a copy of '" + selectedLayer.Name + "' (raster) for data upload.");
                        ExportLayerToUploadableRaster(tempDir.FullName, tempDir.Name, selectedLayer);

                        processingDialog.Update();
                        processingDialog.Focus();

                        // create a list of files in the temp directory
                        List<String> filesNames = new List<String>();
                        for (int k = 0; k < tempDir.GetFiles().Count(); k++)
                            if (!tempDir.GetFiles()[k].Name.EndsWith(".lock"))
                                filesNames.Add(tempDir.GetFiles()[k].Name);

                        // create a Google Maps Engine asset record
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Requesting a new Google Maps Engine asset be created.");
                        MapsEngine.DataModel.gme.UploadingAsset uploadingAsset
                            = api.createRasterAssetForUploading(ext.getToken(),
                            projectId,
                            name,
                            aclName,
                            attribution, // attribution
                            filesNames,
                            description,
                            tags.Split(",".ToCharArray()).ToList<String>());

                        // Initiate upload of file(s)
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Starting to upload files...");
                        api.uploadFilesToAsset(ext.getToken(), uploadingAsset.id, tempDir.GetFiles());

                        // launch a web browser
                        ext.publishRaiseDownloadProgressChangeEvent(false, "Launching a web browser.");
                        System.Diagnostics.Process.Start("https://mapsengine.google.com/admin/#RepositoryPlace:cid="+ projectId +"&v=DETAIL_INFO&aid=" + uploadingAsset.id);
                    }

                    // Delete temporary directory and containing files
                    // TODO: Remove temporary files, but can't remove them at the moment because they are in use by
                    // the ArcMap seesion.
                    //tempDir.Delete(true);

                    // close the processing dialog
                    ext.publishRaiseDownloadProgressChangeEvent(true, "Finished");
                    processingDialog.Close();
                }
                else
                {
                    // display an error dialog to the user
                    System.Windows.Forms.MessageBox.Show("The selected layer is invalid or the destination configuration has not been properly set.");
                }

            }
            catch (System.Exception ex)
            {
                // Ops.
                System.Windows.Forms.MessageBox.Show("An error occured. " + ex.Message);
            }

            // close the dialog
            this.Close();
        }
        /*
         * Loading the form data
         */
        private void GoogleMapsEngineDirectoryListing_Load(object sender, EventArgs e)
        {
            // attempting to download the Google Maps Engine projects for the user
            log.Debug("Attempting to populate the projects drop down list with data.");
            try
            {
                // setup a new API object to query the Google Maps Engine API
                MapsEngine.API.GoogleMapsEngineAPI api = new MapsEngine.API.GoogleMapsEngineAPI(ref log);

                // retrieve a list of projects for the user
                List<MapsEngine.DataModel.gme.Project> projects = api.getProjects(ext.getToken());

                // sort the projects by name
                projects.Sort(delegate(MapsEngine.DataModel.gme.Project firstProject,
                    MapsEngine.DataModel.gme.Project nextProject)
                {
                    return firstProject.name.CompareTo(nextProject.name);
                });

                // set the ddl data source as the newly downloaded project
                log.Debug("Setting the projects object as the data source for the drop down list.");
                this.ddlProjects.DataSource = projects;
                this.ddlProjects.DisplayMember = "name";
                this.ddlProjects.ValueMember = "id";

                // kick off the 
                //ddlProjects_SelectedIndexChanged(null, null);
            }
            catch (System.Exception ex)
            {
                // an error occured, log
                log.Error(ex);
            }
        }
        private void ddlProjects_SelectedIndexChanged(object sender, EventArgs e)
        {
            // attempting to download the Google Maps Engine maps
            log.Debug("Attempting to populate the form with data.");
            try
            {
                // setup a new API object to query the Google Maps Engine API
                MapsEngine.API.GoogleMapsEngineAPI api = new MapsEngine.API.GoogleMapsEngineAPI(ref log);

                // retrieve a list of maps for the filtered project identifier
                maps = api.getMapsByProjectId(ext.getToken(), ((MapsEngine.DataModel.gme.Project)this.ddlProjects.SelectedItem).id);

                // sort the maps by name
                maps.Sort(delegate(MapsEngine.DataModel.gme.Map firstMap,
                    MapsEngine.DataModel.gme.Map nextMap)
                {
                    return firstMap.name.CompareTo(nextMap.name);
                });

                // set the datagrid data source as the newly downloaded maps
                log.Debug("Setting the maps object as the data source for the grid.");
                this.dataGridGlobeDirectory.DataSource = maps;

                // update the boolean value
                isRequestThroughAPI = true;
            }
            catch (System.Exception ex)
            {
                // an error occured, log
                log.Error(ex);
            }
        }
        /*
         * A function to handle the click event after the user clicks 'Add'
         */
        private void btnAdd_Click(object sender, EventArgs e)
        {
            // disable the button immediately
            this.btnAdd.Enabled = false;

            // create a download progress dialog and show it
            Dialogs.Processing.ProgressDialog downloadProgress = new Processing.ProgressDialog();
            downloadProgress.Show(this);

            // attempt to add the selected map to the user ArcGIS instance
            log.Debug("Attempting to create a new feature class and add it to the map.");
            try
            {
                // get the key out of the key/value pair object
                log.Debug("Fetching the user selected MapId from the DataGridView.");
                string MapId = ((MapsEngine.DataModel.gme.Map)this.dataGridGlobeDirectory.SelectedRows[0].DataBoundItem).id;
                log.Debug("MapId: " + MapId);

                // create a new empty Feature Class to hold the Google Maps Engine catalog results
                log.Debug("Creating a new empty feature class to hold the Google Maps Enigne catalog results");
                IFeatureClass fc = Extension.Data.GeodatabaseUtilities.createGoogleMapsEngineCatalogFeatureClass(ref log, ref ext);

                // publish a new download event to the extension
                ext.publishRaiseDownloadProgressChangeEvent(false, "Preparing to download map '" + MapId + "'.", 1, 0);
                
                // create a new reference to the Google Maps API.
                log.Debug("Creating a new instance of the Google Maps Engine API object.");
                MapsEngine.API.GoogleMapsEngineAPI api = new MapsEngine.API.GoogleMapsEngineAPI(ref log);

                // create a new map object to be defined by the API or MapRoot
                log.Debug("Creating a new empty Map object.");
                MapsEngine.DataModel.gme.Map map;

                // query Google Maps Engine for the layers within this map
                log.Debug("Fetching the Google Maps Engine layers for this map.");
                map = api.getMapById(ext.getToken(), MapId);

                // publish a new download event to the extension
                ext.publishRaiseDownloadProgressChangeEvent(false, "Building local geodatabase for map '" + MapId + "'.", 1, 0);

                // create a new Feature Class Management object
                Data.GoogleMapsEngineFeatureClassManagement fcMngmt = new Data.GoogleMapsEngineFeatureClassManagement(api);

                // populate a feature for every Google Maps Engine Map
                log.Debug("Populate the feature class with the specific MapId");
                fcMngmt.populateFCWithGoogleMapsEngineMap(ref fc, ref map);

                // publish a new download event to the extension
                ext.publishRaiseDownloadProgressChangeEvent(true, "Adding '" + MapId + "' layer to your map.", 1, 1);

                // add the new feature class to the map (auto selecting type "map")
                ext.addFeatureClassToMapAsLayer(ref fc, Properties.Resources.GeodatabaseUtilities_schema_LayerName
                    , "" + Properties.Resources.GeodatabaseUtilities_schema_AssetType_Name + " = 'map'");

                // retrieve the Google Maps Engine WMS URL
                string url = Properties.Settings.Default.gme_wms_GetCapabilities;

                // replace the map identifier and auth token
                url = url.Replace("{mapId}", MapId);
                url = url.Replace("{authTokenPlusSlash}", ext.getToken().access_token + "/");

                // proactively add the viewable layer (WMS or WMTS) to the map
                ext.addWebMappingServiceToMap(new Uri(url));
            }
            catch (System.Exception ex)
            {
                // log error and warn user
                log.Error(ex);

                // hide the download progress, if it is visible
                downloadProgress.Hide();

                // warn the user of the error
                ext.displayErrorDialog(Properties.Resources.dialog_GoogleMapsEngineDirectoryListing_btnAdd_Click_unknownerror + "\n" + ex.Message);
            }

            // close the dialog immediately
            this.Close();
        }