text:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;

namespace XMedius.SendSecure
{
    public class Client
    {
        private static TraceSource TraceSource = new TraceSource("XMedius.SendSecure");

        private static readonly Uri DEFAULT_PORTAL_URI = new Uri("https://portal.xmedius.com");
        private static readonly string USER_TOKEN_PATH = "api/user_token";

        private string EnterpriseAccount;
        private string ApiToken;
        private Uri EndPoint;
        private int UserId;
        internal static JsonClient JsonClient;
        private string Locale;

        /// <summary>
        /// Client object constructor.
        /// </summary>
        /// <param name="jsonClient">An existing JsonClient</param>
        /// <param name="enterpriseAccount">The SendSecure enterprise account</param>
        /// <param name="endpoint">The URL to the SendSecure service</param>
        /// <param name="locale">The locale in which the server errors will be returned ("en" will be used by default if empty)</param>
        public Client(JsonClient jsonClient, string enterpriseAccount, Uri endpoint, string locale = "en")
        {
            EnterpriseAccount = enterpriseAccount;
            EndPoint = endpoint;
            Locale = locale;
            JsonClient = jsonClient;
        }

        /// <summary>
        /// Client object constructor.
        /// </summary>
        /// <param name="token">The API Token to be used for authentication with the SendSecure service</param>
        /// <param name="userId">The user id of the current user</param>
        /// <param name="enterpriseAccount">The SendSecure enterprise account</param>
        /// <param name="endpoint">The URL to the SendSecure service</param>
        /// <param name="locale">The locale in which the server errors will be returned ("en" will be used by default if empty)</param>
        public Client(string token, int userId, string enterpriseAccount, Uri endpoint, string locale = "en")
        {
            EnterpriseAccount = enterpriseAccount;
            ApiToken = token;
            UserId = userId;
            EndPoint = endpoint;
            Locale = locale;
            JsonClient = new JsonClient(ApiToken, UserId, EnterpriseAccount, EndPoint);
        }

        /// <summary>
        /// Gets an API Token for a specific user within a SendSecure enterprise account.
        /// </summary>
        /// <param name="enterpriseAccount">The SendSecure enterprise account</param>
        /// <param name="username">The username of a SendSecure user of the current enterprise account</param>
        /// <param name="password">The password of this user</param>
        /// <param name="deviceId">The unique ID of the device used to get the Token</param>
        /// <param name="deviceName">The name of the device used to get the Token</param>
        /// <param name="applicationType">The type/name of the application used to get the Token ("SendSecure C#" will be used by default if empty)</param>
        /// <param name="endpoint">The URL to the SendSecure service</param>
        /// <param name="oneTimePassword">The one-time password of this user (if any)</param>
        /// <param name="cancellationToken"></param>
        /// <returns>(API Token, user ID) to be used for the specified user</returns>
        public static async Task<JsonObjects.UserToken> GetUserTokenAsync(string enterpriseAccount, string username, string password, string deviceId,
            string deviceName, string applicationType = "SendSecure C#", Uri endpoint = null, string oneTimePassword = "",
            CancellationToken cancellationToken = default(CancellationToken))
        {
            if (endpoint == null)
            {
                endpoint = DEFAULT_PORTAL_URI;
            }

            try
            {
                string portalUrl = await Utils.SendSecureUrlUtil.GetPortalUrlForEnterpriseAccountAsync(enterpriseAccount, endpoint, cancellationToken);

                Uri resourceAddress = new Uri(new Uri(portalUrl), USER_TOKEN_PATH);

                var jsonRequest = new JsonObjects.GetTokenRequest
                {
                    permalink = enterpriseAccount,
                    username = username,
                    password = password,
                    application_type = applicationType,
                    device_id = deviceId,
                    device_name = deviceName,
                    otp = oneTimePassword
                };

                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, resourceAddress);
                StringContent jsonContent = new StringContent(JsonConvert.SerializeObject(jsonRequest), Encoding.UTF8, "application/json");
                request.Content = jsonContent;
                request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                string responseString = await Utils.HttpUtil.MakeRequestAsync(request, cancellationToken);

                var ResponseData = JsonConvert.DeserializeObject<JsonObjects.UserToken>(responseString);

                return ResponseData;
            }
            catch (Exceptions.MakeRequestException e)
            {
                if (e.StatusCode > 0)
                {
                    if (!String.IsNullOrEmpty(e.ResponseString))
                    {
                        try
                        {
                            var responseData = JsonConvert.DeserializeObject<JsonObjects.GetTokenResponseError>(e.ResponseString);
                            throw new Exceptions.SendSecureException(responseData.Code, e.ResponseString, responseData.Message);
                        }
                        catch (JsonException)
                        {
                        }
                    }

                    throw new Exceptions.SendSecureException((int)e.StatusCode, e.Message);
                }
                else
                {
                    throw new Exceptions.UnexpectedServerResponseException();
                }

            }
            catch (JsonSerializationException)
            {
                throw new Exceptions.UnexpectedServerResponseException();
            }
            catch (TaskCanceledException)
            {
                TraceSource.TraceEvent(TraceEventType.Information, 0, "GetUserToken Cancelled.");
                throw new OperationCanceledException();
            }
            catch (Exception e)
            {
                TraceSource.TraceEvent(TraceEventType.Error, 0,
                    "Unexpected exception in GetToken ({0})", e.Message);
                throw new Exceptions.SendSecureException(e.Message);
            }
        }

