// Copyright (c) 2015, Evan Summers (twitter.com/evanxsummers)
// ISC license, see http://github.com/evanx/redex/LICENSE

export function create(config, logger, context) {

   function getEventType(service, status) {
      if (!service.status) { // no status i.e. app restarted
         return 'initial';
      } else if (service.status !== status) { // status changed
         return 'changed';
      } else { // status unchanged
         if (service.statusCount === config.debounceCount) {
            return 'debounced';
         } else if (service.statusCount < config.debounceCount) {
            return 'debouncing';
         } else {
            return 'unchanged';
         }
      }
   }

   function setServiceStatus(service, status, eventType, message) {
      service.message = message;
      if (eventType === 'initial') {
         assert(!service.status, 'initial');
         service.status = status;
         service.alertedStatus = service.status;
         service.statusCount = config.debounceCount;
         service.debounceCount = service.debounceCount || config.debounceCount;
      } else if (eventType === 'changed') {
         assert(service.status != status, 'status changed');
         service.statusCount = 0;
         service.status = status;
      } else {
         assert(service.status == status, 'status unchanged', service.statusCount);
         service.statusCount += 1;
      }
   }

   function isAlertableEvent(service, eventType) {
      if (eventType === 'debounced') {
         return true;
      } else if (eventType === 'changed' && service.debounceCount === 0) {
         return true;
      } else {
         return false;
      }
   }

   const those = {
      async pub() {
         return null;
      },
      async start() {
         logger.info('started');
      },
      async end() {
      },
      async processStatus(service, status, message) {
         logger.debug('processStatus', service.name, status, message);
         let eventType = getEventType(service, status);
         service.debug.events = service.debug.events || {};
         service.debug.events[eventType] = { status: status, time: new Date() };
         service.debug.status = service.debug.status || {};
         service.debug.status[status] = { time: new Date() };
         setServiceStatus(service, status, eventType, message);
         if (!isAlertableEvent(service, eventType)) {
            logger.debug('not alertable event:', service.name, eventType, service.status);
         } else if (service.alertedStatus === service.status) {
            logger.debug('equal alertedStatus:', service.name, eventType, service.status);
         } else {
            logger.info('send alert:', service.name, eventType, service.status, service.alertedStatus);
            service.alertedStatus = service.status;
            try {
               await context.components.reporter.sendAlert(service.status + ' ' + service.name, message);
            } catch (err) {
               logger.error(err, 'sendAlert', service.name, service.status);
            }
         }
      }
   };
   return those;
}

@@ -1086,24 +1086,96 @@
 ounceCount;%0A
+         service.debug.events = %7B%7D;%0A         service.debug.status = %7B%7D;%0A
       %7D else
@@ -2103,55 +2103,59 @@
   se
+tSe
 rvice
-.debug.events = service.debug.events %7C%7C %7B%7D
+Status(service, status, eventType, message)
 ;%0A  
@@ -2201,101 +2201,59 @@
 = %7B 
-status: status, time: new Date() %7D;%0A         service.debug.status = service.debug.status %7C%7C %7B
+time: new Date(), status: status, message: message 
 %7D;%0A 
@@ -2313,73 +2313,26 @@
 te()
- %7D;%0A         setServiceStatus(service, status, eventType,
+, message:
  message
 );%0A 
@@ -2319,33 +2319,34 @@
 message: message
-)
+ %7D
 ;%0A         if (!

update commit script