/**
 * TSV Parser from:
 *   https://github.com/vlandham/d3.tsv
 */
(function(){d3.tsv = function(url, callback) {
  d3.text(url, "text/tab-separated-values", function(text) {
    callback(text && d3.tsv.parse(text, "\t"));
  });
};

d3.tsv.version = "0.0.2"
d3.tsv.parse = function(text, separator) {
  var header;
  return separator && d3.tsv.parseRows(text, separator, function(row, i) {
    if (i) {
      var o = {}, j = -1, m = header.length;
      while (++j < m) o[header[j]] = row[j];
      return o;
    } else {
      header = row;
      return null;
    }
  });
};

d3.tsv.parseRows = function(text, separator, f) {
  var EOL = {}, // sentinel value for end-of-line
      EOF = {}, // sentinel value for end-of-file
      rows = [], // output rows
      re = new RegExp("\r\n|[" + separator + "\r\n]", "g"), // field separator regex
      separatorCode = separator.charCodeAt(0), // code to match separator with
      n = 0, // the current line number
      t, // the current token
      eol; // is the current token followed by EOL?

  re.lastIndex = 0; // work-around bug in FF 3.6

  /** @private Returns the next token. */
  function token() {
    if (re.lastIndex >= text.length) return EOF; // special case: end of file
    if (eol) { eol = false; return EOL; } // special case: end of line

    // special case: quotes
    var j = re.lastIndex;
    if (text.charCodeAt(j) === 34) {
      var i = j;
      while (i++ < text.length) {
        if (text.charCodeAt(i) === 34) {
          if (text.charCodeAt(i + 1) !== 34) break;
          i++;
        }
      }
      re.lastIndex = i + 2;
      var c = text.charCodeAt(i + 1);
      if (c === 13) {
        eol = true;
        if (text.charCodeAt(i + 2) === 10) re.lastIndex++;
      } else if (c === 10) {
        eol = true;
      }
      return text.substring(j + 1, i).replace(/""/g, "\"");
    }

    // common case
    var m = re.exec(text);
    if (m) {
      eol = m[0].charCodeAt(0) !== separatorCode;
      return text.substring(j, m.index);
    }
    re.lastIndex = text.length;
    return text.substring(j);
  }

  while ((t = token()) !== EOF) {
    var a = [];
    while ((t !== EOL) && (t !== EOF)) {
      a.push(t);
      t = token();
    }
    if (f && !(a = f(a, n++))) continue;
    rows.push(a);
  }

  return rows;
};
d3.tsv.format = function(rows) {
  return rows.map(function (row) {
    return d3_formatRow(row, "\t");
  }).join("\n");
};

function d3_formatRow(row, separator) {
  return row.map(d3_formatValue).join(separator);
}

function d3_formatValue(text) {
  return /[",\n]/.test(text)
      ? "\"" + text.replace(/\"/g, "\"\"") + "\""
      : text;
}
})();