function Cell(element) {
  this.element = $(element);
  this.coordinates = {
    'x': this.element.attr('cellIndex'),
    'y': this.element.parent().attr('rowIndex')
  };
}

new Cell(null);
Cell.prototype.highlight = function() {
  this.element.addClass('selected');
}

Cell.prototype.unhighlight = function() {
  this.element.removeClass('selected');
}

Cell.prototype.flashOff = function() {
  this.element
    .animate({ backgroundColor: 'red' }, 100)
    .animate({ backgroundColor: 'white' }, 250, function () {
      $(this).removeAttr('style');
    });
}

Cell.prototype.activate = function() {
  this.element.removeClass('selected');
  this.element.addClass('activated');
}

Cell.prototype.neighbor = function(direction) {
  return new Cell(this.element
    .parents("table")
    .find('tr:eq('+(this.coordinates['y'] + direction[1])+')')
    .find('td:eq('+(this.coordinates['x'] + direction[0])+')'));
}

function Range(start, end) {
  this.start = start;
  this.end   = end;
  
  if (start && end) {
    // Determine direction
    this.direction = (function(start, end) {
      var dx = end.coordinates['x'] - start.coordinates['x'];
      var dy = end.coordinates['y'] - start.coordinates['y'];
      var max = Math.max(dx, dy);
      
      return [dx / max, dy / max];
    })(this.start, this.end);
    
    // Load up cells
    this.cells = (function(self) {
      
      function matchDirection(element) {
       return (element[0] == self.direction[0] && element[1] == self.direction[1]);
      }
      
      if ( $.grep(Range.ValidDirections, matchDirection) == 0 ) {
        return [];
      }
      
      var cells = new Array();
      var $current = self.start;
      while ($current.coordinates['x'] <= self.end.coordinates['x'] && $current.coordinates['y'] <= self.end.coordinates['y']) {
        cells.push($current);
        $current = $current.neighbor(self.direction);
      }
      
      return cells;
    })(this);
  }
};

new Range(null, null);
Range.ValidDirections = [[0,1], [1,0], [1,1]];
Range.prototype.activate = function() {
  $.each(this.cells, function(i, e) { e.activate(); });
};

Range.prototype.clear = function() {
  $.each(this.cells, function(i, e) { e.flashOff(); });
};

Range.prototype.matchesWord = function() {
  var dataStart = this.start.element.attr('data-start');
  var dataEnd   = this.end.element.attr('data-end');
  return (dataStart != undefined && dataEnd != undefined) && (dataStart == dataEnd);
};

Range.prototype.markCompleted = function() {
  var word = this.start.element.attr('data-start');
  $("#wordlist").find('li').filter(function() {
    return (new RegExp('^' + word + '$')).test($(this).text());
  }).addClass("completed");
}

$.fn.wordsearch = function() {
  var start, end;
  var me = this;
  
  $(this).find('td').bind('click', function(event) {
    var target = event.target;
    if (!start) {
      start = new Cell(target);
      start.highlight();
      return;
    }

    end = new Cell(target);
    range = new Range(start, end);
    
    start.unhighlight();
    if (range.matchesWord()) {
      range.activate();
      range.markCompleted();
    } else {
      range.clear();
    }
    
    start = end = null;
  });
  
  $("#small").click(function() {
    $(me).removeClass('medium');
    $(me).removeClass('large');
    $(me).addClass('small');
    return false;
  });

  $("#medium").click(function() {
    $(me).removeClass('small');
    $(me).removeClass('large');
    $(me).addClass('medium');
    return false;
  });

  $("#large").click(function() {
    $(me).addClass('large');
    $(me).removeClass('small');
    $(me).removeClass('medium');
    return false;
  });

};

$(document).ready(function() {
  $('#sample, #puzzle').wordsearch();

  $("#print").click(function() {
    window.print();
    return false;
  });
  
  $(".js-only").show();
  
  if ($("#new_puzzle").length > 0) {
    $("#new_puzzle").submit(function(event) {
      var $form = $(event.target);
      
      map = $form.find('input:radio[name=character_map]:checked').val();
      list = $form.find('input:radio[name=word_list]:checked').val();
      label = map + '>' + list;
      
      _gaq.push(['_trackEvent', 'Word Search', 'New', label]);
    });
  }
});