 //  Copyright (c) 2017. All rights reserved.
 //
 
-/// Represents a generic Salesforce object record
+/// Represents a generic record of a Salesforce object
 public struct Record {
 	
-	fileprivate var attributes: RecordAttributes?
+	/// Salesforce type corresponding to this record
+	public var type: String
+	
+	/// Salesforce record ID
+	public var id: String?
+	
 	fileprivate var container: KeyedDecodingContainer<RecordCodingKey>?
-	fileprivate var mutableFields: [String: Codable?]
-	
-	
-	
-	/// Record ID
-	public var id: String? {
-		return attributes?.id
-	}
-	
-	/// Type of object (e.g. Account, Lead, MyCustomObject__c)
-	public var type: String? {
-		return attributes?.type
-	}
-	
-	/// Path to the record detail page in Salesforce
-	public var path: String? {
-		return attributes?.path
-	}
+	fileprivate var mutableFields: [String: Encodable?]
 	
 	/// Subscript by field name; read only
-	subscript<Value: Codable>(field: String) -> Value? {
+	subscript<Value: Decodable>(field: String) -> Value? {
 		return value(forField: field)
-	}
-	
-	/// Returns the value for the given field
-	public func value<Value: Codable>(forField field: String) -> Value? {
-		if mutableFields.keys.contains(field) {
-			return mutableFields[field] as? Value
-		}
-		else {
-			if let c = container, let key = RecordCodingKey(stringValue: field) {
-				return try? c.decode(Value.self, forKey: key)
-			}
-			else {
-				return nil
-			}
-		}
 	}
 	
 	/// Returns the value for the given field as a String

extension Record: Codable {
	
	fileprivate struct RecordCodingKey: CodingKey {
		
		var stringValue: String
		var intValue: Int? = nil
		
		init?(stringValue: String) {
			self.stringValue = stringValue
		}
		
		init?(intValue: Int) {
			return nil
		}
	}
	
	public init(from decoder: Decoder) throws {
		let cont = try decoder.container(keyedBy: RecordCodingKey.self)
		self.container = cont
		self.attributes = try cont.decodeIfPresent(RecordAttributes.self, forKey: RecordCodingKey(stringValue: "attributes")!)
		self.mutableFields = [String: Codable?]()
	}
	
	public func encode(to encoder: Encoder) throws {
		var container = encoder.container(keyedBy: RecordCodingKey.self)
		for field in mutableFields {

		return value(forField: field)
	}
	
	public func address(forField field: String) -> Address? {
		return value(forField: field)
	}
	
	public func subqueryResult(forField field: String) -> QueryResult<Record>? {
		return value(forField: field)
	}
	
	/// Returns the value for the given field
	public func value<Value: Decodable>(forField field: String) -> Value? {
		if mutableFields.keys.contains(field) {
			return mutableFields[field] as? Value
		}
		else {
			if let c = container, let key = RecordCodingKey(stringValue: field) {
				return try? c.decode(Value.self, forKey: key)
			}
			else {
				return nil
			}
		}
	}
	
	/// Sets the value for the given field
	public mutating func setValue(_ value: Encodable?, forField field: String) {
		mutableFields.updateValue(value, forKey: field)
	}
	
	public init(type: String, id: String? = nil, fields: [String: Encodable?] = [String: Encodable?]()) {
		self.type = type
		self.id = id 
		self.mutableFields = fields 
	}
}