        /// <summary>
        /// This method is a high-level combo that initializes the SafeBox, uploads all attachments and commits the SafeBox.
        /// </summary>
        /// <param name="safebox">A non-initialized Safebox object with security profile, recipient(s), subject,
        ///                       message and attachments(not yet uploaded) already defined.</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The updated safebox</returns>
        public async Task<Helpers.Safebox> SubmitSafeboxAsync(Helpers.Safebox safebox, CancellationToken cancellationToken = default(CancellationToken))
        {
            await InitializeSafeboxAsync(safebox, cancellationToken);

            foreach (Helpers.Attachment attachment in safebox.Attachments)
            {
                await UploadAttachmentAsync(safebox, attachment, cancellationToken);
            }

            if (safebox.SecurityProfileId == null)
            {
                var SecurityProfile = await DefaultSecurityProfileAsync(safebox.UserEmail, cancellationToken);
                safebox.SecurityProfileId = SecurityProfile.Id;
                if (safebox.SecurityProfileId == null)
                {
                    throw new Exceptions.SendSecureException("No Security Profile is configured");
                }
            }

            return await CommitSafeboxAsync(safebox, cancellationToken);
        }

        /// <summary>
        /// Pre-creates a SafeBox on the SendSecure system and initializes the Safebox object accordingly.
        /// </summary>
        /// <param name="safebox">A SafeBox object to be finalized by the SendSecure system</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The updated SafeBox object with the necessary system parameters (GUID, public encryption key, upload URL) filled out</returns>
        public async Task<Helpers.Safebox> InitializeSafeboxAsync(Helpers.Safebox safebox, CancellationToken cancellationToken = default(CancellationToken))
        {
            string jsonResponse = await JsonClient.NewSafeboxAsync(safebox.UserEmail, cancellationToken);

            safebox.Update(jsonResponse);

            return safebox;
        }

        /// <summary>
        /// Uploads the specified file as an Attachment of the specified SafeBox.
        /// </summary>
        /// <param name="safebox">An initialized Safebox object</param>
        /// <param name="attachment">An Attachment object - the file to upload to the SendSecure system</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The updated Attachment object with the GUID parameter filled out</returns>
        public async Task<Helpers.Attachment> UploadAttachmentAsync(Helpers.Safebox safebox, Helpers.Attachment attachment, CancellationToken cancellationToken = default(CancellationToken))
        {
            string jsonResponse = await JsonClient.UploadFileAsync(new Uri(safebox.UploadUrl), attachment.Stream, attachment.ContentType, attachment.FileName, attachment.Size, cancellationToken);

            var response = JsonConvert.DeserializeObject<JsonObjects.UploadFileResponseSuccess>(jsonResponse);

            attachment.Guid = response.TemporaryDocument.DocumentGuid;

            return attachment;
        }

        /// <summary>
        /// This actually "Sends" the SafeBox with all content and contact info previously specified.
        /// </summary>
        /// <param name="safebox">A Safebox object already finalized, with security profile, recipient(s),
        ///                       subject and message already defined, and attachments already uploaded.</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The updated safebox</returns>
        public async Task<Helpers.Safebox> CommitSafeboxAsync(Helpers.Safebox safebox, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (safebox.Guid == null)
            {
                throw new Exceptions.SendSecureException("Safebox Guid cannot be null");
            }

            if (safebox.Participants.Count == 0)
            {
                throw new Exceptions.SendSecureException("Participants cannot be empty");
            }

            string jsonResponse = await JsonClient.CommitSafeboxAsync(safebox.ToJson(), cancellationToken);

            safebox.Update(jsonResponse);

            return safebox;
        }

        /// <summary>
        /// Retrieves all available security profiles of the enterprise account for a specific user.
        /// </summary>
        /// <param name="userEmail">The email address of a SendSecure user of the current enterprise account</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The list of all security profiles of the enterprise account, with all their setting values/properties</returns>
        public async Task<List<Helpers.SecurityProfile>> SecurityProfilesAsync(string userEmail, CancellationToken cancellationToken = default(CancellationToken))
        {
            string jsonResponse = await JsonClient.GetSecurityProfilesAsync(userEmail, cancellationToken);

            var response = JsonConvert.DeserializeObject<JsonObjects.SecurityProfilesResponseSuccess>(jsonResponse);

            return response.SecurityProfiles;
        }

        /// <summary>
        /// Retrieves the default security profile of the enterprise account for a specific user.
        /// A default security profile must have been set in the enterprise account, otherwise the method will return nothing.
        /// </summary>
        /// <param name="userEmail">The email address of a SendSecure user of the current enterprise account</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The default security profile of the enterprise, with all its setting values/properties</returns>
        public async Task<Helpers.SecurityProfile> DefaultSecurityProfileAsync(string userEmail, CancellationToken cancellationToken = default(CancellationToken))
        {
            var enterpriseSettings = await EnterpriseSettingsAsync(cancellationToken);
            var securityProfiles = await SecurityProfilesAsync(userEmail, cancellationToken);

            return securityProfiles.Find(x => x.Id == enterpriseSettings.DefaultSecurityProfileId);
        }

        /// <summary>
        /// Retrieves all the current enterprise account's settings specific to a SendSecure Account.
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns>All values/properties of the enterprise account's settings specific to SendSecure</returns>
        public async Task<Helpers.EnterpriseSettings> EnterpriseSettingsAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            string jsonResponse = await JsonClient.GetEnterpriseSettingsAsync(cancellationToken);

