var clone, uuid;

uuid = require('uuid');

// Based on Underscore.js (MIT)
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
exports.debounce = function(func, wait, immediate) {
  var timeout;
  timeout = null;
  return function() {
    var args, callNow, context, later;
    context = this;
    args = arguments;
    later = function() {
      timeout = null;
      if (!immediate) {
        func.apply(context, args);
      }
    };
    callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
    if (callNow) {
      func.apply(context, args);
    }
  };
};

exports.clone = clone = function(obj) {
  var flags, key, newInstance;
  if ((obj == null) || typeof obj !== 'object') {
    return obj;
  }
  if (obj instanceof Date) {
    return new Date(obj.getTime());
  }
  if (obj instanceof RegExp) {
    flags = '';
    if (obj.global != null) {
      flags += 'g';
    }
    if (obj.ignoreCase != null) {
      flags += 'i';
    }
    if (obj.multiline != null) {
      flags += 'm';
    }
    if (obj.sticky != null) {
      flags += 'y';
    }
    return new RegExp(obj.source, flags);
  }
  newInstance = new obj.constructor();
  for (key in obj) {
    newInstance[key] = clone(obj[key]);
  }
  return newInstance;
};

exports.readGraph = function(filepath, callback) {
  var ext, fbp, fs, path;
  path = require('path');
  fs = require('fs');
  fbp = require('fbp');
  ext = path.extname(filepath);
  return fs.readFile(filepath, {
    encoding: 'utf-8'
  }, function(err, contents) {
    var e, graph;
    if (err) {
      return callback(err);
    }
    try {
      if (ext === '.fbp') {
        graph = fbp.parse(contents);
      } else {
        graph = JSON.parse(contents);
      }
    } catch (error) {
      e = error;
      return callback(e);
    }
    return callback(null, graph);
  });
};

exports.normalizeOptions = function(options) {
  if (!options.broker) {
    options.broker = process.env['MSGFLO_BROKER'];
  }
  if (!options.broker) {
    options.broker = process.env['CLOUDAMQP_URL'];
  }
  if (!options.broker) {
    options.broker = 'amqp://localhost';
  }
  if (!options.runtimeId) {
    options.runtimeId = process.env['MSGFLO_RUNTIME_ID'];
  }
  if (!options.runtimeId) {
    options.runtimeId = uuid.v4();
  }
  if (!options.pingInterval && process.env['MSGFLO_PING_INTERVAL']) {
    options.pingInterval = parseInt(process.env['MSGFLO_PING_INTERVAL']);
  }
  if (!options.pingInterval) { // default: never
    options.pingInterval = 0;
  }
  if (!options.pingMethod) {
    options.pingMethod = process.env['MSGFLO_PING_METHOD'];
  }
  if (!options.pingMethod) {
    options.pingMethod = 'POST';
  }
  if (!options.pingUrl) {
    options.pingUrl = process.env['MSGFLO_PING_URL'];
  }
  if (!options.pingUrl) {
    options.pingUrl = "https://api.flowhub.io/runtimes/$RUNTIME_ID";
  }
  options.pingUrl = options.pingUrl.replace('$RUNTIME_ID', options.runtimeId);
  return options;
};

// Note: relies on convention
exports.queueName = function(role, port) {
  return `${role}.${port.toUpperCase()}`;
};

exports.isParticipant = function(p) {
  return (p.component != null) && p.component !== 'msgflo/RoundRobin' && p.component !== 'msgflo/PubSub';
};

exports.iipsForRole = function(graph, role) {
  var conn, i, iips, len, ref;
  iips = {};
  ref = graph.connections;
  for (i = 0, len = ref.length; i < len; i++) {
    conn = ref[i];
    if (conn.data == null) {
      continue;
    }
    if (conn.tgt.process !== role) {
      continue;
    }
    iips[conn.tgt.port] = conn.data;
  }
  return iips;
};
