module JsonRecord
  # Internal methods for reading and writing fields serialized from JSON.
  module AttributeMethods
    # Read a field. The field param must be a FieldDefinition and the context should be the record
    # which is being read from.
    def read_attribute (field, context)
      if field.multivalued?
        arr = json_attributes[field.name]
        unless arr
          arr = EmbeddedDocumentArray.new(field.type, context)
          json_attributes[field.name] = arr
        end
        return arr
      else
        val = json_attributes[field.name]
        if val.nil? and !field.default.nil?
          val = field.default.dup rescue field.default
          json_attributes[field.name] = val
        end
        return val
      end
    end

    # Write a field. The field param must be a FieldDefinition and the context should be the record
    # which is being read from.
    def write_attribute (field, val, context)
      if field.multivalued?
        val = val.values if val.is_a?(Hash)
        json_attributes[field.name] = EmbeddedDocumentArray.new(field.type, context, val)
      else
        old_value = read_attribute(field, context)
        converted_value = field.convert(val)
        converted_value.parent = context if converted_value.is_a?(EmbeddedDocument)
        unless old_value == converted_value
          unless field.type.include?(EmbeddedDocument) or Thread.current[:do_not_track_json_field_changes]
            changes = changed_attributes
            if changes.include?(field.name)
              changes.delete(field.name) if converted_value == changes[field.name]
            else
              old_value = (old_value.clone rescue old_value) unless old_value.nil? || old_value.is_a?(Numeric) || old_value.is_a?(Symbol) || old_value.is_a?(TrueClass) || old_value.is_a?(FalseClass)
              changes[field.name] = old_value
            end
          end
          unless converted_value.nil?
            json_attributes[field.name] = converted_value
          else
            json_attributes.delete(field.name)
          end
        end
        context.json_attributes_before_type_cast[field.name] = val
      end
      return val
    end
  end
end
