/// <summary>
        /// Initialises a new instance with the given description.
        /// </summary>
        ///
        /// <param name="desc">The description.</param>
        public Message(MessageDesc desc)
        {
            ReleaseAssert.IsNotNull(desc, "A description object cannot be null.");

            ReleaseAssert.IsNotNull(desc.MessageId, "MessageId cannot be null.");
            ReleaseAssert.IsNotNull(desc.From, "From cannot be null.");
            ReleaseAssert.IsNotNull(desc.SentOn, "SentOn cannot be null.");

            MessageId  = desc.MessageId;
            From       = desc.From;
            SentOn     = desc.SentOn;
            Read       = desc.Read;
            ReadOn     = desc.ReadOn;
            Redeemed   = desc.Redeemed;
            RedeemedOn = desc.RedeemedOn;
            if (desc.Tags != null)
            {
                Tags = Mutability.ToImmutable(desc.Tags);
            }
            Expiry  = desc.Expiry;
            Title   = desc.Title;
            Text    = desc.Text;
            Data    = desc.Data;
            Rewards = desc.Rewards;
        }
        /// <summary>
        /// Initialises a new instance from the given Json dictionary.
        /// </summary>
        ///
        /// <param name="jsonDictionary">The dictionary containing the Json data.</param>
        public Message(IDictionary <string, object> jsonDictionary)
        {
            ReleaseAssert.IsNotNull(jsonDictionary, "JSON dictionary cannot be null.");
            ReleaseAssert.IsTrue(jsonDictionary.ContainsKey("MessageID"), "Json is missing required field 'MessageID'");
            ReleaseAssert.IsTrue(jsonDictionary.ContainsKey("From"), "Json is missing required field 'From'");
            ReleaseAssert.IsTrue(jsonDictionary.ContainsKey("SentOn"), "Json is missing required field 'SentOn'");
            ReleaseAssert.IsTrue(jsonDictionary.ContainsKey("Read"), "Json is missing required field 'Read'");

            foreach (KeyValuePair <string, object> entry in jsonDictionary)
            {
                // Message Id
                if (entry.Key == "MessageID")
                {
                    ReleaseAssert.IsTrue(entry.Value is string, "Invalid serialised type.");
                    MessageId = (string)entry.Value;
                }

                // From
                else if (entry.Key == "From")
                {
                    ReleaseAssert.IsTrue(entry.Value is IDictionary <string, object>, "Invalid serialised type.");
                    From = new MessageSender((IDictionary <string, object>)entry.Value);
                }

                // Sent On
                else if (entry.Key == "SentOn")
                {
                    ReleaseAssert.IsTrue(entry.Value is string, "Invalid serialised type.");
                    SentOn = JsonSerialisation.DeserialiseDate((string)entry.Value);
                }

                // Read
                else if (entry.Key == "Read")
                {
                    ReleaseAssert.IsTrue(entry.Value is bool, "Invalid serialised type.");
                    Read = (bool)entry.Value;
                }

                // Read On
                else if (entry.Key == "ReadOn")
                {
                    if (entry.Value != null)
                    {
                        ReleaseAssert.IsTrue(entry.Value is string, "Invalid serialised type.");
                        ReadOn = JsonSerialisation.DeserialiseDate((string)entry.Value);
                    }
                }

                // Redeemed
                else if (entry.Key == "Redeemed")
                {
                    if (entry.Value != null)
                    {
                        ReleaseAssert.IsTrue(entry.Value is bool, "Invalid serialised type.");
                        Redeemed = (bool)entry.Value;
                    }
                }

                // Redeemed On
                else if (entry.Key == "RedeemedOn")
                {
                    if (entry.Value != null)
                    {
                        ReleaseAssert.IsTrue(entry.Value is string, "Invalid serialised type.");
                        RedeemedOn = JsonSerialisation.DeserialiseDate((string)entry.Value);
                    }
                }

                // Tags
                else if (entry.Key == "Tags")
                {
                    if (entry.Value != null)
                    {
                        ReleaseAssert.IsTrue(entry.Value is IList <object>, "Invalid serialised type.");
                        Tags = JsonSerialisation.DeserialiseList((IList <object>)entry.Value, (object element) =>
                        {
                            ReleaseAssert.IsTrue(element is string, "Invalid element type.");
                            return((string)element);
                        });
                    }
                }

                // Expiry
                else if (entry.Key == "Expiry")
                {
                    if (entry.Value != null)
                    {
                        ReleaseAssert.IsTrue(entry.Value is long, "Invalid serialised type.");
                        Expiry = (int)(long)entry.Value;
                    }
                }

                // Title
                else if (entry.Key == "Title")
                {
                    if (entry.Value != null)
                    {
                        ReleaseAssert.IsTrue(entry.Value is string, "Invalid serialised type.");
                        Title = (string)entry.Value;
                    }
                }

                // Text
                else if (entry.Key == "Text")
                {
                    if (entry.Value != null)
                    {
                        ReleaseAssert.IsTrue(entry.Value is string, "Invalid serialised type.");
                        Text = (string)entry.Value;
                    }
                }

                // Data
                else if (entry.Key == "Data")
                {
                    if (entry.Value != null)
                    {
                        ReleaseAssert.IsTrue(entry.Value is object, "Invalid serialised type.");
                        Data = new MultiTypeValue((object)entry.Value);
                    }
                }

                // Rewards
                else if (entry.Key == "Rewards")
                {
                    if (entry.Value != null)
                    {
                        ReleaseAssert.IsTrue(entry.Value is IDictionary <string, object>, "Invalid serialised type.");
                        Rewards = new MessageReward((IDictionary <string, object>)entry.Value);
                    }
                }
            }
        }