(function(exports) {

var _             = require('underscore') || this._
,   Backbone      = require('backbone') || this.Backbone
,   clone         = (require('../helpers/clone') || this.Karel.Helpers).clone
,   getLineNumber = (require('../helpers/get_line_number') || this.Karel.Helpers).getLineNumber
,   matrix        = (require('../helpers/matrix') || this.Karel.Helpers).matrix
,   settings      = (require('../settings') || this.Karel).settings
,   sandbox       = (require('../helpers/sandbox') || this.Karel.Helpers).sandbox
,   Position      = (require('../models/position_and_direction') || this.Karel.Models).Position
,   Direction     = (require('../models/position_and_direction') || this.Karel.Models).Direction
,   Robot         = (require('../models/robot') || this.Karel.Models).Robot


function Field() {
  this.bricks = 0
  this.marker = false
  this.block  = false
}

Field.prototype.clone = function() {
  var f = new Field()
  f.bricks = this.bricks
  f.marker = this.marker
  f.block  = this.block 
  return f
}


exports.World = Backbone.Model.extend({

  initialize: function(opts) {
    if (!this.get('fields')) {
      this.set({
        fields: matrix(
          this.get('width'),
          this.get('depth'),
          function() { return new Field() }
        )
      })
    }
    
    this.$fields = this.get('fields')
    
    this.createRobot(opts.robotOptions)
  },

  createRobot: function(opts) {
    opts = opts || {}
    opts.world = this
    var r = new Robot(opts)
    
    r.bind('change', _.bind(function() {
      this.trigger('change:robot')
      this.trigger('change', 'robot')
    }, this))
    
    this.set({ robot: r })
    return r
  },

  // Overwrite Backbone's clone method
  clone: function() {
    return new this.constructor({
      depth: this.get('depth'),
      width: this.get('width'),
      fields: Karel.Helpers.clone(this.get('fields')),
      robotOptions: {
        position:  this.get('robot').get('position'),
        direction: this.get('robot').get('direction')
      }
    })
  },

  triggerChangeField: function(p) {
    this.trigger('change:field', p.x, p.y, this.getField(p))
    this.trigger('change')
  },

  getField: function(position) {
    return this.$fields[position.x][position.y]
  },

  eachField: function(fn) {
    var fields = this.$fields
    ,   w = this.get('width')
    ,   d = this.get('depth')
    for (var x = 0; x < w; x++) {
      for (var y = 0; y < d; y++) {
        fn(x, y, fields[x][y])
      }
    }
  },

  toString: function() {
    var tokens = []
    var p = function(c) { field_height--; tokens.push(c) }
    
    var fields = this.get('fields')
    var height = Math.max(5, 1 + _.max(_.map(fields, function(row) {
      return _.max(_.pluck(row, 'bricks'))
    })))
    
    p('KarolVersion2Deutsch')
    
    p(this.get('width'))
    p(this.get('depth'))
    p(height)
    
    var position = this.get('robot').get('position')
    p(position.x)
    p(position.y)
    var d = this.get('robot').get('direction')
    p([d.isSouth(), d.isWest(), d.isNorth(), d.isEast()].indexOf(true))
    
    var x = this.get('width')
    ,   y = this.get('depth')
    for (var i = 0; i < x; i++) {
      for (var j = 0; j < y; j++) {
        var field = fields[i][j]
        ,   field_height = height
        if (field.block) {
          p('q'); p('q')
        } else {
          _.times(field.bricks, function() { p('z') })
        }
        while (field_height > 0) p('n')
        p(field.marker ? 'm' : 'o')
      }
    }
    
    return tokens.join(' ') + ' '
  }

}, {

  Field: Field,

  fromString: function(str) {
    // Parse .kdw files
    
    var tokens = str.split(/\s/)
    var shift = _(tokens.shift).bind(tokens)
    var _int = function() { return parseInt(shift(), 10) }
    
    tokens.shift() // "KarolVersion2Deutsch"
    
    // Dimensions of the world
    var x = _int(), y = _int(), z = _int()
    
    // Position of the robot
    var position = new Position(_int(), _int())
    
    // Direction of the robot
    var direction = [Direction.SOUTH, Direction.WEST,
                     Direction.NORTH, Direction.EAST][_int()]
    
    var world = new this({
      width: x,
      depth: y,
      robotOptions: {
        direction: direction,
        position: position
      }
    })
    
    var fields = world.get('fields')
    
    for (var i = 0; i < x; i++) {
      for (var j = 0; j < y; j++) {
        var field = new Field()
        if (tokens[0] == 'q') field.block = true
        for (var k = 0; k < z; k++) {
          if (shift() == 'z') field.bricks++
        }
        field.marker = (shift() == 'm')
        fields[i][j] = field
      }
    }
    
    return world
  }

})

})(exports || Karel.Models)

@@ -4044,17 +4044,16 @@
 ction = 
-%5B
 Directio
@@ -4057,84 +4057,39 @@
 tion
-.
+%5B%5B'
 SOUTH
-, Direction.WEST,%0A                     Direction.NORTH, Direction.
+','WEST','NORTH','
 EAST
+'
 %5D%5B_i
@@ -4093,16 +4093,17 @@
 %5B_int()%5D
+%5D
 %0A    %0A  
@@ -4112,193 +4112,63 @@
 var 
-wor
+fie
 ld
+s
  = 
-new this(%7B%0A      width: x,%0A      depth: y,%0A      robotOptions: %7B%0A        direction: direction,%0A        position: position%0A      %7D%0A    %7D)%0A    %0A    var fields = world.get('fields'
+matrix(x, y, function() %7B return new Field() %7D
 )%0A  
@@ -4260,27 +4260,28 @@
 field = 
-new Field()
+fields%5Bi%5D%5Bj%5D
 %0A       
@@ -4465,66 +4465,190 @@
     
-  fields%5Bi%5D%5Bj%5D =
+%7D%0A    %7D%0A    %0A    return new this(%7B%0A      width: x,%0A      depth: y,%0A      fields:
  field
+s,
 %0A      
-%7D%0A    %7D
+robotOptions: %7B%0A        direction: direction,
 %0A    
-%0A
     
-return world
+position: position%0A      %7D%0A    %7D)
 %0A  %7D

Fix weird issue that occurred when creating a world fromString and then asking the robot if the current field has a marker