/// <summary>
        /// This method uses EsriHttpClient.Get method to fetch licensing info from licensing portal
        /// </summary>
        /// <returns></returns>
        Tuple<bool, string> TestGetLicense()
        {
            string printMore = "";
            LicenseLevels ll = LicenseInformation.Level;
            string ll_str = Enum.GetName(typeof(LicenseLevels), ll);
            printMore += "License level: " + ll_str + "\n";

            Tuple<bool, string> regPortal = GetLicensingPortalFReg();
            //if (regPortal.Item1 == false)
            //Assert.Inconclusive(regPortal.Item2 + " [CR310474]");
            string portalUrl = regPortal.Item2;
            printMore += "Licensing portal: " + portalUrl + "\n";
            EsriHttpClient myClient = new EsriHttpClient();

            #region REST call to get appInfo.Item.id and user.lastLogin of the licensing portal
            string selfUri = @"/sharing/rest/portals/self?f=json";
            var selfResponse = myClient.Get(portalUrl + selfUri);
            if (selfResponse == null)
                return new Tuple<bool, string>(false, "HTTP response is null");

            if (selfResponse.StatusCode != System.Net.HttpStatusCode.OK)
                return new Tuple<bool, string>(false, "Licensing portal is not set");

            string outStr = selfResponse.Content.ReadAsStringAsync().Result;

            //Deserialize the response in JSON into a usable object. 
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            PortalSelf self_obj = (PortalSelf)serializer.Deserialize(outStr, typeof(PortalSelf));
            if ((self_obj == null) || (self_obj.appInfo == null) || (self_obj.user == null))
            {
                return new Tuple<bool, string>(true, printLicenseCodes() + "\nPro is licensed offline.");
            }
            #endregion

            #region REST call to get the userLicenses
            string layerUri = @"/sharing/rest/content/listings/" + self_obj.appInfo.itemId + "/userLicenses?f=json&nonce=007&timestamp=" + self_obj.user.lastLogin;
            var response = myClient.Get(portalUrl + layerUri);
            if (response == null)
                return new Tuple<bool, string>(false, "HTTP response is null");

            string outStr2 = response.Content.ReadAsStringAsync().Result;

            //Deserialize the response in JSON into a usable object. 
            userLicenses obj = (userLicenses)serializer.Deserialize(outStr2, typeof(userLicenses));
            if (obj == null || obj.userEntitlementsString == null)
            {
                return new Tuple<bool, string>(true, printLicenseCodes() + "\nPro is licensed offline, and signed in with a different account.");
            }
            userEntitlementsString entitlement = (userEntitlementsString)serializer.Deserialize(obj.userEntitlementsString, typeof(userEntitlementsString));
            if (entitlement == null)
                return new Tuple<bool, string>(false, "Failed to fetch valid entitlements.");
            else
            {
                printMore += printLicenseCodes() + "Entitlements returned by GET request:";
                foreach (string e in entitlement.entitlements)
                    printMore += " " + e;
                printMore += "\nLicenses returned by GET request:";
                foreach (string l in entitlement.licenses)
                    printMore += " " + l;
                return new Tuple<bool, string>(true, printMore);
            }
            #endregion
        }
        /// <summary>
        /// Execute the given query and return the result
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public async Task<string> ExecWithEsriClientAsync(OnlineQuery query, ObservableCollection<OnlineResultItem> results, int maxResults = 0) {

            if (maxResults == 0)
                maxResults = OnlineQuery.DefaultMaxResults;
            if (MaxResponseLength == 0)
                MaxResponseLength = OnlineQuery.DefaultMaxResponseLength;

            _response = new StringBuilder();
            _errorResponse = "";

            //slap in the initial request
            _response.AppendLine(query.FinalUrl);
            _response.AppendLine("");

            try {
                Tuple<long, long> stats = new Tuple<long, long>(-1, -1);
                do {

                    query.Start = stats.Item2;

                    Debug.WriteLine("");
                    Debug.WriteLine(query.FinalUrl);
                    Debug.WriteLine("");

                    EsriHttpClient httpClient = new EsriHttpClient();
                    //submit the query
                    EsriHttpResponseMessage response = await httpClient.GetAsync(new Uri(query.FinalUrl).ToString());
                    HttpResponseHeaders headers = response.Headers;

                    //read out the json
                    string raw = await response.Content.ReadAsStringAsync();
                    //convert entity-replacement tags
                    raw = raw.Replace("&lt;", "<").Replace("&gt;", ">");
                    if (_response.Length < MaxResponseLength) {
                        _response.AppendLine("");
                        _response.AppendLine(raw);
                        if (_response.Length > MaxResponseLength)
                            _response.AppendLine("...");
                    }

                    Debug.WriteLine("");
                    Debug.WriteLine(raw);
                    Debug.WriteLine("");

                    //deserialize
                    stats = await ProcessResultsAsync(results, raw, query);

                } while (stats.Item2 < maxResults && stats.Item2 > 0);

            }
            catch (WebException we) {
                //bad request
                _response.AppendLine("");
                _response.AppendLine("WebException: " + we.Message);
                _response.AppendLine(query.FinalUrl);
                _response.AppendLine("");
                _response.AppendLine(new Uri(query.FinalUrl).Scheme.ToUpper() + " " +
                                ((int)we.Status).ToString());
                try {
                    _errorResponse = new StreamReader(we.Response.GetResponseStream()).ReadToEnd();
                    _response.AppendLine(_errorResponse);
                }
                catch {
                }
            }

            return _response.ToString();
        }
        /// <summary>
        /// Execute the query command
        /// </summary>
        private void CmdDoQuery()
        {
            try
            {
                var httpEsri = new EsriHttpClient() { BaseAddress = PortalManager.GetActivePortal() };
                // value has the following format: url with {};Redlands,...,...;Search Query,...,...
                // where Redlands ... are values and search query are keys
                var parts = AgolQuery.Value.Split(";".ToCharArray());
                var getUrl = parts[0];

                // get parameters
                if (CallParams.Count > 0)
                {
                    var lstParams = new List<object>() as IList<object>;
                    foreach (var kv in CallParams)
                        lstParams.Add(kv.Param);
                    getUrl = string.Format(parts[0], lstParams.ToArray());
                }
                System.Diagnostics.Debug.WriteLine(getUrl);
                var httpResponse = httpEsri.Get(getUrl);
                if (httpResponse.StatusCode == HttpStatusCode.OK && httpResponse.Content != null)
                {
                    var content = httpResponse.Content.ReadAsStringAsync().Result;
                    QueryResult = string.Format(@"{0}{1}", getUrl, System.Environment.NewLine);
                    QueryResult += string.Format(@"IsSuccessStatusCode: {0}{1}", httpResponse.IsSuccessStatusCode, System.Environment.NewLine);
                    QueryResult += string.Format(@"StatusCode: {0}{1}", httpResponse.StatusCode, System.Environment.NewLine);
                    QueryResult += content;
                    if (AgolQuery.Key == ArcGISOnlineQueries.AGSQueryType.GetSelf)
                    {
                        _AgolUser = AgolUser.LoadAgolUser(content);
                    }
                    else if (AgolQuery.Key == ArcGISOnlineQueries.AGSQueryType.GetSearch)
                    {
                        _AgolSearchResult = AgolSearchResult.LoadAgolSearchResult(content);
                    }
                    else if (AgolQuery.Key == ArcGISOnlineQueries.AGSQueryType.GetUserContent)
                    {
                        _AgolUserContent = AgolUserContent.LoadAgolUserContent(content);
                        _AgolFolderContent = null;
                    }
                    else if (AgolQuery.Key == ArcGISOnlineQueries.AGSQueryType.GetUserContentForFolder)
                    {
                        _AgolFolderContent = AgolFolderContent.LoadAgolFolderContent(content);
                    }
                    System.Diagnostics.Debug.WriteLine(QueryResult);
                }
            }
            catch (Exception ex)
            {
                QueryResult = ex.ToString();
            }
        }
        /// <summary>
        /// Post "publish" request on the portal item
        /// </summary>
        /// <param name="baseURI"></param>
        /// <param name="username"></param>
        /// <param name="itemId"></param>
        /// <param name="filetype"></param>
        /// <param name="publishParameters"></param>
        /// <returns></returns>
        Tuple<bool, string> publishService(string baseURI, string username, string itemId, string filetype, string publishParameters)
        {
            EsriHttpClient myClient = new EsriHttpClient();
            string requestUrl = baseURI + @"/sharing/rest/content/users/" + username + @"/publish";

            var postData = new List<KeyValuePair<string, string>>();
            postData.Add(new KeyValuePair<string, string>("f", "json"));
            postData.Add(new KeyValuePair<string, string>("itemId", itemId));
            postData.Add(new KeyValuePair<string, string>("filetype", filetype));
            postData.Add(new KeyValuePair<string, string>("publishParameters", publishParameters));
            HttpContent content = new FormUrlEncodedContent(postData);

            EsriHttpResponseMessage respMsg = myClient.Post(requestUrl, content);
            if(respMsg==null)
                return new Tuple<bool, String>(false, "HTTP response is null");

            string outStr = respMsg.Content.ReadAsStringAsync().Result;
            //Deserialize the response in JSON into a usable object. 
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            //Deserialize the response in JSON into a usable object. 
            PublishedServices obj = (PublishedServices)serializer.Deserialize(outStr, typeof(PublishedServices));
            if (obj == null)
                return new Tuple<bool, String>(false, "Service creation fails - " + outStr);

            string respReturn = "";
            foreach (PublishedService ps in obj.services)
                respReturn += ps.serviceurl;
            if (respReturn == "")
                return new Tuple<bool, String>(false, "Service creation fails - " + outStr);
            else
                return new Tuple<bool, String>(true, respReturn);

        }
        private async Task<string> QueryImpl()
        {
            // Create EsriHttpClient object
            var httpClient = new EsriHttpClient();

            // Make a self call to extract the signed on username for now. 
            // Coming soon - An API which will give you the the signed on username for a portal
            var selfUrl = new UriBuilder(PortalManager.GetActivePortal())
            {
                Path = "sharing/rest/portals/self",
                Query = "f=json"
            };

            EsriHttpResponseMessage response = httpClient.Get(selfUrl.Uri.ToString());

            dynamic portalSelf = JObject.Parse(await response.Content.ReadAsStringAsync());
            // if the response doesn't contain the user information then it is essentially
            // an anonymous request against the portal
            if (portalSelf.user == null)
                return "Unable to get current user from portal";

            string userName = portalSelf.user.username;
            string query = [email protected]"q=owner:{userName} tags:""UploadVtpkToAgol Demo"" type:""Vector Tile Service"" ";

            // Once uploaded make another REST call to search for the uploaded data
            var searchUrl = new UriBuilder(PortalManager.GetActivePortal())
            {
                Path = "sharing/rest/search",
                Query = [email protected]"{query}&f=json"
            };

            var searchResults = httpClient.Get(searchUrl.Uri.ToString());

            dynamic resultItems = JObject.Parse(await searchResults.Content.ReadAsStringAsync());

            long numberOfTotalItems = resultItems.total.Value;

            if (numberOfTotalItems == 0)
                return [email protected]"Unable to find uploaded item with query: {query}";

            var resultItemList = new List<dynamic>();
            resultItemList.AddRange(resultItems.results);
            //get the first result
            dynamic item = resultItemList[0];

            // Create an item from the search results

            string itemId = item.id;
            var currentItem = ItemFactory.Create(itemId, ItemFactory.ItemType.PortalItem);

            // Finally add the feature service to the map
            // if we have an item that can be turned into a layer
            // add it to the map
            if (LayerFactory.CanCreateLayerFrom(currentItem))
                LayerFactory.CreateLayer(currentItem, MapView.Active.Map);
            return [email protected]"Downloaded this item: {item.name} [Type: {item.type}] to ArcGIS Online and added the item to the Map";
        }
        /// <summary>
        /// Post "analyze" request on the portal item
        /// </summary>
        /// <param name="baseURI"></param>
        /// <param name="itemId"></param>
        /// <param name="filetype"></param>
        /// <param name="analyzeParameters"></param>
        /// <returns></returns>
        Tuple<bool, string> analyzeService(string baseURI, string itemId, string filetype, string analyzeParameters)
        {
            EsriHttpClient myClient = new EsriHttpClient();
            string requestUrl = baseURI + @"/sharing/rest/content/features/analyze";

            var postData = new List<KeyValuePair<string, string>>();
            postData.Add(new KeyValuePair<string, string>("f", "json"));
            postData.Add(new KeyValuePair<string, string>("itemId", itemId));
            postData.Add(new KeyValuePair<string, string>("filetype", filetype));
            postData.Add(new KeyValuePair<string, string>("analyzeParameters", analyzeParameters));
            HttpContent content = new FormUrlEncodedContent(postData);

            EsriHttpResponseMessage respMsg = myClient.Post(requestUrl, content);
            if (respMsg == null)
                return new Tuple<bool, String>(false, "HTTP response is null");

            string outStr = respMsg.Content.ReadAsStringAsync().Result;
            //Deserialize the response in JSON into a usable object. 
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            //Deserialize the response in JSON into a usable object. 
            AnalyzedService obj = (AnalyzedService)serializer.Deserialize(outStr, typeof(AnalyzedService));
            if (obj == null)
                return new Tuple<bool, String>(false, "Service fails to be analyzed - " + outStr);
            if (obj.publishParameters != null)
            {
                string respReturn = SerializeToString(obj.publishParameters);
                if (respReturn == "")
                    return new Tuple<bool, String>(false, "Service fails to be analyzed - " + outStr);
                else
                    return new Tuple<bool, String>(true, respReturn);
            }
            return new Tuple<bool, String>(false, "Service fails to be analyzed - " + outStr);
        }
        /// <summary>
        /// Check if the service name is already in use
        /// </summary>
        /// <param name="baseURI"></param>
        /// <param name="serviceName"></param>
        /// <param name="serviceType"></param>
        /// <returns></returns>
        Tuple<bool, string> isServiceNameAvailable(string baseURI, string serviceName, string serviceType)
        {
            EsriHttpClient myClient = new EsriHttpClient();

            #region REST call to get appInfo.Item.id and user.lastLogin of the licensing portal
            string selfUri = @"/sharing/rest/portals/self?f=json";
            var selfResponse = myClient.Get(baseURI + selfUri);
            if (selfResponse == null)
                return new Tuple<bool, String>(false, "HTTP response is null");

            string outStr = selfResponse.Content.ReadAsStringAsync().Result;

            //Deserialize the response in JSON into a usable object. 
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            PortalSelf self_obj = (PortalSelf)serializer.Deserialize(outStr, typeof(PortalSelf));
            if ((self_obj == null) || (self_obj.id == null))
            {
                return new Tuple<bool, String>(false, "Failed portal self call");
            }
            #endregion

            string requestUrl = baseURI + @"/sharing/rest/portals/" + self_obj.id + @"/isServiceNameAvailable";
            requestUrl += "?f=json&type=" + serviceType + "&name=" + serviceName;

            EsriHttpResponseMessage respMsg = myClient.Get(requestUrl);
            if (respMsg == null)
                return new Tuple<bool, String>(false, "HTTP response is null");

            outStr = respMsg.Content.ReadAsStringAsync().Result;
            //Deserialize the response in JSON into a usable object. 
            AvailableResult obj = (AvailableResult)serializer.Deserialize(outStr, typeof(AvailableResult));
            if (obj == null)
                return new Tuple<bool, String>(false, "Service fails to be analyzed - " + outStr);
            return new Tuple<bool, string> (obj.available, outStr);
        }
        /// <summary>
        /// Gets the item title/name based on its item ID
        /// </summary>
        /// <param name="baseURI"></param>
        /// <param name="username"></param>
        /// <param name="itemId"></param>
        /// <returns></returns>
        Tuple<bool, string> getServiceName(string baseURI, string username, string itemId)
        {
            EsriHttpClient myClient = new EsriHttpClient();

            #region REST call to get service name
            string requestUrl = baseURI + @"/sharing/rest/content/users/" + username + @"/items/" + itemId + "?f=json";
            var response = myClient.Get(requestUrl);
            if (response == null)
                return new Tuple<bool, String>(false, "HTTP response is null");

            string outStr = response.Content.ReadAsStringAsync().Result;

            //Deserialize the response in JSON into a usable object. 
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            OnlineItem obj = (OnlineItem)serializer.Deserialize(outStr, typeof(OnlineItem));
            if (obj == null || obj.item.title == null)
            {
                return new Tuple<bool, String>(false, "Failed item call");
            }
            return new Tuple<bool, String>(true, obj.item.title);
            #endregion
        }
        /// <summary>
        /// Search for item in the active portal or the portal URL specified.
        /// Returns itemdID or null if item not found.
        /// </summary>
        /// <param name="itemName">Item Name as a string</param>
        /// <param name="itemType">Item TYpe as a string. Use types used by AGO/portal</param>
        /// <param name="portalURL">PortalURL as a string. Optional. When specified, searchs in that URL, else under active portal</param>
        /// <returns>PortalItem. Null if item was not found</returns>
        public static Tuple<bool, SDCItem> SearchPortalItemREST(string @itemName, string itemType, string portalURL)
        {
            //string extension = System.IO.Path.GetExtension(@itemName);
            //@itemName = @itemName.Substring(0, @itemName.Length - extension.Length);

            try
            {
                #region Construct and make REST query
                if (!portalURL.EndsWith("/"))
                    portalURL += "/";

                string queryURL = portalURL + @"sharing/rest/search?q=" + @itemName + " AND type:" + itemType + "&f=json";
                EsriHttpClient myClient = new EsriHttpClient();
                var response = myClient.Get(queryURL);
                if (response == null)
                    return new Tuple<bool, SDCItem>(false, null);

                string outStr = response.Content.ReadAsStringAsync().Result;
                JavaScriptSerializer serializer = new JavaScriptSerializer();
                SearchResult sr = (SearchResult)serializer.Deserialize(outStr, typeof(SearchResult));
                #endregion

                #region Get ItemID from search result, rerun the search for the item and return the full item
                if (sr != null)
                {
                    while (sr.nextStart <= sr.total)
                    {
                        for (int i = 0; i < sr.results.Count; i++)
                        {
                            //string srID = sr.results[i].id; //Technically, only one item with a particular name and type can exist
                            //string itemQueryURL = portalURL + @"sharing/rest/content/items/" + srID + "?f=json&token=" + pToken;
                            //SDCItem resultItem = (SDCItem)RESTcaller(itemQueryURL, typeof(SDCItem));
                            //if ((resultItem.title == itemName) && (resultItem.type == itemType))
                            //    return resultItem;
                            if ((sr.results[i].name == itemName) && (sr.results[i].type.Contains(itemType)))
                                return new Tuple<bool, SDCItem>(true, sr.results[i]);
                        }
                        if (sr.nextStart <= 0)
                            return new Tuple<bool, SDCItem>(false, null);

                        #region prepare for the enxt batch of search results
                        queryURL = portalURL + @"sharing/rest/search?q=" + itemName + " AND type:" + itemType + "&f=json&start=" + sr.nextStart;
                        response = myClient.Get(queryURL);
                        if (response == null)
                            return new Tuple<bool, SDCItem>(false, null);
                        outStr = response.Content.ReadAsStringAsync().Result;
                        sr = (SearchResult)serializer.Deserialize(outStr, typeof(SearchResult));
                        #endregion
                    }
                    return new Tuple<bool, SDCItem>(false, null);
                }
                else
                    return new Tuple<bool, SDCItem>(false, null);
                #endregion
            }
            catch (Exception exRESTsearch)
            {
                Console.WriteLine("Exception occurred when search for item through REST call. Exception: " + exRESTsearch.ToString());
                return null;
            }
        }
   /// <summary>
   /// Uploads a local item to online with its parameters
   /// </summary>
   /// <param name="baseURI"></param>
   /// <param name="itemPathStr"></param>
   /// <param name="thumbnail"></param>
   /// <param name="tags"></param>
   /// <returns></returns>
   Tuple<bool, string> uploadItem(string baseURI, string itemPathStr, string thumbnail, String tags)
   {
       String[] tags_arr = tags.Split(new Char[] { ',', ':', '\t' });
 
       EsriHttpClient myClient = new EsriHttpClient();
       Tuple<bool, string> response = null;
       Item itemToUpload = ItemFactory.Create(itemPathStr);
       if (itemToUpload != null)
       {
           response = myClient.Upload(baseURI, itemToUpload, thumbnail, tags_arr);
           if (response.Item1)
           {
               Tuple<bool, SDCItem> result = SearchPortalItemREST(itemToUpload.Name, itemToUpload.Type, baseURI);
               if(result.Item1)
                   return new Tuple<bool, string>(true, result.Item2.id);
               else
                   return new Tuple<bool, string>(true,"Cannot find item online");
           }
           else
               return new Tuple<bool, String>(false, "Upload fails - " + response.Item2);
       }else
           return new Tuple<bool, String>(false, "Null item cannot be uploaded - " + response.Item2);
   }