 
   isIgnored = (type, thing) -> (t for t in ignoresOfType robot, type when t is thing).length != 0
   isWanted = (event) -> !(
-    isIgnored("project", extractProject event) ||
+    isIgnored("project", (event.change || event.refUpdate).project) ||
     isIgnored("user", extractName event) ||
     isIgnored("event", event.type))
 
   streamEvents.stderr.on "data", (data) ->
     robot.logger.info "Gerrit stream-events: #{data}"
   streamEvents.stdout.on "data", (data) ->
-    json = JSON.parse data
-    msg = formatEvent json
-    if msg == null
+    robot.logger.debug "Gerrit stream-events: #{data}"
+    json = try
+      JSON.parse data
+    catch error
+      robot.logger.error "Gerrit stream-events: Error parsing Gerrit JSON. Error=#{error}, Event=#{data}"
+      null
+    return unless json
+    formatter = formatters.events[json.type]
+    msg = try
+      formatter json if formatter
+    catch error
+      robot.logger.error "Gerrit stream-events: Error formatting event. Error=#{error}, Event=#{data}"
+      null
+    if formatter == null
       robot.logger.info "Gerrit stream-events: Unrecognized event #{data}"
     else if msg && isWanted json
       # Bug in messageRoom? Doesn't work with multiple rooms

      else if status.rowCount == 0
        msg.send "Gerrit didn't find anything matching your query"
      else
        msg.send formatQueryResult r for r in results when r.id

ignoreOrReportEventsMe = (robot, gerrit) -> (msg) ->
  type = msg.match[2].toLowerCase()

#   To disable event stream spam, use the value "disabled"
eventStreamRooms = process.env.HUBOT_GERRIT_EVENTSTREAM_ROOMS

# TODO: Make these template driven with env-var overrides possible.
# See the following for descriptions of the input JSON data:
# http://gerrit-documentation.googlecode.com/svn/Documentation/2.4/json.html
# http://gerrit-documentation.googlecode.com/svn/Documentation/2.4/cmd-stream-events.html
formatters =
  queryResult:          (json) -> "'#{json.change.subject}' for #{json.change.project}/#{json.change.branch} by #{extractName json.change} on #{formatDate json.change.lastUpdated}: #{json.change.url}"
  events:
    "patchset-created": (json) -> "#{extractName json} uploaded patchset #{json.patchSet.number} of '#{json.change.subject}' for #{json.change.project}/#{json.change.branch}: #{json.change.url}"
    "change-abandoned": (json) -> "#{extractName json} abandoned '#{json.change.subject}' for #{json.change.project}/#{json.change.branch}: #{json.change.url}"
    "change-restored":  (json) -> "#{extractName json} restored '#{json.change.subject}' for #{json.change.project}/#{json.change.branch}: #{json.change.url}"
    "change-merged":    (json) -> "#{extractName json} merged patchset #{json.patchSet.number} of '#{json.change.subject}' for #{json.change.project}/#{json.change.branch}: #{json.change.url}"
    "comment-added":    (json) -> "#{extractName json} reviewed patchset #{json.patchSet.number} (#{extractReviews json}) of '#{json.change.subject}' for #{json.change.project}/#{json.change.branch}: #{json.change.url}"
    "ref-updated":      (json) -> "#{extractName json} updated reference #{json.refUpdate.project}/#{json.refUpdate.refName}"

formatDate = (seconds) -> new Date(seconds * 1000).toDateString()
extractName = (json) ->
  account = json.uploader || json.abandoner || json.restorer || json.submitter || json.author || json.owner
  account?.name || account?.email || "Gerrit"
extractReviews = (json) ->
  ("#{a.description}=#{a.value}" for a in json.approvals).join ","

module.exports = (robot) ->
  gerrit = url.parse sshUrl