            return Helpers.EnterpriseSettings.FromJson(jsonResponse);
        }

        /// <summary>
        /// Retrieves all the current user account's settings specific to SendSecure Account.
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns>All values/properties of the user account's settings specific to SendSecure</returns>
        public async Task<Helpers.UserSettings> UserSettingsAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            string jsonResponse = await JsonClient.GetUserSettingsAsync(cancellationToken);

            return Helpers.UserSettings.FromJson(jsonResponse);
        }

        /// <summary>
        /// Retrieves all favorites associated to a specific user.
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns>The list of all favorites of the user account, with all their properties</returns>
        public async Task<List<Helpers.Favorite>> FavoritesAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            string jsonResponse = await JsonClient.GetFavoritesAsync(cancellationToken);

            var response = JsonConvert.DeserializeObject<JsonObjects.GetFavoritesResponseSuccess>(jsonResponse);

            return response.Favorites;
        }

        /// <summary>
        /// Creates a new favorite associated to a specific user.
        /// </summary>
        /// <param name="favorite">A Favorite object</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The updated Favorite</returns>
        public async Task<Helpers.Favorite> CreateFavoriteAsync(Helpers.Favorite favorite, CancellationToken cancellationToken = default(CancellationToken))
        {
            string jsonResponse = await JsonClient.CreateFavoriteAsync(favorite.UpdateFor<Helpers.Favorite.Creation>().ToJson(), cancellationToken);

            favorite.Update(jsonResponse);

            return favorite;
        }

        /// <summary>
        /// Update an existing favorite associated to a specific user.
        /// </summary>
        /// <param name="favorite">A Favorite object</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The updated Favorite</returns>
        public async Task<Helpers.Favorite> EditFavoriteAsync(Helpers.Favorite favorite, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (favorite.Id == null)
            {
                throw new Exceptions.SendSecureException("Favorite id cannot be null");
            }

            string jsonResponse = await JsonClient.EditFavoriteAsync(favorite.UpdateFor<Helpers.Favorite.Edition>().ToJson(), favorite.Id, cancellationToken);

            favorite.Update(jsonResponse);

            return favorite;
        }

        /// <summary>
        /// Delete contact methods of an existing favorite associated to a specific user.
        /// </summary>
        /// <param name="favorite">A Favorite object</param>
        /// <param name="contactMethodsIds">A list of contact methods ids</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The updated Favorite</returns>
        public async Task<Helpers.Favorite> DeleteFavoriteContactMethods(Helpers.Favorite favorite, List<int?> contactMethodsIds, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (favorite.Id == null)
            {
                throw new Exceptions.SendSecureException("Favorite id cannot be null");
            }

            string jsonResponse = await JsonClient.EditFavoriteAsync(favorite.UpdateFor<Helpers.Favorite.Destruction>().OfFollowingContacts(contactMethodsIds).ToJson(), favorite.Id, cancellationToken);

            favorite.Update(jsonResponse);

            return favorite;
        }

        /// <summary>
        /// Delete an existing favorite associated to a specific user.
        /// </summary>
        /// <param name="favorite">A Favorite object</param>
        /// <param name="cancellationToken"></param>
        /// <returns>Nothing</returns>
        public async Task<string> DeleteFavoriteAsync(Helpers.Favorite favorite, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (favorite.Id == null)
            {
                throw new Exceptions.SendSecureException("Favorite id cannot be null");
            }

            return await JsonClient.DeleteFavoriteAsync(favorite.Id, cancellationToken);
        }

        /// <summary>
        /// Create a new participant for a specific safebox associated to the current user's account,
        /// and add the new participant to the Safebox object.
        /// </summary>
        /// <param name="participant">A Participant object</param>
        /// <param name="safebox">A Safebox object</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The updated Participant</returns>
        public async Task<Helpers.Participant> CreateParticipantAsync(Helpers.Participant participant, Helpers.Safebox safebox, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (safebox.Guid == null)
            {
                throw new Exceptions.SendSecureException("Safebox Guid cannot be null");
            }

            if (participant.Email == null)
            {
                throw new Exceptions.SendSecureException("Participant email cannot be null");
            }

            string jsonResponse = await JsonClient.CreateParticipantAsync(participant.UpdateFor<Helpers.Participant.Creation>().ToJson(), safebox.Guid, cancellationToken);

            participant.Update(jsonResponse);
            safebox.Participants.Add(participant);

            return participant;
        }

        /// <summary>
        /// Update an existing participant of a specific safebox associated to the current user's account.
        /// </summary>
        /// <param name="participant">A Participant object</param>
        /// <param name="safebox">A Safebox object</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The updated Participant</returns>
        public async Task<Helpers.Participant> UpdateParticipantAsync(Helpers.Participant participant, Helpers.Safebox safebox, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (safebox.Guid == null)
            {
                throw new Exceptions.SendSecureException("Safebox Guid cannot be null");
            }

            if (participant.Id == null)
            {
                throw new Exceptions.SendSecureException("Participant Id cannot be null");
            }

            string jsonResponse = await JsonClient.UpdateParticipantAsync(participant.UpdateFor<Helpers.Participant.Edition>().ToJson(), safebox.Guid, participant.Id, cancellationToken);

            participant.Update(jsonResponse);

            return participant;
        }

        /// <summary>
        /// Delete contact methods of an existing participant of a specific safebox associated to the current user's account.
        /// </summary>
        /// <param name="participant">A Participant object</param>
        /// <param name="safebox">A Safebox object</param>
        /// <param name="contactMethodsIds">A list of contact method id</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The updated Participant</returns>
        public async Task<Helpers.Participant> DeleteParticipantContactMethods(Helpers.Participant participant, Helpers.Safebox safebox, List<int?> contactMethodsIds, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (safebox.Guid == null)
            {
                throw new Exceptions.SendSecureException("Safebox Guid cannot be null");
            }

            if (participant.Id == null)
            {
                throw new Exceptions.SendSecureException("Participant id cannot be null");
            }

            string jsonResponse = await JsonClient.UpdateParticipantAsync(participant.UpdateFor<Helpers.Participant.Destruction>().OfFollowingContacts(contactMethodsIds).ToJson(), safebox.Guid, participant.Id, cancellationToken);

            participant.Update(jsonResponse);

            return participant;
        }

        /// <summary>
        /// Search the recipients for a SafeBox
        /// </summary>
        /// <param name="term">A Search term</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The list of recipients that matches the search term</returns>
        public async Task<JsonObjects.SearchRecipientResponseSuccess> SearchRecipientAsync(string term, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (term == null)
            {
                throw new Exceptions.SendSecureException("Search term cannot be null");
            }

            string jsonResponse = await JsonClient.SearchRecipientAsync(term, cancellationToken);

            return JsonObjects.SearchRecipientResponseSuccess.FromJson(jsonResponse);
        }

        /// <summary>
        /// Add time to the expiration date of a specific safebox associated to the current user's account.
        /// </summary>
        /// <param name="safebox">A Safebox object</param>
        /// <param name="timeValue">Time value to be added to the expiration date</param>
        /// <param name="timeUnit">Time unit to be added to the expiration date</param>
        /// <param name="cancellationToken"></param>
        /// <returns>AddTimeResponseSuccess object containing the request result</returns>
        public async Task<JsonObjects.AddTimeResponseSuccess> AddTimeAsync(Helpers.Safebox safebox, int timeValue, Helpers.SecurityEnums.TimeUnit timeUnit, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (safebox.Guid == null)
            {
                throw new Exceptions.SendSecureException("Safebox Guid cannot be null");
            }

            var json = "{\"safebox\":{\"add_time_value\":" + timeValue + ",\"add_time_unit\":\"" + Helpers.SecurityEnums.TimeUnitToString(timeUnit) + "\"}}";
            string jsonResponse = await JsonClient.AddTimeAsync(json, safebox.Guid, cancellationToken);
            var response = JsonConvert.DeserializeObject<JsonObjects.AddTimeResponseSuccess>(jsonResponse);

            safebox.Expiration = response.NewExpiration;

            return response;
        }

        /// <summary>
        /// Close a specific safebox associated to the current user's account.
        /// </summary>
        /// <param name="safebox">A Safebox object</param>
        /// <param name="cancellationToken"></param>
        /// <returns>RequestResponse object containing the request result</returns>
        public async Task<JsonObjects.RequestResponse> CloseSafeboxAsync(Helpers.Safebox safebox, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (safebox.Guid == null)
            {
                throw new Exceptions.SendSecureException("Safebox Guid cannot be null");
            }

            string jsonResponse = await JsonClient.CloseSafeboxAsync(safebox.Guid, cancellationToken);

            return JsonObjects.RequestResponse.FromJson(jsonResponse);
        }

        /// <summary>
        /// Delete content of a specific safebox associated to the current user's account.
        /// </summary>
        /// <param name="safebox">A Safebox object</param>
        /// <param name="cancellationToken"></param>
        /// <returns>RequestResponse object containing the request result</returns>
        public async Task<JsonObjects.RequestResponse> DeleteSafeboxContentAsync(Helpers.Safebox safebox, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (safebox.Guid == null)
            {
                throw new Exceptions.SendSecureException("Safebox Guid cannot be null");
            }

            string jsonResponse = await JsonClient.DeleteSafeboxContentAsync(safebox.Guid, cancellationToken);

            return JsonObjects.RequestResponse.FromJson(jsonResponse);
        }

        /// <summary>
        /// Mark all messages as read of a specific safebox associated to the current user's account.
        /// </summary>
        /// <param name="safebox">A Safebox object</param>
        /// <param name="cancellationToken"></param>
        /// <returns>RequestResponse object containing the request result</returns>
        public async Task<JsonObjects.RequestResponse> MarkAsReadAsync(Helpers.Safebox safebox, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (safebox.Guid == null)
            {
                throw new Exceptions.SendSecureException("Safebox Guid cannot be null");
            }

            string jsonResponse = await JsonClient.MarkAsReadAsync(safebox.Guid, cancellationToken);

            return JsonObjects.RequestResponse.FromJson(jsonResponse);
        }

        /// <summary>
        /// Mark all messages as unread of a specific safebox associated to the current user's account.
        /// </summary>
        /// <param name="safebox">A Safebox object</param>
        /// <param name="cancellationToken"></param>
        /// <returns>RequestResponse object containing the request result</returns>
        public async Task<JsonObjects.RequestResponse> MarkAsUnreadAsync(Helpers.Safebox safebox, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (safebox.Guid == null)
            {
                throw new Exceptions.SendSecureException("Safebox Guid cannot be null");
            }

            string jsonResponse = await JsonClient.MarkAsUnreadAsync(safebox.Guid, cancellationToken);

            return JsonObjects.RequestResponse.FromJson(jsonResponse);
        }

        /// <summary>
        /// Mark a message as read of a specific safebox associated to the current user's account.
        /// </summary>
        /// <param name="safebox">A Safebox object</param>
        /// <param name="message">A Message object</param>
        /// <param name="cancellationToken"></param>
        /// <returns>RequestResponse object containing the request result</returns>
        public async Task<JsonObjects.RequestResponse> MarkAsReadMessageAsync(Helpers.Safebox safebox, Helpers.Message message, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (safebox.Guid == null)
            {
                throw new Exceptions.SendSecureException("Safebox Guid cannot be null");
            }

            if (message.Id == null)
            {
                throw new Exceptions.SendSecureException("Message Id cannot be null");
            }

            string jsonResponse = await JsonClient.MarkAsReadMessageAsync(safebox.Guid, message.Id, cancellationToken);

            return JsonObjects.RequestResponse.FromJson(jsonResponse);
        }

        /// <summary>
        /// Mark a message as unread of a specific safebox associated to the current user's account.
        /// </summary>
        /// <param name="safebox">A Safebox object</param>
        /// <param name="message">A Message object</param>
        /// <param name="cancellationToken"></param>
        /// <returns>RequestResponse object containing the request result</returns>
        public async Task<JsonObjects.RequestResponse> MarkAsUnreadMessageAsync(Helpers.Safebox safebox, Helpers.Message message, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (safebox.Guid == null)
            {
                throw new Exceptions.SendSecureException("Safebox Guid cannot be null");
            }

            if (message.Id == null)
            {
                throw new Exceptions.SendSecureException("Message Id cannot be null");
            }

            string jsonResponse = await JsonClient.MarkAsUnreadMessageAsync(safebox.Guid, message.Id, cancellationToken);

            return JsonObjects.RequestResponse.FromJson(jsonResponse);
        }

        /// <summary>
        /// Retrieve a specific file url of a specific safebox associated to the current user's account.
        /// </summary>
        /// <param name="safebox">A Safebox object</param>
        /// <param name="attachment">An Attachment object</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The file url</returns>
        public async Task<string> FileUrlAsync(Helpers.Safebox safebox, Helpers.Attachment attachment, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (safebox.Guid == null)
            {
                throw new Exceptions.SendSecureException("Safebox Guid cannot be null");
            }

            if (attachment.Guid == null)
            {
                throw new Exceptions.SendSecureException("Document Guid cannot be null");
            }

            string jsonResponse = await JsonClient.GetFileUrlAsync(safebox.Guid, attachment.Guid, safebox.UserEmail, cancellationToken);
            var response = JObject.Parse(jsonResponse);

            return response["url"].Value<string>();
        }

        /// <summary>
        /// Retrieve the audit record url of a specific safebox associated to the current user's account.
        /// </summary>
        /// <param name="safebox">A Safebox object</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The Audit Record Url</returns>
        public async Task<string> AuditRecordUrlAsync(Helpers.Safebox safebox, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (safebox.Guid == null)
            {
                throw new Exceptions.SendSecureException("Safebox Guid cannot be null");
            }

            string jsonResponse = await JsonClient.GetAuditRecordUrlAsync(safebox.Guid, cancellationToken);
            var response = JObject.Parse(jsonResponse);

            return response["url"].Value<string>();
        }

        /// <summary>
        /// Retrieve the audit record pdf of a specific safebox associated to the current user's account.
        /// </summary>
        /// <param name="safebox">A Safebox object</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The audit record pdf stream</returns>
        public async Task<string> AuditRecordPdfAsync(Helpers.Safebox safebox, CancellationToken cancellationToken = default(CancellationToken))
        {
            string url = await AuditRecordUrlAsync(safebox, cancellationToken);

            return await JsonClient.GetAuditRecordPdfAsync(url, cancellationToken);
        }

        /// <summary>
        /// Retrieve a filtered list of safeboxes for the current user account.
        /// </summary>
        /// <param name="status">Filter by SafeBox status [in_progress, closed, content_deleted, unread]</param>
        /// <param name="search">Search term in SafeBox subject and ID, message text, participant email, first name and last name, file name and fingerprint</param>
        /// <param name="per_page">Splits the list in several pages, with 0 < per_page <= 1000 (default is 100)</param>
        /// <param name="page">Selects the page to return</param>
        /// <param name="cancellationToken"></param>
        /// <returns>SafeboxesResponse containing the count, previous page url, the next page url and a list of Safebox</returns>
        public async Task<JsonObjects.SafeboxesResponse> SafeboxesAsync(Helpers.Safebox.Status status, string search, int per_page, int page, CancellationToken cancellationToken = default(CancellationToken))
        {
            string jsonResponse = await JsonClient.GetSafeboxesAsync(Helpers.Safebox.StatusToString(status), search, per_page, page, cancellationToken);
            var response = JObject.Parse(jsonResponse);

            var safeboxes = new JArray();
            foreach (JObject safebox in response["safeboxes"])
            {
                safeboxes.Add(safebox["safebox"]);
            }
            response["safeboxes"] = safeboxes;

            return JsonObjects.SafeboxesResponse.FromJson(response.ToString());
        }

        /// <summary>
        /// Retrieve the list of safeboxes for the current user account with an URL.
        /// </summary>
        /// <param name="url">The complete search url</param>
        /// <param name="cancellationToken"></param>
        /// <returns>SafeboxesResponse containing the count, previous page url, the next page url and a list of Safebox</returns>
        public async Task<JsonObjects.SafeboxesResponse> SafeboxesAsync(string url, CancellationToken cancellationToken = default(CancellationToken))
        {
            string jsonResponse = await JsonClient.GetSafeboxesAsync(url, cancellationToken);
            var response = JObject.Parse(jsonResponse);

            var safeboxes = new JArray();
            foreach (JObject safebox in response["safeboxes"])
            {
                safeboxes.Add(safebox["safebox"]);
            }
            response["safeboxes"] = safeboxes;

            return JsonObjects.SafeboxesResponse.FromJson(response.ToString());
        }

        /// <summary>
        /// Retrieve the list of safeboxes for the current user account.
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns>SafeboxesResponse containing the count, previous page url, the next page url and a list of Safebox</returns>
        public async Task<JsonObjects.SafeboxesResponse> SafeboxesAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            string jsonResponse = await JsonClient.GetSafeboxesAsync(cancellationToken);
            var response = JObject.Parse(jsonResponse);

            var safeboxes = new JArray();
            foreach (JObject safebox in response["safeboxes"])
            {
                safeboxes.Add(safebox["safebox"]);
            }
            response["safeboxes"] = safeboxes;

            return JsonObjects.SafeboxesResponse.FromJson(response.ToString());
        }

        /// <summary>
        /// Retrieve all info of an existing safebox for the current user account.
        /// </summary>
        /// <param name="safebox">A Safebox object</param>
        /// <param name="sections">The list of sections to be retrieved</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The updated safebox containing all the informations on the specified sections.
        ///          If no sections are specified, it will return all safebox infos.</returns>
        public async Task<Helpers.Safebox> SafeboxInfoAsync(Helpers.Safebox safebox, string[] sections, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (safebox.Guid == null)
            {
                throw new Exceptions.SendSecureException("Safebox Guid cannot be null");
            }

            string parameters = sections != null ? String.Join(",", sections) : "";
            string jsonResponse = await JsonClient.GetSafeboxInfoAsync(safebox.Guid, parameters, cancellationToken);
            var response = JObject.Parse(jsonResponse);

            safebox.Update(response["safebox"].ToString());

            return safebox;
        }

        /// <summary>
        /// Retrieve all participants info of an existing safebox for the current user account.
        /// </summary>
        /// <param name="safebox">A Safebox object</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The list of participants</returns>
        public async Task<List<Helpers.Participant>> ParticipantsAsync(Helpers.Safebox safebox, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (safebox.Guid == null)
            {
                throw new Exceptions.SendSecureException("Safebox Guid cannot be null");
            }

            string jsonResponse = await JsonClient.GetSafeboxParticipantsAsync(safebox.Guid, cancellationToken);

            safebox.Update(jsonResponse);

            return safebox.Participants;
        }

        /// <summary>
        /// Retrieve all messages info of an existing safebox for the current user account.
        /// </summary>
        /// <param name="safebox">A Safebox object</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The list of messages</returns>
        public async Task<List<Helpers.Message>> MessagesAsync(Helpers.Safebox safebox, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (safebox.Guid == null)
            {
                throw new Exceptions.SendSecureException("Safebox Guid cannot be null");
            }

            string jsonResponse = await JsonClient.GetSafeboxMessagesAsync(safebox.Guid, cancellationToken);

            safebox.Update(jsonResponse);

            return safebox.Messages;
        }

        /// <summary>
        /// Retrieve all event_history info of an existing safebox for the current user account.
        /// </summary>
        /// <param name="safebox">A Safebox object</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The list of EventHistory</returns>
        public async Task<List<Helpers.EventHistory>> EventHistoryAsync(Helpers.Safebox safebox, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (safebox.Guid == null)
            {
                throw new Exceptions.SendSecureException("Safebox Guid cannot be null");
            }

            string jsonResponse = await JsonClient.GetSafeboxEventHistoryAsync(safebox.Guid, cancellationToken);

            safebox.Update(jsonResponse);

            return safebox.EventHistory;
        }

        /// <summary>
        /// Retrieve all security options info of an existing safebox for the current user account.
        /// </summary>
        /// <param name="safebox">A Safebox object</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The Security Options</returns>
        public async Task<Helpers.SecurityOptions> SecurityOptionsAsync(Helpers.Safebox safebox, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (safebox.Guid == null)
            {
                throw new Exceptions.SendSecureException("Safebox Guid cannot be null");
            }

            string jsonResponse = await JsonClient.GetSafeboxSecurityOptionsAsync(safebox.Guid, cancellationToken);

            safebox.Update(jsonResponse);

            return safebox.SecurityOptions;
        }

        /// <summary>
        /// Retrieve all download activity info of an existing safebox for the current user account.
        /// </summary>
        /// <param name="safebox">A Safebox object</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The Download Activity</returns>
        public async Task<Helpers.DownloadActivity> DownloadActivityAsync(Helpers.Safebox safebox, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (safebox.Guid == null)
            {
                throw new Exceptions.SendSecureException("Safebox Guid cannot be null");
            }

            string jsonResponse = await JsonClient.GetSafeboxDownloadActivityAsync(safebox.Guid, cancellationToken);

            safebox.Update(jsonResponse);

            return safebox.DownloadActivity;
        }

        /// <summary>
        /// Retrieve a specific Safebox by its guid.
        /// </summary>
        /// <param name="safeboxGuid">The safebox GUID</param>
        /// <param name="cancellationToken"></param>
        /// <returns>A Safebox object</returns>
        public async Task<Helpers.Safebox> GetSafeboxAsync(string safeboxGuid, CancellationToken cancellationToken = default(CancellationToken))
        {
            var jsonResponse = await JsonClient.GetSafeboxInfoAsync(safeboxGuid, String.Empty, cancellationToken);
            var response = JObject.Parse(jsonResponse);
            return Helpers.Safebox.FromJson(response["safebox"].ToString());
        }

        /// <summary>
        /// Reply to a specific safebox associated to the current user's account.
        /// </summary>
        /// <param name="safebox">A Safebox object</param>
        /// <param name="reply">A Reply object</param>
        /// <param name="cancellationToken"></param>
        /// <returns>RequestResponse object containing the request result</returns>
        public async Task<JsonObjects.RequestResponse> ReplyAsync(Helpers.Safebox safebox, Helpers.Reply reply, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (safebox.Guid == null)
            {
                throw new Exceptions.SendSecureException("Safebox Guid cannot be null");
            }

            foreach(Helpers.Attachment attachment in reply.Attachments)
            {
                var fileParamsJson = safebox.TemporaryDocument(attachment.Size);
                var newFileResponseJson = await JsonClient.NewFileAsync(safebox.Guid, fileParamsJson, cancellationToken);
                var newFileResponse = JsonObjects.NewFileResponseSuccess.FromJson(newFileResponseJson);
                var uploadResponseJson = await JsonClient.UploadFileAsync(new Uri(newFileResponse.UploadUrl), attachment.Stream, attachment.ContentType, attachment.FileName, attachment.Size, cancellationToken);
                var uploadResponse = JsonConvert.DeserializeObject<JsonObjects.UploadFileResponseSuccess>(uploadResponseJson);
                reply.DocumentIds.Add(uploadResponse.TemporaryDocument.DocumentGuid);
            };

            var response = await JsonClient.ReplyAsync(safebox.Guid, reply.ToJson(), cancellationToken);
            return JsonObjects.RequestResponse.FromJson(response);
        }

        /// <summary>
        /// Call to get the list of all the localized messages of a consent group.
        /// </summary>
        /// <param name="consentGroupId">The id of the consent group</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The list of all the localized messages</returns>
        public async Task<Helpers.ConsentMessageGroup> GetConsentGroupMessagesAsync(int consentGroupId, CancellationToken cancellationToken = default(CancellationToken))
        {
            var jsonResponse = await JsonClient.GetConsentGroupMessagesAsync(consentGroupId, cancellationToken);
            var response = JObject.Parse(jsonResponse);
            return Helpers.ConsentMessageGroup.FromJson(response["consent_message_group"].ToString());
        }

    }
}


