<commit_before>
import EventEmitter from 'events'
import {Map, Set} from 'immutable'

var keyCodes = {
  72: 'left',  // 'h',
  74: 'down',  // 'j',
  75: 'up',    // 'k',
  76: 'right', // 'l',

  37: 'left',
  38: 'up',
  39: 'right',
  40: 'down',
}

class Store extends EventEmitter {
  constructor(bridge) {
    super()
    this.data = new Map();
    this.roots = new Set();
    this.parents = new window.Map();
    this.bridge = bridge;
    this.hovered = null;
    this.selected = null;
    this.selBottom = false;
    this.bridge.on('root', id => {
      console.log('got rot');
      this.roots = this.roots.add(id);
      if (!this.selected) {
        this.selected = id;
        this.emit('selected');
      }
      this.emit('roots');
    });

    this.bridge.on('mount', (data) => {
      this.data = this.data.set(data.id, Map(data));
      if (data.children && data.children.forEach) {
        data.children.forEach(cid => {
          this.parents.set(cid, data.id);
        });
      }
      this.emit(data.id);
    });

    this.bridge.on('update', (data) => {
      this.data = this.data.set(data.id, Map(data));
      if (data.children && data.children.forEach) {
        data.children.forEach(cid => {
          this.parents.set(cid, data.id);
        });
      }
      this.emit(data.id);
    });

    this.bridge.on('unmount', id => {
      this.parents.delete(id);
      // this.data = this.data.set(data.id, Map(data));
      // this.emit(data.id);
    });
  }

  onKeyDown(e) {
    var dir = keyCodes[e.keyCode];
    if (!dir) {
      return;
    }
    e.preventDefault();
    var dest = this.getDest(dir);
    if (!dest) {
      return;
    }
    var move = this.getMove(dest);
    if (move && move !== this.selected) {
      this.select(move);
    }
  }

  skipWrapper(id, up) {
    if (!id) {
      return;
    }
    var node = this.get(id);
    if (node.get('nodeType') !== 'Wrapper') {
      return id;
    }
    if (up) {
      return this.parents.get(id);
    }
    return node.get('children')[0];
  }

  hasBottom(id) {
    var node = this.get(id);
    var children = node.get('children');
    if ('string' === typeof children || !children || !children.length || node.get('collapsed')) {
      return false;
    }
    return true;
  }

  getDest(dir) {
    var id = this.selected;
    var bottom = this.selBottom;
    var node = this.get(id);
    var collapsed = node.get('collapsed');
    var children = node.get('children');
    var hasChildren = children && children.length;
    var pid = this.parents.get(id);
    if (dir === 'down') {
      if (bottom || collapsed || !hasChildren) {
        return 'nextSibling';
      }
      return 'firstChild';
    }<commit_msg>now navigation is excellent<commit_after>
import EventEmitter from 'events'
import {Map, Set} from 'immutable'

var keyCodes = {
  72: 'left',  // 'h',
  74: 'down',  // 'j',
  75: 'up',    // 'k',
  76: 'right', // 'l',

  37: 'left',
  38: 'up',
  39: 'right',
  40: 'down',
}

class Store extends EventEmitter {
  constructor(bridge) {
    super()
    this.data = new Map();
    this.roots = new Set();
    this.parents = new window.Map();
    this.bridge = bridge;
    this.hovered = null;
    this.selected = null;
    this.selBottom = false;
    this.bridge.on('root', id => {
      console.log('got rot');
      this.roots = this.roots.add(id);
      if (!this.selected) {
        this.selected = id;
        this.emit('selected');
      }
      this.emit('roots');
    });

    this.bridge.on('mount', (data) => {
      this.data = this.data.set(data.id, Map(data));
      if (data.children && data.children.forEach) {
        data.children.forEach(cid => {
          this.parents.set(cid, data.id);
        });
      }
      this.emit(data.id);
    });

    this.bridge.on('update', (data) => {
      this.data = this.data.set(data.id, Map(data));
      if (data.children && data.children.forEach) {
        data.children.forEach(cid => {
          this.parents.set(cid, data.id);
        });
      }
      this.emit(data.id);
    });

    this.bridge.on('unmount', id => {
      this.parents.delete(id);
      // this.data = this.data.set(data.id, Map(data));
      // this.emit(data.id);
    });
  }

  onKeyDown(e) {
    var dir = keyCodes[e.keyCode];
    if (!dir) {
      return;
    }
    e.preventDefault();
    var dest = this.getDest(dir);
    if (!dest) {
      return;
    }
    var move = this.getMove(dest);
    if (move && move !== this.selected) {
      this.select(move);
    }
  }

  skipWrapper(id, up) {
    if (!id) {
      return;
    }
    var node = this.get(id);
    if (node.get('nodeType') !== 'Wrapper') {
      return id;
    }
    if (up) {
      return this.parents.get(id);
    }
    return node.get('children')[0];
  }

  hasBottom(id) {
    var node = this.get(id);
    var children = node.get('children');
    if ('string' === typeof children || !children || !children.length || node.get('collapsed')) {
      return false;
    }
    return true;
  }

  getDest(dir) {
    var id = this.selected;
    var bottom = this.selBottom;
    var node = this.get(id);
    var collapsed = node.get('collapsed');
    var children = node.get('children');
    var hasChildren = children && 'string' !== typeof children && children.length;
    var pid = this.parents.get(id);
    if (dir === 'down') {
      if (bottom || collapsed || !hasChildren) {
        return 'nextSibling';
      }
      return 'firstChild';
    }
{'fraction_non_alphanumeric': 0.18243491015768243, 'fraction_numerical': 0.0062339567290062336, 'mean_word_length': 2.1659895531050495, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5663484', 'n_tokens_mistral': 1897, 'n_tokens_neox': 1877, 'n_words': 388}