/// <summary>
 /// Generates the info hash section for HealthVault service
 /// web requests given the specified data beginning at the specified
 /// index.
 /// </summary>
 /// 
 /// <param name="buffer">
 /// An array of bytes representing the UTF8 encoded data.
 /// </param>
 /// 
 /// <param name="index">
 /// An integer representing the starting location in the byte array.
 /// </param>
 /// 
 /// <param name="count">
 /// An integer representing the count of bytes.
 /// </param>
 /// 
 /// <returns>
 /// A string representing the info hash.
 /// </returns>
 /// 
 internal static string CreateInfoHash(Byte[] buffer, int index, int count)
 {
     CryptoHash hash = new CryptoHash();
     hash.ComputeHash(buffer, index, count);
     return hash.Finalize().GetXml();
 }
        /// <summary>
        /// 
        /// </summary>
        /// 
        /// <param name="appId"></param>
        /// <param name="ticket"></param>
        /// <param name="sharedSecret"></param>
        /// 
        /// <param name="isMra">
        /// True if the application is a multi-record application, or false otherwise. Multi-record
        /// applications can work with many user records at one time and does not rely on the
        /// selected record when performing operations.
        /// </param>
        /// 
        /// <param name="isPersistent">
        /// True if creating a persistent token, or false otherwise.  Persistent connections
        /// remain valid for the duration specified in the application's configuration within
        /// HealthVault.  Typically, persistent tokens are valid for up to one year.
        /// </param>
        /// 
        /// <param name="cancelTrigger"></param>
        /// <param name="shellUrl"></param>
        /// 
        /// <returns></returns>
        /// 
        /// <exception cref ="HealthServiceException">
        /// If the request results in an error being returned from the Shell.  The 
        /// <see cref="HealthServiceException.ErrorCode"/> can give more details about the error
        /// that occurred.
        /// </exception>
        /// 
        /// <exception cref="HealthRecordAuthorizationRequiredException">
        /// If the user could not be logged in because they have not authorized the application to
        /// a health record. The application should direct the user to the APPAUTH target of the
        /// Shell.
        /// </exception>
        /// 
        /// <exception cref="HealthRecordAuthorizationNotPossible">
        /// If the user does not have access to a health record that meets the minimum authorization
        /// requirements of the application. The user will need to request more access from the 
        /// custodian to use this application.
        /// </exception>
        /// 
        /// <exception cref="HealthRecordReauthorizationRequired">
        /// If the user had authorized a health record for this application but the application
        /// changed its required base authorizations such that the user must reauthorize the
        /// application. The application should direct the user to the APPAUTH target of the Shell.
        /// </exception>
        /// 
        private static string VerifyTicketWithShell(
            Guid appId,
            string ticket,
            CryptoHash sharedSecret,
            bool isMra,
            bool isPersistent,
            ManualResetEvent cancelTrigger,
            Uri shellUrl)
        {
            ShellResponseHandler handler = new ShellResponseHandler();
            EasyWebRequest request = new EasyWebRequest();
            request.ForceAsyncRequest = true;
            request.RequestCompressionMethod = String.Empty;

            if (cancelTrigger != null)
            {
                request.RequestCancelTrigger = cancelTrigger;
            }

            // Add the Authorization header for passport verification
            string ticketHeader =
                Convert.ToBase64String(
                    new UTF8Encoding().GetBytes("WLID1.0 t=" + ticket));
            request.Headers.Add(
                "LiveIdTicket",
                ticketHeader);

            // Add the shared secret header for creating the session token
            string sharedSecretHeader =
                Convert.ToBase64String(
                    new UTF8Encoding().GetBytes(sharedSecret.GetInfoXml()));
            request.Headers.Add(
                "SharedSecret",
                sharedSecretHeader);

            string authToken = null;
            try
            {
                Uri liveIdTicketVerifierUrl =
                    new Uri(
                        shellUrl,
                        "redirect.aspx?target=verifyliveid&targetqs=" +
                            HttpUtility.UrlEncode(
                                "?appid=" + appId + "&ismra=" + SDKHelper.XmlFromBool(isMra) +
                                "&persistwctoken=" + SDKHelper.XmlFromBool(isPersistent)));

                request.Fetch(liveIdTicketVerifierUrl,handler);

                ApplicationRecordAuthorizationAction action =
                    ApplicationRecordAuthorizationAction.Unknown;

                XmlReader infoReader = handler.Response.InfoReader;
                if (SDKHelper.ReadUntil(infoReader, "token"))
                {
                    if (infoReader.MoveToAttribute("app-record-auth-action"))
                    {
                        try
                        {
                            action =
                                (ApplicationRecordAuthorizationAction)Enum.Parse(
                                    typeof(ApplicationRecordAuthorizationAction),
                                    infoReader.Value);
                        }
                        catch (ArgumentException)
                        {
                        }
                    }
                }

                switch (action)
                {
                    case ApplicationRecordAuthorizationAction.NoActionRequired :
                        break;

                    case ApplicationRecordAuthorizationAction.AuthorizationRequired :
                        throw new HealthRecordAuthorizationRequiredException();

                    case ApplicationRecordAuthorizationAction.ReauthorizationNotPossible :
                        throw new HealthRecordAuthorizationNotPossible();

                    case ApplicationRecordAuthorizationAction.ReauthorizationRequired :
                        throw new HealthRecordReauthorizationRequired();

                    default :
                        throw new HealthServiceException(
                            HealthServiceStatusCode.RecordAuthorizationFailure);
                }

                infoReader.MoveToElement();
                authToken = infoReader.ReadElementContentAsString();
            }
            catch (WebException webException)
            {
                if (((HttpWebResponse)webException.Response).StatusCode ==
                    HttpStatusCode.Forbidden)
                {
                    throw new HealthServiceAccessDeniedException(
                        webException.Message,
                        webException);
                }
                throw;
            }
            finally
            {
                if (request != null)
                {
                    request.Dispose();
                    request = null;
                }
            }
            return authToken;
        }