text:
Home » News » Bollywood News » REVEALED: Rani Mukerji will next be seen in Hichki
REVEALED: Rani Mukerji will next be seen in Hichki
Created: Feb 27, 2017 - 3:51 pm IST
While Aditya Chopra released his much ambitious love story Befikre last year, his wife and actress Rani Mukerji has been enjoying motherhood. But now, Rani is all set to return to what she loves doing the most and has even signed a film. The Chopra bahu will be seen in the forthcoming YRF venture titled Hichki.
Directed by Siddharth P. Malhotra and produced by Maneesh Sharma, the film we hear is a positive and inspiring story about a woman who turns her biggest weakness into her biggest strength. Talking about the film, Rani Mukerji added, "I was looking for a script that would challenge and excite me, and Hichki came my way. Each of us has a weakness that pulls us back. It could be a disability or any condition but if we just look at it as simply a hiccup, we can emerge as a winner. It won't come in the way of achieving our dreams. Hichki is built on this positive premise and I decided to take it up."
Hichki will be Maneesh Sharma's third film as a producer with Yash Raj Films after Dum Laga Ke Haisha and the forthcoming Meri Pyaari Bindu. Siddharth P. Malhotra, who has directed We Are Family, will be making his first film with Yash Raj Films. On the other hand, Rani Mukerji was last seen playing in the role of an action packed cop in Mardaani in 2014.
More Pages: Hichki Box Office Collection , Hichki Movie Review
Tags : Aditya Chopra, Hichki, Maneesh Sharma, Mardaani, News, Rani Mukerji, Siddharth P.Malhotra, Yash Raj Films
Jayeshbhai Jordaar: Boman Irani roped in to…
Box Office - Mardaani 2 is a good success,…
Box Office Economics: Rani Mukherji starrer…
EXCLUSIVE: Akshay Kumar teams up with YRF…
Mardaani 2 Box Office Collections: Rani…
Sharvari BREAKS Silence on Bunty Aur Babli 2 with Saif…
Watch: Debutant Sharvari calls Bunty Aur Babli 2 a…
"Debuting opposite Ranveer Singh gives me the…
Reality Check: That vital pre-release 'vibe'
2009 – 2019: Here's how Bollywood stars have changed…
#2019Recap: Most underrated performances of 2019
"Mardaani 2 was an extremely risky film to make" -…
Akshay Kumar: Introducing - the director
EXCLUSIVE: Will Hrithik Roshan and Tiger Shroff…
Mardaani 2 Box Office Collections: The Rani Mukerji…

