text: /**
   * @author Titus Wormer
   * @copyright 2015 Titus Wormer
   * @license MIT
   * @module remark:parse:tokenize:table
   * @fileoverview Tokenise a table.
   */
  
  'use strict';
  
  var whitespace = require('is-whitespace-character');
  
  module.exports = table;
  table.notInList = true;
  
  var C_BACKSLASH = '\\';
  var C_TICK = '`';
  var C_DASH = '-';
  var C_PIPE = '|';
  var C_COLON = ':';
  var C_SPACE = ' ';
  var C_NEWLINE = '\n';
  var C_TAB = '\t';
  
  var MIN_TABLE_COLUMNS = 1;
  var MIN_TABLE_ROWS = 2;
  
  var TABLE_ALIGN_LEFT = 'left';
  var TABLE_ALIGN_CENTER = 'center';
  var TABLE_ALIGN_RIGHT = 'right';
  var TABLE_ALIGN_NONE = null;
  
  /* Tokenise a table. */
  function table(eat, value, silent) {
    var self = this;
    var index;
    var alignments;
    var alignment;
    var subvalue;
    var row;
    var length;
    var lines;
    var queue;
    var character;
    var hasDash;
    var align;
    var cell;
    var preamble;
    var count;
    var opening;
    var now;
    var position;
    var lineCount;
    var line;
    var rows;
    var table;
    var lineIndex;
    var pipeIndex;
    var first;
  
    /* Exit when not in gfm-mode. */
    if (!self.options.gfm) {
      return;
    }
  
    /* Get the rows.
     * Detecting tables soon is hard, so there are some
     * checks for performance here, such as the minimum
     * number of rows, and allowed characters in the
     * alignment row. */
    index = 0;
    lineCount = 0;
    length = value.length + 1;
    lines = [];
  
    while (index < length) {
      lineIndex = value.indexOf(C_NEWLINE, index);
      pipeIndex = value.indexOf(C_PIPE, index + 1);
  
      if (lineIndex === -1) {
        lineIndex = value.length;
      }
  
      if (pipeIndex === -1 || pipeIndex > lineIndex) {
        if (lineCount < MIN_TABLE_ROWS) {
          return;
        }
  
        break;
      }
  
      lines.push(value.slice(index, lineIndex));
      lineCount++;
      index = lineIndex + 1;
    }
  
    /* Parse the alignment row. */
    subvalue = lines.join(C_NEWLINE);
    alignments = lines.splice(1, 1)[0] || [];
    index = 0;
    length = alignments.length;
    lineCount--;
    alignment = false;
    align = [];
  
    while (index < length) {
      character = alignments.charAt(index);
  
      if (character === C_PIPE) {
        hasDash = null;
  
        if (alignment === false) {
          if (first === false) {
            return;
          }
        } else {
          align.push(alignment);
          alignment = false;
        }
  
        first = false;
      } else if (character === C_DASH) {
        hasDash = true;
        alignment = alignment || TABLE_ALIGN_NONE;
      } else if (character === C_COLON) {
        if (alignment === TABLE_ALIGN_LEFT) {
          alignment = TABLE_ALIGN_CENTER;
        } else if (hasDash && alignment === TABLE_ALIGN_NONE) {
          alignment = TABLE_ALIGN_RIGHT;
        } else {
          alignment = TABLE_ALIGN_LEFT;
        }
      } else if (!whitespace(character)) {
        return;
      }
  
      index++;
    }
  
    if (alignment !== false) {
      align.push(alignment);
    }
  
    /* Exit when without enough columns. */
    if (align.length < MIN_TABLE_COLUMNS) {
      return;
    }
  
    /* istanbul ignore if - never used (yet) */
    if (silent) {
      return true;
    }
  
    /* Parse the rows. */
    position = -1;
    rows = [];
  
    table = eat(subvalue).reset({
      type: 'table',
      align: align,
      children: rows
    });
  
    while (++position < lineCount) {
      line = lines[position];
      row = {type: 'tableRow', children: []};
  
      /* Eat a newline character when this is not the
       * first row. */
      if (position) {
        eat(C_NEWLINE);
      }
  
      /* Eat the row. */
      eat(line).reset(row, table);
  
      length = line.length + 1;
      index = 0;
      queue = '';
      cell = '';
      preamble = true;
      count = null;
      opening = null;
  
      while (index < length) {
        character = line.charAt(index);
  
        if (character === C_TAB || character === C_SPACE) {
          if (cell) {
            queue += character;
          } else {
            eat(character);
          }
  
          index++;
          continue;
        }
  
        if (character === '' || character === C_PIPE) {
          if (preamble) {
            eat(character);
          } else {
            if (character && opening) {
              queue += character;
              index++;
              continue;
            }
  
            if ((cell || character) && !preamble) {
              subvalue = cell;
  
              if (queue.length > 1) {
                if (character) {
                  subvalue += queue.slice(0, queue.length - 1);
                  queue = queue.charAt(queue.length - 1);
                } else {
                  subvalue += queue;
                  queue = '';
                }
              }
  
              now = eat.now();
  
              eat(subvalue)({
                type: 'tableCell',
                children: self.tokenizeInline(cell, now)
              }, row);
            }
  
            eat(queue + character);
  
            queue = '';
            cell = '';
          }
        } else {
          if (queue) {
            cell += queue;
            queue = '';
          }
  
          cell += character;
  
          if (character === C_BACKSLASH && index !== length - 2) {
            cell += line.charAt(index + 1);
            index++;
          }
  
          if (character === C_TICK) {
            count = 1;
  
            while (line.charAt(index + 1) === character) {
              cell += character;
              index++;
              count++;
            }
  
            if (!opening) {
              opening = count;
            } else if (count >= opening) {
              opening = 0;
            }
          }
        }
  
        preamble = false;
        index++;
      }
  
      /* Eat the alignment row. */
      if (!position) {
        eat(C_NEWLINE + alignments);
      }
    }
  
    return table;
  }
  