internal virtual void ModifyQueryString(QueryStringBuilder qsb)
 {
     foreach (var query in QueryStringParameters)
     {
         qsb.Add(query.Key, query.Value);
     }
 }
        /// <summary>
        /// Returns change information for items at and below the specified item-id.
        /// </summary>
        /// <param name="rootItemReference"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public async Task <ODViewChangesResult> ViewChangesAsync(ODItemReference rootItemReference, ViewChangesOptions options)
        {
            if (!rootItemReference.IsValid())
            {
                throw new ArgumentException("rootItemReference was invalid. Requires either an ID or Path");
            }
            if (null == options)
            {
                throw new ArgumentNullException("options");
            }

            var queryParams = new QueryStringBuilder();

            options.ModifyQueryString(queryParams);

            Uri serviceUri = UriForItemReference(rootItemReference, ApiConstants.ViewChangesServiceAction, queryParams);
            var request    = await CreateHttpRequestAsync(serviceUri, ApiConstants.HttpGet);

            return(await DataModelForRequest <ODViewChangesResult>(request));
        }
        /// <summary>
        /// Return the URL for the service based on an item reference, navigation path (optional) and query string (optional)
        /// </summary>
        /// <param name="itemReference"></param>
        /// <param name="navigationPath"></param>
        /// <param name="queryString"></param>
        /// <returns></returns>
        private Uri UriForItemReference(ODItemReference itemReference, string navigationPath = null, QueryStringBuilder queryString = null)
        {
            // RootUrl = "https://api.onedrive.com/v1.0"
            StringBuilder url = new StringBuilder(RootUrl);

            if (!string.IsNullOrEmpty(itemReference.Id))
            {
                if (!string.IsNullOrEmpty(itemReference.DriveId))
                {
                    url.AppendFormat("/drives/{0}", itemReference.DriveId);
                }
                else
                {
                    url.AppendFormat("/drive");
                }

                url.AppendFormat("/items/{0}", itemReference.Id);
            }
            else if (!string.IsNullOrEmpty(itemReference.Path))
            {
                if (!itemReference.Path.StartsWith("/drive", StringComparison.Ordinal))
                {
                    throw new ArgumentException("Invalid ODItemReference: Path doesn't start with \"/drive\" or \"/drives\".");
                }

                url.Append(itemReference.Path);
                if (itemReference.Path.OccurrencesOfCharacter(':') == 1)
                {
                    // Make sure we terminate the path escape so we can add a navigation property if necessary
                    url.Append(":");
                }
            }
            else
            {
                // Just address the drive if both path & id are null.
                if (!string.IsNullOrEmpty(itemReference.DriveId))
                {
                    url.AppendFormat("/drives/{0}", itemReference.DriveId);
                }
                else
                {
                    url.AppendFormat("/drive");
                }
            }

            if (!string.IsNullOrEmpty(navigationPath))
            {
                if (url[url.Length - 1] != '/')
                {
                    url.AppendFormat("/");
                }
                url.Append(navigationPath);
            }

            UriBuilder builder = new UriBuilder(url.ToString());

            if (null != queryString && queryString.HasKeys)
            {
                builder.Query = queryString.ToString();
            }

#if DEBUG
            System.Diagnostics.Debug.WriteLine("URL: " + builder.Uri);
#endif
            return(builder.Uri);
        }
        private static Uri GetAuthenticationUri(string clientId)
        {
            var queryStringBuilder = new QueryStringBuilder();
            queryStringBuilder.Add("client_id", clientId);
            queryStringBuilder.Add("scope", string.Join(" ", (new [] { Scope.Basic, Scope.OfflineAccess, Scope.Signin, Scope.OneDriveReadWrite }).Select(s => s.GetDescription())));
            queryStringBuilder.Add("redirect_uri", LIVE_LOGIN_DESKTOP_URI);
            queryStringBuilder.Add("response_type", "code");
            queryStringBuilder.Add("display", "popup");

            return new UriBuilder(LIVE_LOGIN_AUTHORIZE_URI) { Query = queryStringBuilder.ToString() }.Uri;
        }
        private static async Task<string> PostQuery(string uriString, QueryStringBuilder queryStringBuilder)
        {
            HttpWebRequest httpWebRequest = WebRequest.CreateHttp(uriString);
            httpWebRequest.Method = "POST";
            httpWebRequest.ContentType = "application/x-www-form-urlencoded";
            var stream = await httpWebRequest.GetRequestStreamAsync();
            using (var writer = new StreamWriter(stream)) {
                await writer.WriteAsync(queryStringBuilder.ToString());
                await writer.FlushAsync();
            }

            var response = await httpWebRequest.GetResponseAsync() as HttpWebResponse;
            if (response != null && response.StatusCode == HttpStatusCode.OK) {
                using (var reader = new StreamReader(response.GetResponseStream())) {
                    return await reader.ReadToEndAsync();
                }
            }

            return null;
        }
        private static async Task<AppTokenResponse> RedeemRefreshTokenAsync(string clientId, string clientSecret, string refreshToken)
        {
            var queryStringBuilder = new QueryStringBuilder();
            queryStringBuilder.Add("client_id", clientId);
            queryStringBuilder.Add("redirect_uri", LIVE_LOGIN_DESKTOP_URI);
            queryStringBuilder.Add("client_secret", clientSecret);
            queryStringBuilder.Add("refresh_token", refreshToken);
            queryStringBuilder.Add("grant_type", "refresh_token");

            string response = await PostQuery(LIVE_LOGIN_TOKEN_URI, queryStringBuilder);

            return JsonConvert.DeserializeObject<AppTokenResponse>(response);
        }
        /// <summary>
        /// Returns change information for items at and below the specified item-id.
        /// </summary>
        /// <param name="rootItemReference"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public async Task<ODViewChangesResult> ViewChangesAsync(ODItemReference rootItemReference, ViewChangesOptions options)
        {
            if (!rootItemReference.IsValid())
                throw new ArgumentException("rootItemReference was invalid. Requires either an ID or Path");
            if (null == options)
                throw new ArgumentNullException("options");

            var queryParams = new QueryStringBuilder();
            options.ModifyQueryString(queryParams);

            Uri serviceUri = UriForItemReference(rootItemReference, ApiConstants.ViewChangesServiceAction, queryParams);
            var request = await CreateHttpRequestAsync(serviceUri, ApiConstants.HttpGet);

            return await DataModelForRequest<ODViewChangesResult>(request);
        }