redpajama_set_name: RedPajamaCommonCrawl


text:
RobotsNOW Brings Robotics Programs to Elementary Schools to Address National STEM Education Crisis
Visit https://www.robotsnow.org/ for further information
Two teenage brothers (ages 13 and 16) believe the US STEM education crisis begins in elementary school, and they intend to do something about it! After their robotics team won the VEX IQ Robotics World Championships, they founded RobotsNOW to provide after-school robotics programs to students, so they can experience STEM fields in a fun, hands-on way.
08/10/17, 05:33 AM | Industrial Robotics, Mobile & Service Robots
Although most attention regarding the US STEM education crisis focuses on the small percentage of US college graduates earning engineering degrees (4-5% of US graduates compared to 31% in China), this issue extends well into elementary school. In fact, two teenage brothers believe thats where the STEM (Science, Technology, Engineering and Mathematics) education crisis begins, and they intend to do something about it!
After their robotics team won First Place at the 2014 VEX IQ Robotics World Championships, Gabriel and Chandler Wimmer learned that most US elementary schools had no after-school STEM programs. "We had to do something. Our experience in competitive robotics was so positive. Of course, winning was fun, but more importantly, it gave us confidence to try other STEM activities," states Gabriel. "We wanted every kid to have access to the same programs that we enjoyed, so we launched RobotsNOW."
RobotsNOW is a 501(c)(3) nonprofit organization that advocates for robotics programs for elementary school students so they can experience STEM subjects in a fun, hands-on way. Robotics is an ideal teaching medium since it combines all STEM fields to design, build and program robots. Plus, most kids are familiar with the building-block style of the more popular robotics platforms, such as LEGO NXT and VEX IQ.
Gabriel and Chandler are examples of the positive impact that after-school robotics programs can have. Gabriel developed a passion for STEM fields and now attends Thomas Jefferson High School for Science & Technology where he is a member of its Rocketry and CyberPatriot teams. At age 11, Chandler had the necessary confidence in STEM to enter a national toy invention contest, targeted for high school kids. He won second place, signing a royalty agreement with the sponsoring toy company for his design.
This summer, the brothers have expanded RobotsNOWs scope to include free, week-long robotics camps in under-served school districts. The camps are extremely popular with over 25 students and teachers attending each camp. During these camps, students learn to use the engineering design process, program sensors, and build complex robots. "The camps are a lot of fun. The only bad part is that the kids ask if their schools will be starting robotics clubs because they want to join," Chandler, an 8th Grader at Nysmith School, says. "Right now, the answer is 'no because the schools dont have the funds to buy robotics equipment. Thats why were launching a crowdfunding campaign."
RobotsNOWs crowdfunding campaign, titled "Help Start After-School Robotics Programs," is hosted by Generosity.com, a subsidiary of IndieGoGo.com. The purpose of this campaign is to raise funds to donate fully-configured robotics labs that can support in-class and after-school robotics programs for every student at an elementary school. The cost of a robotics lab is $8000.
"I know $8000 is a lot of money," admits Gabriel. "But I think it represents an incredible return-on-investment. Our economy is driven by STEM innovators, and the next Bill Gates or Elon Musk could be at one of these elementary schools! Regardless, these programs could help kids realize a passion in a STEM field that could change the rest of their lives."
The RobotsNOW Crowdfunding Campaign is currently live and accepting donations.
Additional information about RobotsNOW may be found on their official website.
High Performance Servo Drives for localized and distributed control applications from Servo2Go.com
Engineered to drive brushless and brush servomotors in torque, velocity or position mode, Servo2Go.com offers a broad selection of servo drives in a wide range of input voltages and output power levels.


