//
//  Message.swift
//  Astro
//
//  Created by Mark Sandstrom on 4/23/15.
//  Copyright (c) 2015 Mobify Research & Development Inc. All rights reserved.
//

import Foundation

/// A deserialized json object.
///
/// `JSONObject` has the same constraints as outlined in
/// [NSJSONSerialization](https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSJSONSerialization_Class/index.html#//apple_ref/occ/cl/NSJSONSerialization)
/// with the *additional constraint* that the top level object be a
/// `Dictionary`:
///
/// - The top level object is an NSDictionary.
/// - All objects are instances of NSString, NSNumber, NSArray, NSDictionary, or NSNull.
/// - All dictionary keys are instances of NSString.
/// - Numbers are not NaN or infinity.
///
/// Example: `["key": ["value", "value"]]`

public typealias JSONObject = [String: Any]

/// Concatenate two JsonObjects together. Returns a new
func +(lhs: JSONObject, rhs: JSONObject) -> JSONObject {
    var result = lhs
    for (key, value) in rhs {
        result[key] = value
    }
    return result
}

/// `MessageAddress` is treated as an opaque type throughout most of Astro iOS.
public typealias MessageAddress = String

/// The base class for messages that can be sent through a `MessageBus`.
///
public class Message {
    /// The `MessageAddress` to where message will be sent.
    let to: MessageAddress

    /// The `MessageAddress` the message is sent from.
    let from: MessageAddress

    /// An opaque `JSONObject`. The data stored varies by specialized `Message` type.
    let payload: JSONObject

    // The messageBus property is set to the messageBus that the message was
    // sent on. It is nil if the message is unsent.
    var messageBus: MessageBus?

    init(to: MessageAddress, from: MessageAddress, payload: JSONObject = JSONObject()) {
        self.to = to
        self.from = from
        self.payload = payload
    }

    func toBridgeMessage() -> BridgeMessage {
        return BridgeMessage(address: self.to, jsonObject: ["payload": self.payload])
    }
}

extension Message: CustomStringConvertible {
    public var description: String {
        return "\(type(of: self))(to: \(to), payload: \(payload))"
    }
}
