// Generated by CoffeeScript 1.12.7
(function() {
  var EventEmitter, LCD_BLINKOFF, LCD_BLINKON, LCD_CLEARDISPLAY, LCD_CURSORMOVE, LCD_CURSOROFF, LCD_CURSORON, LCD_CURSORSHIFT, LCD_DISPLAYCONTROL, LCD_DISPLAYMOVE, LCD_DISPLAYOFF, LCD_DISPLAYON, LCD_ENTRYLEFT, LCD_ENTRYMODESET, LCD_ENTRYRIGHT, LCD_ENTRYSHIFTDECREMENT, LCD_ENTRYSHIFTINCREMENT, LCD_FUNCTIONSET, LCD_MOVELEFT, LCD_MOVERIGHT, LCD_RETURNHOME, LCD_SETCGRAMADDR, LCD_SETDDRAMADDR, MCP23017_GPIOA, MCP23017_GPIOB, MCP23017_IOCON_BANK0, MCP23017_IOCON_BANK1, MCP23017_IODIRB, Plate, WireAdapter, flip, pollables,
    extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
    hasProp = {}.hasOwnProperty;

  MCP23017_IOCON_BANK0 = 0x0A;

  MCP23017_IOCON_BANK1 = 0x15;

  MCP23017_GPIOA = 0x09;

  MCP23017_IODIRB = 0x10;

  MCP23017_GPIOB = 0x19;

  LCD_CLEARDISPLAY = 0x01;

  LCD_RETURNHOME = 0x02;

  LCD_ENTRYMODESET = 0x04;

  LCD_DISPLAYCONTROL = 0x08;

  LCD_CURSORSHIFT = 0x10;

  LCD_FUNCTIONSET = 0x20;

  LCD_SETCGRAMADDR = 0x40;

  LCD_SETDDRAMADDR = 0x80;

  LCD_DISPLAYON = 0x04;

  LCD_DISPLAYOFF = 0x00;

  LCD_CURSORON = 0x02;

  LCD_CURSOROFF = 0x00;

  LCD_BLINKON = 0x01;

  LCD_BLINKOFF = 0x00;

  LCD_ENTRYRIGHT = 0x00;

  LCD_ENTRYLEFT = 0x02;

  LCD_ENTRYSHIFTINCREMENT = 0x01;

  LCD_ENTRYSHIFTDECREMENT = 0x00;

  LCD_DISPLAYMOVE = 0x08;

  LCD_CURSORMOVE = 0x00;

  LCD_MOVERIGHT = 0x04;

  LCD_MOVELEFT = 0x00;

  flip = [0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0C, 0x1C, 0x02, 0x12, 0x0A, 0x1A, 0x06, 0x16, 0x0E, 0x1E];

  pollables = [LCD_CLEARDISPLAY, LCD_RETURNHOME];

  EventEmitter = require('events').EventEmitter;

  WireAdapter = require('./I2CBusWireAdapter');

  Plate = (function(superClass) {
    extend(Plate, superClass);

    function Plate(device, address, pollInterval) {
      this.ADDRESS = address;
      this.PORTA = 0;
      this.PORTB = 0;
      this.DDRB = 0x10;
      this.WIRE = new WireAdapter(device, address);
      if (pollInterval == null) {
        pollInterval = 200;
      }
      this.init();
      this.BSTATE = 0;
      if (pollInterval > 0) {
        this.poll = setInterval((function(_this) {
          return function() {
            var cur, key;
            cur = _this.buttonState();
            if (cur !== _this.BSTATE) {
              key = _this.BSTATE ^ cur;
              _this.emit('button_change', key);
              if (cur < _this.BSTATE) {
                _this.emit('button_up', key);
              } else {
                _this.emit('button_down', key);
              }
              return _this.BSTATE = cur;
            }
          };
        })(this), pollInterval);
      }
    }

    Plate.prototype.colors = {
      OFF: 0x00,
      RED: 0x01,
      GREEN: 0x02,
      BLUE: 0x04,
      YELLOW: 0x03,
      TEAL: 0x06,
      VIOLET: 0x05,
      WHITE: 0x07,
      ON: 0x07
    };

    Plate.prototype.buttons = {
      SELECT: 0x01,
      RIGHT: 0x02,
      DOWN: 0x04,
      UP: 0x08,
      LEFT: 0x10
    };

    Plate.prototype.clear = function() {
      return this.writeByte(LCD_CLEARDISPLAY);
    };

    Plate.prototype.home = function() {
      return this.writeByte(LCD_RETURNHOME);
    };

    Plate.prototype.close = function() {
      if (this.poll != null) {
        return clearInterval(this.poll);
      }
    };

    Plate.prototype.backlight = function(color) {
      var c;
      c = ~color;
      this.PORTA = (this.PORTA & 0x3F) | ((c & 0x3) << 6);
      this.PORTB = (this.PORTB & 0xFE) | ((c & 0x4) >> 2);
      this.sendBytes(MCP23017_GPIOA, this.PORTA);
      return this.sendBytes(MCP23017_GPIOB, this.PORTB);
    };

    Plate.prototype.message = function(text, clear) {
      var i, j, len, line, lines, results;
      if (clear) {
        this.clear();
      }
      lines = text.split('\n');
      results = [];
      for (i = j = 0, len = lines.length; j < len; i = ++j) {
        line = lines[i];
        if (i === 1) {
          this.writeByte(0xC0);
        }
        if (i < 2) {
          results.push(this.writeByte(line, true));
        } else {
          results.push(void 0);
        }
      }
      return results;
    };

    Plate.prototype.buttonState = function() {
      var ret;
      ret = this.WIRE.readByte(MCP23017_GPIOA);
      return ret & 0x1F;
    };

    Plate.prototype.buttonName = function(val) {
      switch (val) {
        case this.buttons.SELECT:
          return "SELECT";
        case this.buttons.RIGHT:
          return "RIGHT";
        case this.buttons.UP:
          return "UP";
        case this.buttons.DOWN:
          return "DOWN";
        case this.buttons.LEFT:
          return "LEFT";
        default:
          return void 0;
      }
    };

    Plate.prototype.createChar = function(location, pattern) {
      var data, j, len;
      location = location & 0x7;
      this.writeByte(LCD_SETCGRAMADDR | (location << 3));
      for (j = 0, len = pattern.length; j < len; j++) {
        data = pattern[j];
        this.writeByte(data, true);
      }
      return this.clear();
    };

    Plate.prototype.init = function() {
      var displaycontrol, displaymode, displayshift;
      this.sendBytes(MCP23017_IOCON_BANK1, 0);
      this.sendBytes(0, [0x3F, this.DDRB, 0x3F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3F, 0x0, 0x0, 0x0, 0x0, 0x0, this.PORTA, this.PORTB, this.PORTA, this.PORTB]);
      this.sendBytes(MCP23017_IOCON_BANK0, 0xA0);
      displayshift = LCD_CURSORMOVE | LCD_MOVERIGHT;
      displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
      displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
      this.writeByte(0x33);
      this.writeByte(0x32);
      this.writeByte(0x28);
      this.writeByte(LCD_CLEARDISPLAY);
      this.writeByte(LCD_CURSORSHIFT | displayshift);
      this.writeByte(LCD_ENTRYMODESET | displaymode);
      this.writeByte(LCD_DISPLAYCONTROL | displaycontrol);
      this.writeByte(LCD_RETURNHOME);
      this.clear;
      return this.backlight(0x0);
    };

    Plate.prototype.sendBytes = function(cmd, values) {
      var data, reg;
      reg = cmd;
      if (typeof values === 'number') {
        data = [];
        data.push(values);
        values = data;
      }
      return this.WIRE.writeBytes(cmd, values);
    };

    Plate.prototype.sendByte = function(value) {
      return this.WIRE.writeByte(value);
    };

    Plate.prototype.maskOut = function(bitmask, value) {
      var hi, lo;
      hi = bitmask | flip[value >> 4];
      lo = bitmask | flip[value & 0x0F];
      return [hi | 0x20, hi, lo | 0x20, lo];
    };

    Plate.prototype.writeByte = function(value, char_mode) {
      var bitmask, bits, data, hi, j, k, last, lo, ref;
      char_mode = char_mode || false;
      if (this.DDRB & 0x10) {
        lo = (this.PORTB & 0x01) | 0x40;
        hi = lo | 0x20;
        this.sendBytes(MCP23017_GPIOB, lo);
        while (true) {
          this.sendByte(hi);
          bits = this.readByte();
          this.sendBytes(MCP23017_GPIOB, [lo, hi, lo]);
          if ((bits & 0x2) === 0) {
            break;
          }
        }
        this.PORTB = lo;
        this.DDRB &= 0xEF;
        this.sendBytes(MCP23017_IODIRB, this.DDRB);
      }
      bitmask = this.PORTB & 0x01;
      if (char_mode) {
        bitmask |= 0x80;
      }
      if (typeof value === "string") {
        last = value.length - 1;
        data = [];
        for (k = j = 0, ref = last; 0 <= ref ? j <= ref : j >= ref; k = 0 <= ref ? ++j : --j) {
          if (value[k] != null) {
            data = data.concat(this.maskOut(bitmask, value[k].charCodeAt(0)));
            if (data.length >= 32 || k === last) {
              this.sendBytes(MCP23017_GPIOB, data);
              this.PORTB = data[data.length - 1];
              data = [];
            }
          }
        }
      } else {
        data = this.maskOut(bitmask, value);
        this.sendBytes(MCP23017_GPIOB, data);
        this.PORTB = data[data.length - 1];
      }
      if (!char_mode && pollables.indexOf(value) !== -1) {
        this.DDRB |= 0x10;
        return this.sendBytes(MCP23017_IODIRB, this.DDRB);
      }
    };

    Plate.prototype.readByte = function() {
      return this.WIRE.readByte();
    };

    return Plate;

  })(EventEmitter);

  module.exports = Plate;

}).call(this);