Developing a file without recognizing the style makes us really baffled and asks whether the file we made is correct?
There are different layouts that are all proper, you can choose one amongst many styles and layouts from the photo listed below. If you assume the layout of the record layout is not intriguing you can seek other styles in this message.
uploading is fascinating, you can share it on social media to ensure that your buddies could figure out.


Manchester United have already made discreet approaches over a January transfer window raid for Barcelona defender Clement Lenglet, it has emerged.
The young Frenchman has endured a difficult start at the Nou Camp, failing to impress manager Ernesto Valverde since his move from Sevilla this summer.
Lenglet shone at his old club, attracting plenty of interest from other major clubs before eventually opting for Barcelona, but he's since struggled to establish himself in the starting line up due to the presence of big names like Gerard Pique and Samuel Umtiti at the back.
It was claimed yesterday by Don Balon that the 23-year-old already regrets his move to Barca and could be considering his future ahead of January.
CaughtOffside understands that United have been in touch to re-open talks over signing him after also being in for him during his days at Sevilla.
Jose Mourinho's side look in dire need of new centre-backs after a poor start to the season in which Ander Herrera was used in a back three in the recent home defeat to Tottenham.
United were known to be in for big names in defence this summer, but Ed Woodward overruled Mourinho's targets such as Toby Alderweireld and Jerome Boateng for being too old, while Harry Maguire was too expensive.
Lenglet would likely be available for around £50million, which is more affordable and a better investment for a player with his best years ahead of him.
Still, it remains to be seen if Barcelona will want to let him go so quickly, and there is still plenty of time for him to work his way into Valverde's starting line up despite a tricky start.
Is Clement Lenglet the defender Man United need?


