function point_plus(point1, point2) {return [point1[0] + point2[0], point1[1] + point2[1]]}
function untag_point(str){
  var ints = str.split('-')
  var point = []
  $(ints).each(function(){
    point.push(parseInt(this))
  })
  return point
}
function tag_point (point) {return point.join("-")}

String.prototype.capitalize = function(){ //v1.0
    return this.replace(/\w+/g, function(a){
        return a.charAt(0).toUpperCase() + a.substr(1).toLowerCase();
    });
};

// Game logic constants
var orthogonals = [[0,1],[0,-1],[1,0],[-1,0]]
var diagonals   = [[-1,-1],[-1,+1],[+1,-1],[+1,+1]]
var wizard_movements = orthogonals.concat(diagonals)
var strengths = {water:'fire', fire:'plant', plant:'water'}


function ElementalChess(your_players, game_id, user_id, user_name, timestamp, turn){
  //  If there's no game_id, this game is off the record, so disable networking
  var networking = game_id ? true : false
  var dragging = false
  var checking_events = false

  var sent_events = {}
  var min_event_period = 1000
  var event_period = min_event_period
  var event_check_timer
  var last_interaction = new Date().getTime()


  if (!turn) turn = 0
  var turn_order = ["red","blue"]

  function find_offset_spaces(location, movements){
    var class_point = function(){ return "." + tag_point( point_plus(location,this) ) }
    filter = $(movements).map(class_point).get().join(',')
    return $('.space').filter(filter)    
  }

  function analyze_piece(piece){
    var kind   = piece.attr('data_kind')
    var level = kind.slice(kind.length-1,kind.length)
    var type  = kind.slice(0, kind.length-1)
    var player = piece.attr('data_player')
    return {kind:kind, level:level, type:type, player:player}
  }

  // Given a piece element, returns a set of space elements that are valid moves
  function find_targets(piece_node){
    var attacker = analyze_piece(piece_node)
    var movements = orthogonals
    if(attacker.kind == "wizard") movements = wizard_movements
    
    var space = piece_node.parents('.space:first')
    var location = untag_point(space.attr("data_location"))
    var neighbors = find_offset_spaces(location, movements)
    
    // blacklist ones with disagreeable pieces on them (true => keep)
    var targets = neighbors.filter(function(){
      var defender_node = $(this).children('.piece')
      if(!defender_node.length) return true               // blank spaces are always legal
      if(attacker.kind == 'wizard') return false                   // wizards can't attack
      var defender = analyze_piece(defender_node)
      if(attacker.player == defender.player) return false    // can't attack yourself
      if(defender.kind == 'wizard') return true     // anything beats wizard
      if(strengths[attacker.type] == defender.type) return true              // elemental strengths
      if(attacker.type == defender.type && attacker.level > defender.level) return true // same type fights by level
      return false
    })
    // if (attacker.kind == "wizard") console.debug(targets)
    return targets
  }
  
  // function wizard_in_check(player){
  //   var wizard = $('.'+player+'-player.wizard-kind')
  //   var wizard_space = wizard.parents('.space:first')
  //   var wizard_location = untag_point(wizard_space.attr("data_location"))
  //   var wizard_threat_spaces = find_offset_spaces(wizard_location, orthogonals)
  //   var wizard_threats = wizard_threat_spaces.filter(function(){
  //     var attacker_node = $(this).children('.piece')
  //     if (!attacker_node.length) return false
  //     // any piece can hurt a wizard, so we don't really need to look at the piece
  //   })
  // 
  //   if (wizard_threats.length){
  //     // lets try and take these pieces
  //     
  //     
  //     
  //     // lets try and move out of the way
  //   }
  //   
  //   var wizard_moves = find_tagets(wizard)
  //   
  // }
    
  // Moving Pieces
  // NOTE: maybe we could implement this in a way that didn't have to be updated all the time?
  // Like, what if the dragging-start handler could just say no if it's not your turn?
  // research this.  Might be a performance booster.
  function update_dragging(){
    $(".piece").draggable("destroy")

    var player = turn_order[turn % turn_order.length]
    
    // NOTE: Okay, this function may be on its way to destruction, BUT
    // I'm piggy-backing the turn indicator code here
    var wizard = $('.'+player+'-player.wizard-kind')
    if (!wizard.length) {
      // you've lost!
      var winner = turn_order[(turn - 1) % turn_order.length]
      $('.winner').addClass(winner).text(winner.capitalize()+" Player Wins").show()
      return
    }
    
    $(".player_indicator.current").removeClass("current")
    $(".player_indicator."+player).addClass("current")
    
    if($.inArray(player,your_players) == -1) return         // no dragging other people's stuff
    
    $(".piece."+player+"-player").draggable({helper:'clone', scroll:true, start:function(event,ui){
        dragging = true
        $(this).addClass('dragging')  // is this class necessary?
      }, stop:function(event,ui){
        dragging = false
        $('.highlight').removeClass('highlight')
        $(this).removeClass('dragging')
      }
    })
  }
  
  update_dragging()

  $(".space").droppable({accept:".piece", drop:function(event,ui){
    piece = ui.draggable
    from_space = piece.parents(".space:first")
    to_space = $(this)

    // Don't allow drops on invalid moves
    if($.inArray(this,find_targets(piece)) == -1) return

    if (networking) {
      from_space_tag = from_space.attr("data_location")
      to_space_tag = to_space.attr("data_location")
      // NOTE: could add optional piece_tag to payload here for validation purposes
      data = {from_space:from_space_tag, to_space:to_space_tag}
      $.ajax({type:"POST", url:"/games/"+game_id+"/moves", data:data, success:function(response){
        $('#status').text('')
        sent_events[response] = true
        move_message(user_name, user_id, piece.attr('data_kind'), from_space_tag, to_space_tag)
      }, error:function(response){
        $('#status').text(response.responseText)
      }})
    }
    // since we want to be responsive, lets just move the thing right now.
    to_space.children(".piece").remove()
    from_space.children(".piece").appendTo(to_space)
    
    // and advance the turn ourselves
    turn += 1
    update_dragging()
  }})
  
  // hilighting moves
  $(".piece").hover(function(){ // mouse-in
    if(dragging) return
    var player = turn_order[turn % turn_order.length]
    if($.inArray(player,your_players) == -1) return   // no dragging other people's stuff
    if($(this).attr('data_player') != player) return  // must be this player's turn

    find_targets($(this)).addClass('highlight')
  }, function(){ // mouse-out
    if(dragging) return
    $('.highlight').removeClass('highlight')
  })

  // function win_message(user_name, user_id, piece, from, to){
  //   $('#messages').prepend("<p class=\"move\"><a href=\"/users/"+user_id+"\">"+user_name+"</a> moved "+piece+" from "+from+" to "+to+"</p>")
  // }
  
  function move_message(user_name, user_id, piece, from, to){
    $('#messages').prepend("<p class=\"move\"><a href=\"/users/"+user_id+"\">"+user_name+"</a> moved "+piece+" from "+from+" to "+to+"</p>")
  }
  
  function chat_message(user_name, user_id, text){
    $('#messages').prepend("<p class=\"chat\"><a href=\"/users/"+user_id+"\">"+user_name+"</a>: "+text+"</p>" )
  }
  
  // Getting Game Events
  function checkEvents(){
    checking_events = true // lock updates until we're done
    var miliseconds_idle = new Date().getTime() - last_interaction
    event_period = min_event_period + miliseconds_idle*miliseconds_idle / 1000000.0
    $.getJSON('/games/'+game_id+'/events/'+timestamp, function(response){
      $.each(response, function(){
        if(sent_events[this.timestamp]){
          // don't apply events you sent yourself from this browser window
          // but do check them off as having been received, so our blacklist doesn't pile up
          delete sent_events[this.timestamp]
        } else if(this.type == "move"){
          var from_space = $("[data_location="+this.from_space+"]")
          var to_space = $("[data_location="+this.to_space+"]")
          var piece = from_space.children(".piece")
          to_space.children(".piece").remove()
          piece.prependTo(to_space)
          turn += 1
          move_message(this.name+" moves", piece.attr('data_kind'), this.from_space, this.to_space)
          update_dragging() // because the board has changed
        } else if(this.type == "chat"){
          chat_message(this.name, this.user_id, this.text)
        }
        timestamp = this.timestamp
      })
      event_check_timer = setTimeout(checkEvents, event_period)
      checking_events = false
    })
  }

  function nudge(){
    if (checking_events) return
    var miliseconds_idle = new Date().getTime() - last_interaction
    last_interaction = new Date().getTime()
    if(miliseconds_idle > 5000){
      clearTimeout(event_check_timer)
      checkEvents()
    }
  }

  if (networking) {
    $(document).mousemove(nudge)
    $(document).keypress(nudge)
    event_check_timer = setTimeout(checkEvents, event_period)  
  }
  
  // Sending Game Chat
  $('#chat').submit(function(event){
    event.preventDefault()
    var field = $('#chat [name=text]')
    var message = field.val()
    if(message == '') return
    data = {text:message}
    field.val('')
    $.post('/games/'+game_id+'/chat',data)
  })
}
