var component = require('omniscient'),
    EventEmitter = require('events').EventEmitter,
    Immutable = require('immutable'),
    bind = require('lodash.bind'),
    React = require('react/addons');

var CELL_SIZE = 30,
    BORDER_SIZE = 1,
    TEXT_X_OFFSET = 7,
    TEXT_Y_OFFSET = 25;

function position(a) {
    return (Math.floor(a / 3) + 2) * BORDER_SIZE +
        a * (CELL_SIZE + BORDER_SIZE);
}

var Cell = component(function (props, statics) {
    var x = props.cursor.get('x'),
        y = props.cursor.get('y'),
        value = props.cursor.get('value');

    function onClick(e) {
        statics.events.emit('click', {
            x: x,
            y: y
        });
    }

    return React.DOM.g({
        className: React.addons.classSet({
            "sudoku__cell": true,
            "sudoku__cell--not-editable": !props.cursor.get('editable'),
            "sudoku__cell--highlighted": props.cursor.get('highlighted'),
            "sudoku__cell--focussed": props.cursor.get('focussed')
        })
    }, 
        React.DOM.rect({
            x: position(x),
            y: position(y),
            width: CELL_SIZE,
            height: CELL_SIZE,
            onClick: onClick
        }), value ? [
            React.DOM.text({
                key: "text",
                x: position(x) + TEXT_X_OFFSET,
                y: position(y) + TEXT_Y_OFFSET,
                className: "sudoku__cell-text",
                onClick: onClick
            }, value)
        ] : []
    );
});

function highlights(focusX, focusY) {
    var focusSquareX = Math.floor(focusX / 3),
        focusSquareY = Math.floor(focusY / 3);

    return function (x, y) {
        var squareX = Math.floor(x / 3),
            squareY = Math.floor(y / 3);

        return x == focusX ||
            y == focusY ||
            squareX == focusSquareX && squareY == focusSquareY;
    };
}

var events = new EventEmitter();

function mapCells(grid, f) {
    return grid.map(function (column) {
        return column.map(f);
    });
}

var Grid = component({
    focusCell: function (position) {
        var isHighlighted = highlights(position.x, position.y),
            cells = this.props.cells;

        cells.update(function (state) {
            return mapCells(state, function (cell) {
                return cell.merge({
                    focussed: cell.get('x') === position.x && cell.get('y') === position.y,
                    highlighted: isHighlighted(cell.get('x'), cell.get('y'))
                });
            });
        });

        this.focus = cells.get([position.x, position.y]);
    },

    blurCell: function () {
        this.props.cells.update(function (state) {
            return mapCells(state, function (cell) {
                return cell.merge({
                    focussed: false,
                    highlighted: false
                });
            });
        });
    },

    componentDidMount: function () {
        events.on('click', bind(this.focusCell, this));
    },

    componentWillUnmount: function () {
        events.removeAllListeners();
    }
}, function (props) {
    var cells = props.cells.flatMap(function (column) {
        return column.map(function (cell) {
            return Cell(cell.get('x') + "_" + cell.get('y'), {
                cursor: cell,
                statics: {
                    events: events
                }
            });
        });
    });

    return React.DOM.svg({
        width: position(9),
        height: position(9),
        tabIndex: "0",
        onBlur: this.blurCell
    }, React.DOM.rect({
        x: 0,
        y: 0,
        width: position(9),
        height: position(9),
        className: "sudoku__background"
    }), cells.toJS());
});

module.exports = Grid;


@@ -280,16 +280,90 @@
 SET = 25
+,%0A    KEY_LEFT = 37,%0A    KEY_UP = 38%0A    KEY_RIGHT = 39,%0A    KEY_DOWN = 40
 ;%0A%0Afunct
@@ -2659,24 +2659,915 @@
 %5D);%0A    %7D,%0A%0A
+    onKeyDown: function (event) %7B%0A        var x, y;%0A%0A        if (this.focus) %7B%0A            x = this.focus.get('x');%0A            y = this.focus.get('y');%0A%0A            if (event.keyCode === KEY_LEFT && x %3E 0) %7B%0A                this.focusCell(%7B%0A                    x: x - 1,%0A                    y: y%0A                %7D);%0A            %7D else if (event.keyCode === KEY_RIGHT && x %3C 8) %7B%0A                this.focusCell(%7B%0A                    x: x + 1,%0A                    y: y%0A                %7D);%0A            %7D else if (event.keyCode === KEY_UP && y %3E 0) %7B%0A                this.focusCell(%7B%0A                    x: x,%0A                    y: y - 1%0A                %7D);%0A            %7D else if (event.keyCode === KEY_DOWN && y %3C 8) %7B%0A                this.focusCell(%7B%0A                    x: x,%0A                    y: y + 1%0A                %7D);%0A            %7D%0A        %7D%0A%0A        event.preventDefault();%0A    %7D,%0A%0A
     blurCell
@@ -4506,16 +4506,51 @@
 blurCell
+,%0A        onKeyDown: this.onKeyDown
 %0A    %7D, 

Add ability to change focused cell with keyboard