(function() {

  $block_size = 32;

  this.def_tag('EDITOR_TAG_ID',"NODE_TAG",function(__scope,__class){

    if(!this.__ctor__){this.__ctor__= function EDITOR_TAG_ID(){__class.__super__.__ctor__.apply(this, arguments)}; this.__ctor__.prototype = this.prototype; }

    this.prototype.awaken = function() {
      var _this = this;
      this["@ticks"] = 10000;
      this["@scheduled_timers"] = [];
      this["@timers"] = [];
      $set_interval((function() {
        return _this.tick();
      }), 1000 / 30);
      this["@bottom_row"] = $bottom_row = 0;
      this["@paused_distance"] = 0;
      this["tabindex="](0);
      this.ondom('mousewheel', 'onscroll');
      this.ondom('mousemove', 'onmousemove');
      $win.addEventListener('resize', (function() {
        return _this.onresize(arguments[0]);
      }), false);
      return true;
    }; __method_added(this,"awaken");

    this.prototype.onscroll = function(e) {
      var move;
      move = (e.wheelDelta > 0 && 4) || (e.wheelDelta < 0 && -4) || 0;
      if (e.metaKey) move *= 3;
      return this["bottom_row="](this["@bottom_row"] + move);
    }; __method_added(this,"onscroll");

    this.prototype.bottom_row = function() {
      return this["@bottom_row"];
    }; __method_added(this,"bottom_row");

    this.prototype["bottom_row="] = function(row) {
      var old;
      row = __scope.Math.max(row, -8);
      old = this["@bottom_row"];
      if (old !== row) {
        this["@bottom_row"] = row;
        $bottom_row = row;
        return this.refresh(row - old);
      }
    }; __method_added(this,"bottom_row=");

    this.prototype.tick = function() {
      var timer, _i, _len, _primitive, _ref, _results;
      this["@ticks"] += 2;
      _ref = this["@scheduled_timers"];
      _results = [];
      for (_i = 0, _len = (_ref.len ? _ref.len() : _ref.length),_primitive = (_ref instanceof Array || !_ref.at); _i < _len; _i++) {
        timer = _primitive ? _ref[_i] : _ref.at(_i);
        if (this["@paused"]) {
          _results.push(timer.freeze(this["@paused_distance"]));
        } else {
          _results.push(timer.tick(this["@ticks"]));
        }
      }
      return _results;
    }; __method_added(this,"tick");

    this.prototype.show = function(level) {
      var _this = this;
      __class.__super__.prototype.show.apply(this, arguments);
      this["@bottom_row"] = $bottom_row = 0;
      this["@level"] = level;
      this.cleanup_timers();
      $set_timeout((function() {
        return _this.draw_lines();
      }), 100);
      this.refresh();
      this.focus();
      this["@level"].grid().on('change', function(idx, char) {
        return _this.draw_idx(idx, char);
      });
      return this["@level"].timers().on('change', function(idx, config) {
        if (config) {
          return _this.render_timer(idx, config);
        } else {
          return _this.remove_timer(idx);
        }
      });
    }; __method_added(this,"show");

    this.prototype.refresh = function(delta) {
      this.redraw(delta);
      this.draw_lines();
      if (!delta) return this.render_timers();
    }; __method_added(this,"refresh");

    this.prototype.redraw = function(delta) {
      var c, canvas, char, cols, from_row, grid, height, level, path, r, reps, rows_in_view, to_row, type, x, y;
      canvas = __tagid('world');
      level = __tagid('app').level();
      grid = level.grid().raw();
      height = this.height();
      rows_in_view = __scope.Math.ceil(height / ($block_size / 2));
      this["@cols"] = cols = level.width();
      this["@repeats"] = reps = __scope.Math.ceil(this.width() / (cols * $block_size));
      canvas["width="](this.width());
      canvas["height="](height);
      from_row = this["@bottom_row"];
      to_row = from_row + rows_in_view;
      canvas.fill_rect('#000000');
      if (from_row < 0) {
        y = height + from_row * ($block_size / 2);
        canvas.fill_rect('#141c1d', 0, y, this.width(), height - y);
      }
      r = __scope.Math.max(from_row, 0);
      while (r < to_row) {
        c = 0;
        y = height - (r - this["@bottom_row"]) * ($block_size / 2) - ($block_size / 2);
        while (c < cols) {
          char = grid[r * cols + c];
          type = __scope.Block[char] || __scope.Block['empty'];
          path = "/blocks/" + type["@name"] + ".png";
          x = c * $block_size + (r % 2) * ($block_size / 2) - ($block_size / 2);
          canvas.draw_image(path, x, y, $block_size, $block_size);
          if (reps > 1) {
            canvas.draw_image(path, x + cols * $block_size, y, $block_size, $block_size);
          }
          if (reps > 2) {
            canvas.draw_image(path, x + cols * $block_size * 2, y, $block_size, $block_size);
          }
          if (reps > 3) {
            canvas.draw_image(path, x + cols * $block_size * 3, y, $block_size, $block_size);
          }
          if (reps > 4) {
            canvas.draw_image(path, x + cols * $block_size * 4, y, $block_size, $block_size);
          }
          c++;
        }
        r++;
      }
      __tagid('foreground')["@node"].style.webkitTransform = "translate3d(0," + (this["@bottom_row"] * ($block_size / 2)) + "px,0)";
    }; __method_added(this,"redraw");

    this.prototype.draw_lines = function() {
      var canvas, y2;
      var _this = this;
      canvas = __tagid('world');
      y2 = this.height();
      (1).upto(this["@repeats"], function(i) {
        var x;
        x = _this["@cols"] * $block_size * i - 1;
        return canvas.draw_line(x, 0, x, y2, {
          style: 'rgba(50,50,50,0.4)',
          width: 2
        });
      });
      return this;
    }; __method_added(this,"draw_lines");

    this.prototype.draw_idx = function(index, type) {
      var c, cols, r;
      cols = __tagid('app').level().width();
      r = __scope.Math.floor(index / cols);
      c = index % cols;
      return this.draw_block(r, c, type);
    }; __method_added(this,"draw_idx");

    this.prototype.cleanup_timers = function() {
      true;      __tagid('foreground')["empty!"]();
      this["@scheduled_timers"] = [];
      return this["@timers"] = [];
    }; __method_added(this,"cleanup_timers");

    this.prototype.remove_timer = function(idx) {
      var node;
      if (node = this["@timers"]['[]'](idx)) {
        this["@scheduled_timers"].remove(node);
        this["@timers"]['[]='](idx,void 0);
        node["destroy!"]();
      }
    }; __method_added(this,"remove_timer");

    this.prototype.render_timers = function() {
      var _this = this;
      __tagid('app').level().timers().each_pair(function(idx, json) {
        var node;
        node = _this.timerblock_for_index(idx);
        node["index="](idx);
        return node["config="](__scope.JSON.parse(json));
      });
      return true;
    }; __method_added(this,"render_timers");

    this.prototype.render_timer = function(idx, config) {
      var node;
      node = this.timerblock_for_index(idx);
      node["index="](idx);
      node["config="](__scope.JSON.parse(config));
      return node["select!"]();
    }; __method_added(this,"render_timer");

    this.prototype.timerblock_for_index = function(idx) {
      var node;
      if (!(node = this["@timers"]['[]'](idx))) {
        node = this["@timers"]['[]='](idx,__tag('timerblock',null,null,{}));
        this["@scheduled_timers"].push(node);
        __tagid('foreground')["<<"](node);
      }
      return node;
    }; __method_added(this,"timerblock_for_index");

    this.prototype.pause = function() {
      this["@paused"] = true;
      __tagid('timings').show();
      return this.p('PAUSED');
    }; __method_added(this,"pause");

    this.prototype.resume = function() {
      this["@paused"] = false;
      __tagid('timings').hide();
      return this.p('RESUMED');
    }; __method_added(this,"resume");

    this.prototype.draw_block = function(r, c, type) {
      var canvas, cols, dx, empty, i, path, rel_row, reps, x, y;
      canvas = __tagid('world');
      type = __scope.Block[type] || __scope.Block['empty'];
      cols = __tagid('app').level().width();
      reps = __scope.Math.ceil(this.width() / (cols * $block_size));
      empty = "/blocks/empty.png";
      path = "/blocks/" + type["@name"] + ".png";
      rel_row = r - $bottom_row;
      x = c * $block_size + (r % 2) * ($block_size / 2) - ($block_size / 2);
      y = this.height() - rel_row * ($block_size / 2) - ($block_size / 2);
      i = 0;
      while (i < reps) {
        dx = cols * $block_size * i;
        canvas.draw_image(empty, x + dx, y, $block_size, $block_size);
        canvas.draw_image(path, x + dx, y, $block_size, $block_size);
        if (c === 0 && r % 2 === 0) {
          canvas.draw_line(x + dx + 16 - 1, y, x + dx + 16 - 1, y + 32, {
            style: 'rgba(50,50,50,0.5)',
            width: 2
          });
        }
        i++;
      }
    }; __method_added(this,"draw_block");

    this.prototype.onresize = function(event) {
      if (__tagid('app').level()) return this.redraw();
    }; __method_added(this,"onresize");

    this.prototype.ontap = function(touch) {
      if (this["@tool"]) return this["@tool"].ontap(touch, this);
    }; __method_added(this,"ontap");

    this.prototype.onmousemove = function(event) {
      if (this["@tool"]) return this["@tool"].onmousemove(event, this);
    }; __method_added(this,"onmousemove");

    this.prototype.ontouchstart = function(touch) {
      if (this["@tool"]) return this["@tool"].ontouchstart(touch, this);
    }; __method_added(this,"ontouchstart");

    this.prototype.ontouchmove = function(touch) {
      if (this["@tool"]) return this["@tool"].ontouchmove(touch, this);
    }; __method_added(this,"ontouchmove");

    this.prototype.ontouchend = function(touch) {
      if (this["@tool"]) return this["@tool"].ontouchend(touch, this);
    }; __method_added(this,"ontouchend");

    this.prototype.onkeydown = function(event) {
      var chr, i, tool;
      chr = event.char();
      if (chr['[]'](/\d/)) {
        i = event.char().to_i() - 1;
        if (i === -1) i = 9;
        tool = __msel([['#tools','>','tool']], this)['[]'](i);
        if (tool) __tagid('tools')["selected="](tool);
      } else if (chr === 'S') {
        if (this["@paused"]) {
          this.resume();
        } else {
          this.pause();
        }
      } else if (chr === 'R') {
        __tagid('brushcanvas')["rotate!"]();
      }
      return true;
    }; __method_added(this,"onkeydown");

    this.prototype.onformchange = function(event) {
      this.p('updated timer', __sel([['#timings',' ','slider']], this).value());
      return this["@paused_distance"] = __sel([['#timings',' ','slider']], this).value();
    }; __method_added(this,"onformchange");

    this.prototype["tool="] = function(tool) {
      if (this["@tool"] !== tool) {
        this["@tool"] = tool;
        this["@tool"]["enable!"]();
      }
      return tool;
    }; __method_added(this,"tool=");

  });

}).call($$base);

