|
/** Mathematical mod */ |
|
function mmod(m, n) { |
|
return (m % n + n) % n; |
|
} |
|
|
|
class NavigableTable { |
|
static _populateIDMap(rows) { |
|
let idMap = {}; |
|
for (let i = 0; i < rows.length; i++) { |
|
for (var j = 0; j < rows[i].length; j++) { |
|
idMap[rows[i][j].id] = [i, j]; |
|
} |
|
} |
|
|
|
return idMap; |
|
} |
|
|
|
constructor(rows) { |
|
this.rows = rows; |
|
this.idMap = NavigableTable._populateIDMap(this.rows); |
|
} |
|
|
|
containsID(id) { |
|
return !!this.toPath(id); |
|
} |
|
|
|
get(path) { |
|
return this.rows[path[0]][path[1]]; |
|
} |
|
|
|
toPath(id) { |
|
return this.idMap[id]; |
|
} |
|
|
|
/** |
|
* @param distance should only be 1 (right) or -1 (left) |
|
* @return next position skipping left and right and table direction to move |
|
*/ |
|
moveH(id, distance) { |
|
const path = this.toPath(id); |
|
let index = mmod(path[1] + distance, this.rows[path[0]].length); |
|
return { |
|
tableDirection: 0, |
|
next: this.get([path[0], index]) |
|
}; |
|
} |
|
|
|
/** |
|
* @param distance should only be 1 (down) or -1 (up) |
|
*/ |
|
moveV(id, distance) { |
|
const path = this.toPath(id); |
|
const nPos = path[0] + distance; |
|
let tableDirection = 0; |
|
if(nPos < 0) { |
|
tableDirection = -1; |
|
} else if (nPos >= this.rows.length) { |
|
tableDirection = 1; |
|
} |
|
const res = [tableDirection === 0 ? nPos : path[0], path[1]]; |
|
return {tableDirection: tableDirection, next: this.get(res)}; |
|
} |
|
} |
|
|
|
class TableList { |
|
constructor(tables) { |
|
this.tables = tables; |
|
} |
|
|
|
moveH(id, direction) { |
|
return this.tables.find((t) => t.containsID(id)).moveH(id, direction).next; |
|
} |
|
|
|
moveV(id, direction) { |
|
const index = this.tables.findIndex((t) => t.containsID(id)); |
|
const res = this.tables[index].moveV(id, direction); |
|
const tableIndex = mmod(index + res.tableDirection, this.tables.length); |
|
const nrowtblChng = direction < 0 ? this.tables[tableIndex].rows.length - 1 : 0; |
|
if(index === tableIndex) { |
|
return res.next; |
|
} else { |
|
return this.tables[tableIndex].get([nrowtblChng,0]); |
|
} |
|
} |
|
} |