/// <summary>
        /// Checks the access an account has with an organization..
        /// </summary>
        /// <param name="name">The organization name.</param>
        /// <param name="accountId">The account identifier.</param>
        /// <param name="allowAdmin">if set to <c>true</c> allow admin.</param>
        /// <param name="allowWrite">if set to <c>true</c> allow write.</param>
        /// <param name="allowRead">if set to <c>true</c> allow read.</param>
        public void CheckAccess(
            DomainLabel name,
            EmailAddress accountId,
            out bool allowAdmin,
            out bool allowWrite,
            out bool allowRead)
        {
            allowAdmin = false;
            allowWrite = false;
            allowRead = false;

            if (name == null)
            {
                throw new ArgumentNullException("name");
            }

            if (accountId == null)
            {
                throw new ArgumentNullException("accountId");
            }

            CloudTable orgMemberTable = this.GetOrganizationMembershipTable();
            TableOperation getOrgMember = TableOperation.Retrieve<OrganizationMembershipEntity>(
                name.ToString(),
                accountId.ToString());
            TableResult result = orgMemberTable.Execute(getOrgMember);
            OrganizationMembershipEntity entity = result.Result as OrganizationMembershipEntity;
            if (entity != null)
            {
                allowRead = true;
                allowWrite = entity.AllowWrite;
                allowAdmin = entity.AllowAdmin;
            }
        }
        /// <summary>
        /// Authorizes the application.
        /// </summary>
        /// <param name="accountId">The account identifier.</param>
        /// <param name="applicationName">Name of the application.</param>
        public void AuthorizeApplication(EmailAddress accountId, DomainLabel applicationName)
        {
            if (accountId == null)
            {
                throw new ArgumentNullException("accountId");
            }

            if (applicationName == null)
            {
                throw new ArgumentNullException("applicationName");
            }

            CloudTable authorizeTable = this.GetAuthorizedApplicationsTable();
            AuthorizedApplicationEntity entity = new AuthorizedApplicationEntity(
                accountId.ToString(),
                applicationName.ToString());

            TableOperation op = TableOperation.InsertOrMerge(entity);
            authorizeTable.Execute(op);
        }
        /// <summary>
        /// Creates an application.
        /// </summary>
        /// <param name="name">The name of the application.</param>
        /// <param name="friendlyName">The friendly name of the application.</param>
        /// <param name="organizationName">The organization that owns the application.</param>
        /// <param name="clientId">the client id.</param>
        /// <param name="clientSecret">the client secret.</param>
        /// <param name="homePageUrl">The home page URL.</param>
        /// <param name="authorizationCallbackUrl">The authorization callback URL.</param>
        /// <param name="accountId">The user creating the application.</param>
        /// <remarks>
        /// This call assumes the user has been already authorized to create the application.
        /// </remarks>
        public void CreateApplication(
            DomainLabel name,
            string friendlyName,
            DomainLabel organizationName,
            string clientId,
            string clientSecret,
            Uri homePageUrl,
            Uri authorizationCallbackUrl,
            EmailAddress accountId)
        {
            if (!ValidateApplicationName(name))
            {
                throw new ArgumentOutOfRangeException("name");
            }

            if (string.IsNullOrWhiteSpace(friendlyName))
            {
                throw new ArgumentOutOfRangeException("friendlyName");
            }

            if (organizationName == null)
            {
                throw new ArgumentNullException("organizationName");
            }

            if (accountId == null)
            {
                throw new ArgumentNullException("accountId");
            }

            if (string.IsNullOrWhiteSpace(clientId))
            {
                throw new ArgumentOutOfRangeException("clientId");
            }

            if (string.IsNullOrWhiteSpace(clientSecret))
            {
                throw new ArgumentOutOfRangeException("clientSecret");
            }

            if (homePageUrl == null)
            {
                throw new ArgumentNullException("homePageUrl");
            }

            if (authorizationCallbackUrl == null)
            {
                throw new ArgumentNullException("authorizationCallbackUrl");
            }

            CloudTable appTable = this.GetApplicationTable();
            CloudTable appByClientIdTable = this.GetApplicationNameByClientIdTable();
            CloudTable orgAppsTable = this.GetOrganizationApplicationsTable();
            if (FindExistingApplication(appTable, name.ToString()) != null)
            {
                throw new InvalidOperationException("Application already exists.");
            }

            ApplicationEntity appEntity = new ApplicationEntity(name.ToString())
            {
                FriendlyName = friendlyName,
                OrganizationId = organizationName.ToString(),
                ClientId = clientId,
                ClientSecret = clientSecret,
                CreatedByAccountId = accountId.ToString(),
                CreatedTime = DateTime.UtcNow,
                HomePageUrl = homePageUrl.ToString(),
                AuthorizationCallbackUrl = authorizationCallbackUrl.ToString()
            };

            appEntity.LastModifiedByAccountId = appEntity.CreatedByAccountId;
            appEntity.LastModifiedTime = appEntity.CreatedTime;

            OrganizationApplicationEntity orgAppEntity = new OrganizationApplicationEntity(
                organizationName.ToString(),
                name.ToString());

            ApplicationNameByClientIdEntity appByClientIdEntity = new ApplicationNameByClientIdEntity(
                clientId)
                {
                    ApplicationName = name.ToString()
                };

            TableOperation insertAppByClientId = TableOperation.InsertOrMerge(appByClientIdEntity);
            appByClientIdTable.Execute(insertAppByClientId);

            TableOperation insertOrgApp = TableOperation.InsertOrMerge(orgAppEntity);
            orgAppsTable.Execute(insertOrgApp);

            TableOperation insertApp = TableOperation.Insert(appEntity);
            appTable.Execute(insertApp);
        }
        /// <summary>
        /// Validates the format and length of the name.
        /// </summary>
        /// <param name="name">the name to validate.</param>
        /// <returns>whether or not the name is a valid name.</returns>
        private static bool ValidateApplicationName(DomainLabel name)
        {
            if (name == null)
            {
                return false;
            }

            if (name.ToString().Length > MaxNameLength)
            {
                return false;
            }

            return true;
        }
        /// <summary>
        /// Determines whether is application authorized by the specified account identifier.
        /// </summary>
        /// <param name="accountId">The account identifier.</param>
        /// <param name="applicationName">Name of the application.</param>
        /// <returns>Whether the user has authorized the application.</returns>
        public bool IsApplicationAuthorized(EmailAddress accountId, DomainLabel applicationName)
        {
            if (accountId == null)
            {
                throw new ArgumentNullException("accountId");
            }

            if (applicationName == null)
            {
                throw new ArgumentNullException("applicationName");
            }

            CloudTable authorizeTable = this.GetAuthorizedApplicationsTable();
            TableOperation op = TableOperation.Retrieve<AuthorizedApplicationEntity>(
                accountId.ToString(),
                applicationName.ToString());
            TableResult result = authorizeTable.Execute(op);
            return (result.Result as AuthorizedApplicationEntity) != null;
        }
        /// <summary>
        /// Gets the applications of the given organization.
        /// </summary>
        /// <param name="organizationName">Name of the organization.</param>
        /// <returns>List of application records.</returns>
        public IEnumerable<OrganizationApplicationInfo> GetApplicationsOfOrganization(
            DomainLabel organizationName)
        {
            if (organizationName == null)
            {
                throw new ArgumentNullException("organizationName");
            }

            CloudTable appTable = this.GetApplicationTable();
            CloudTable orgAppsTable = this.GetOrganizationApplicationsTable();
            TableQuery<OrganizationApplicationEntity> orgAppsQuery =
                new TableQuery<OrganizationApplicationEntity>().Where(
                    TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, organizationName.ToString()));
            List<string> appNames = new List<string>();
            foreach (OrganizationApplicationEntity accountMember in orgAppsTable.ExecuteQuery(orgAppsQuery))
            {
                appNames.Add(accountMember.RowKey);
            }

            List<OrganizationApplicationInfo> results = new List<OrganizationApplicationInfo>();
            foreach (string appName in appNames)
            {
                TableOperation getApp = TableOperation.Retrieve<ApplicationEntity>(appName, string.Empty);
                TableResult getAppResult = appTable.Execute(getApp);
                ApplicationEntity app = getAppResult.Result as ApplicationEntity;
                if (app != null)
                {
                    results.Add(new OrganizationApplicationInfo
                        {
                            ApplicationName = DomainLabel.Parse(app.PartitionKey),
                            FriendlyName = app.FriendlyName
                        });
                }
            }

            return results;
        }
        /// <summary>
        /// Gets the application.
        /// </summary>
        /// <param name="applicationName">Name of the application.</param>
        /// <returns>application info.</returns>
        /// <remarks>
        /// This assumes the caller will filter results for what a user is authorized to do.
        /// </remarks>
        public ApplicationInfo GetApplication(DomainLabel applicationName)
        {
            if (applicationName == null)
            {
                throw new ArgumentNullException("applicationName");
            }

            CloudTable appTable = this.GetApplicationTable();
            ApplicationEntity entity = FindExistingApplication(appTable, applicationName.ToString());
            if (entity == null)
            {
                return null;
            }

            return new ApplicationInfo
            {
                Name = applicationName,
                FriendlyName = entity.FriendlyName,
                OrganizationName = DomainLabel.Parse(entity.OrganizationId),
                ClientId = entity.ClientId,
                ClientSecret = entity.ClientSecret,
                HomePageUrl = new Uri(entity.HomePageUrl),
                AuthorizationCallbackUrl = new Uri(entity.AuthorizationCallbackUrl)
            };
        }
        /// <summary>
        /// Computes the bytes.
        /// </summary>
        /// <param name="accountId">The account identifier.</param>
        /// <param name="applicationName">Name of the application.</param>
        /// <param name="expires">The expires.</param>
        /// <returns>the body of the token.</returns>
        private static byte[] ComputeBytes(
            EmailAddress accountId, 
            DomainLabel applicationName, 
            DateTime expires)
        {
            byte[] encodedAccountId = Encoding.UTF8.GetBytes(accountId.ToString());
            byte[] encodedAppName = Encoding.UTF8.GetBytes(applicationName.ToString());
            byte[] raw = new byte[encodedAccountId.Length + encodedAppName.Length + 2 + SizeOfLong];
            Array.Copy(encodedAccountId, 0, raw, 0, encodedAccountId.Length);
            raw[encodedAccountId.Length] = 0;
            Array.Copy(encodedAppName, 0, raw, encodedAccountId.Length + 1, encodedAppName.Length);
            raw[encodedAccountId.Length + encodedAppName.Length + 1] = 0;
            long expiresBinary = expires.ToBinary();
            for (int i = 0; i < SizeOfLong; i++)
            {
                byte value = unchecked((byte)(expiresBinary >> (8 * i)));
                raw[encodedAccountId.Length + encodedAppName.Length + 2 + i] = value;
            }

            return raw;
        }
        /// <summary>
        /// Gets info about the members of an organization.
        /// </summary>
        /// <param name="name">the name of the organization.</param>
        /// <returns>A list of membership info.</returns>
        public IEnumerable<OrganizationMembershipInfo> GetOrganizationMemberships(
            DomainLabel name)
        {
            CloudTable orgMemberTable = this.GetOrganizationMembershipTable();
            TableQuery<OrganizationMembershipEntity> accountMemberQuery =
                new TableQuery<OrganizationMembershipEntity>().Where(
                    TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, name.ToString()));
            List<OrganizationMembershipInfo> result = new List<OrganizationMembershipInfo>();
            foreach (OrganizationMembershipEntity entity in orgMemberTable.ExecuteQuery(accountMemberQuery))
            {
                OrganizationMembershipInfo info = new OrganizationMembershipInfo
                {
                    AccountId = EmailAddress.Parse(entity.RowKey),
                    AllowAdmin = entity.AllowAdmin,
                    AllowWrite = entity.AllowWrite
                };

                result.Add(info);
            }

            return result;
        }
        /// <summary>
        /// Gets information about an organization on behalf of a given account id.
        /// </summary>
        /// <param name="name">name of the organization.</param>
        /// <returns>organization info or null if the organization does not exist.</returns>
        public OrganizationInfo GetOrganization(
            DomainLabel name)
        {
            CloudTable orgTable = this.GetOrganizationTable();
            OrganizationEntity orgEntity = FindExistingOrganization(orgTable, name.ToString());
            if (orgEntity == null)
            {
                return null;
            }

            return new OrganizationInfo
            {
                Name = name,
                FriendlyName = orgEntity.FriendlyName,
                CreatedBy = EmailAddress.Parse(orgEntity.CreatedByAccountId),
                CreatedTime = orgEntity.CreatedTime,
                LastModifiedBy = EmailAddress.Parse(orgEntity.LastModifiedByAccountId),
                LastModifiedTime = orgEntity.LastModifiedTime
            };
        }
        /// <summary>
        /// Creates a new organization.
        /// </summary>
        /// <param name="name">The name of the organization.</param>
        /// <param name="friendlyName">the friendly name.</param>
        /// <param name="accountId">the account creating the organization who will be an admin.</param>
        public void CreateOrganization(
            DomainLabel name,
            string friendlyName,
            EmailAddress accountId)
        {
            if (!ValidateOrganizationName(name))
            {
                throw new ArgumentOutOfRangeException("name");
            }

            if (string.IsNullOrWhiteSpace(friendlyName))
            {
                throw new ArgumentOutOfRangeException("friendlyName");
            }

            if (accountId == null)
            {
                throw new ArgumentNullException("accountId");
            }

            CloudTable orgTable = this.GetOrganizationTable();
            CloudTable orgMemberTable = this.GetOrganizationMembershipTable();
            CloudTable accountMemberTable = this.GetAccountMembershipTable();
            OrganizationEntity existing = FindExistingOrganization(orgTable, name.ToString());
            if (existing != null)
            {
                throw new InvalidOperationException("Organization already exists.");
            }

            AccountMembershipEntity accountMember = new AccountMembershipEntity()
            {
                PartitionKey = accountId.ToString(),
                RowKey = name.ToString()
            };

            OrganizationMembershipEntity orgMember = new OrganizationMembershipEntity()
            {
                PartitionKey = name.ToString(),
                RowKey = accountId.ToString(),
                AllowAdmin = true,
                AllowWrite = true
            };

            OrganizationEntity org = new OrganizationEntity()
            {
                PartitionKey = name.ToString(),
                RowKey = string.Empty,
                FriendlyName = friendlyName,
                CreatedByAccountId = accountId.ToString(),
                CreatedTime = DateTime.UtcNow
            };

            org.LastModifiedByAccountId = org.CreatedByAccountId;
            org.LastModifiedTime = org.CreatedTime;

            TableOperation insertAccountMember = TableOperation.InsertOrReplace(accountMember);
            TableOperation insertOrgMember = TableOperation.InsertOrReplace(orgMember);
            TableOperation insertOrg = TableOperation.InsertOrReplace(org);
            accountMemberTable.Execute(insertAccountMember);
            orgMemberTable.Execute(insertOrgMember);
            orgTable.Execute(insertOrg);
        }