Extremely scarce Chris Ware Whitney Biennial Poster from 2002. Professionally preserved inside UV protection glass. This is so rare that it does not come to market often at all. There was another one from over 5 years ago and it was not in great condition. This one is guaranteed to go up in value due to rarity. The genius in Chris Ware's work is evident here! The item "Rare CHRIS WARE The Whitney Prevaricator 2002 BIENNIAL POSTER Collectors Item" is in sale since Wednesday, October 11, 2017. This item is in the category "Collectibles\Comics\Original Comic Art\Other Original Comic Art". The seller is "wisetrader2056" and is located in Attleboro, Massachusetts. This item can be shipped to United States, Canada, United Kingdom, Denmark, Romania, Slovakia, Bulgaria, Czech republic, Finland, Hungary, Latvia, Lithuania, Malta, Estonia, Australia, Greece, Portugal, Cyprus, Slovenia, Japan, China, Sweden, South Korea, Indonesia, Taiwan, South africa, Thailand, Belgium, France, Hong Kong, Ireland, Netherlands, Poland, Spain, Italy, Germany, Austria, Israel, Mexico, New Zealand, Singapore, Switzerland, Norway, Saudi arabia, United arab emirates, Qatar, Kuwait, Bahrain, Croatia, Malaysia, Brazil, Colombia, Panama, Jamaica.