/**
 * @author Julenka
 */
var HEIGHT = 50;
var WIDTH = 70;

var COLORS = ['c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9', 'c10', 'c11','c12','c13','c14','c15','c16'];

// Whether the tiles have changed
var _can_update = true;
var _mosaic_modified = false;
// Map of {"x,y" => color}
var _delta_map = {};
var _mouse_down = false;

var _cur_color = 'c1';
var _x1 = -1;
var _y1 = -1;
var _mouse_down;

function indexOf(color){
  for (var i = 0; i < COLORS.length; i++) {
    if (COLORS[i] == color) {
      return i;
    }
  }
}

/*
 * Every X seconds, the "is dirty" bit swtiches back.
 * The page will only refresh if the mosaic is not dirty
 * Also sends an update to the server. This way if the server does choose
 * to update the data will look correct.
 */
function resetChanged(){
  _can_update = true;
  sendUpdate();
  setTimeout("resetChanged()", 50);
}

function refreshTiles(){
  if (_can_update) {
    // Only refresh the tiles if the user hans't modified them since 
    getTiles();
  }
  setTimeout("refreshTiles()", 1000);
}


/*
 * Draws tiles with given rows and columns with colors specified by colors
 * @rows number of rows
 * @cols number of columns
 * @colors color specification must be at least as big as rows x cols
 */
function drawTiles(rows, cols, colors){
  // First, clear tiles
  var table = document.createElement("table");
  table.setAttribute("cellpadding", "0");
  table.setAttribute("cellspacing", "1");
  table.setAttribute("id", "canvas-table");
  for (var i = 0; i < rows; i++) {
    var row = document.createElement("tr");
    for (var j = 0; j < cols; j++) {
      var td = document.createElement("td");
      var div = document.createElement("div");
      var color = COLORS[colors[i * cols + j]];
      div.setAttribute("class", color);
	  div.setAttribute("onmousedown", "handleMouseDown(this, event);");
	  div.setAttribute("onmouseup", "handleMouseUp(this);");
	  div.setAttribute("onmouseover", "handleMouseOver(this, event);");
	  div.setAttribute("onclick", "handleMouseClick(this, event);");
      div.setAttribute("id", i + "," + j);
      td.appendChild(div);
      row.appendChild(td);
    }
    table.appendChild(row);
  }
  document.getElementById("canvas").appendChild(table);
}


function updateTiles(rows, cols, colors){
  for (var i = 0; i < rows; i++) {
    for (var j = 0; j < cols; j++) {
      var color = COLORS[colors[i * cols + j]];
      $(i + "," + j).setAttribute("class", color);
    }
  }
}

function randColor(){
  return COLORS[Math.floor(Math.random() * COLORS.length)];
}

/**
 * 
 * @param {Object} div The dive of the color that was picked.
 */
function handleColorPickerClick(div){
    // Set the current color
	_cur_color = div.id;
	// Unselect all divs
    for(var i = 0; i < COLORS.length; i++){
		document.getElementById(COLORS[i]).setAttribute("class", COLORS[i]);
	}
	// Set this div to be selected
	div.setAttribute("class", div.id + " color-selected");
}

function handleMouseDown(div, e){
  _mouse_down = true;
  handleMouseOver(div, e);
}

function handleMouseClick(div, e) {
  // Toggle the tiles changed bit.
  _mosaic_modified = true;
  _can_update = false;
  // Modify the tile to be the current color
  div.setAttribute("class", _cur_color);
  // Put the changes in the delta map
  _delta_map[div.id] = indexOf(_cur_color);	
}

function setVisibility(div, val){
    div.style["display"] = val ? "inline" : "none";
}


function handleMouseOver(div, e){
  if(!_mouse_down){
    // Don't do anything unless the mouse button is down.
  	return;
  }
  // Toggle the tiles changed bit.
  _mosaic_modified = true;
  _can_update = false;
  // Modify the tile to be the current color
  div.setAttribute("class", _cur_color);
  // Put the changes in the delta map
  _delta_map[div.id] = indexOf(_cur_color);
  
  // If special click, fill
  if(isSpecialClick(e)){
    var coords = div.id.split(",");
    var x = parseInt(coords[0]);
    var y = parseInt(coords[1]); 
    if(_x1 == -1){
        _x1 = x;
        _y1 = y;
        div.setAttribute("class", _cur_color);
    } else {
        // x1, y1 were set so we need to fill
        fill(_x1, _y1, x, y);

    }
  }	
}

// From http://www.java2s.com/Code/JavaScript/Event/Shiftkeypressed.htm
// Determine whether the click was a right click or not.
function isSpecialClick(e){
  // if (!e) var e = window.event;
  // return e.shiftKey;
  return false;

}


function isMouseDown(e){
  if (!e) var e = window.event;
  return e.button == 1;

}

// Fills the region from x1, y1 to x2, y2 the current color
function fill(x1,y1, x2, y2){
  // Toggle the tiles changed bit.
  _mosaic_modified = true;
  _can_update = false;
  if(x2 < x1){
  	var tmp = x1;
	x1 = x2;
	x2 = tmp;
  } 
  if(y2 < y1){
  	var tmp = y1;
	y1 = y2;
	y2 = tmp;
  }
  for(var i = x1; i <= x2; i++){
	for(var j = y1; j <= y2; j++){
	  $(i + "," + j).setAttribute("class", _cur_color);
	  _delta_map[i + "," + j] = indexOf(_cur_color);
	}
  }
}

function handleMouseUp(div){
	_mouse_down = false;
    // Reset x1, y1
    _x1 = -1;
    _y1 = -1;
}


/*
 * Sends the _delta_map (list of modified tiles) off to the server and
 * resets the delta map.
 * Should it only send an update when a user has stopped clicking?
 */
function sendUpdate(){
  // Only update if the user has modified the mosaic and not touched it recently.
  if (_mosaic_modified && _can_update) {
    for (r_c in _delta_map) {
      x_y = r_c.split(",");
      var row = x_y[0];
      var col = x_y[1];
      var next = _delta_map[r_c];
      
      var pars = "row=" + row + "&col=" + col + "&next=" + next;
      var url = "/change_tile.cgi";
      var myAjax = new Ajax.Request(url, {
        method: 'post',
        parameters: pars,
      });
    }
	_mosaic_modified = false;
    _delta_map = {};
  }
}

function initTiles(){
  var url = "/get_tiles.cgi";
  var pars = "type=lst";
  initColorPicker();
  var myAjax = new Ajax.Request(url, {
    method: 'get',
    parameters: pars,
    onComplete: handleInitResponse
  });
}

function initColorPicker(){
  var table = document.createElement("table");
  table.setAttribute("cellpadding", "0");
  table.setAttribute("cellspacing", "7");
  table.setAttribute("id", "color-picker");
  var row = document.createElement("tr");
  for (var i = 0; i < COLORS.length; i++) {
      var td = document.createElement("td");
      var div = document.createElement("div");
      var color = COLORS[i];
	  // Set the color of the tile. If it is the first color, make this the selected 
	  // color as well. 
      div.setAttribute("class", color + (i == 0 ? " color-selected" : ""));
      div.setAttribute("onclick", "handleColorPickerClick(this);");
      div.setAttribute("id", COLORS[i]);
	  div.setAttribute("style", "width: 40px; height: 40px;");
      td.appendChild(div);
      row.appendChild(td);
    table.appendChild(row);
  }
  document.getElementById("canvas").appendChild(table);
}

function getTiles(){
  var url = "/get_tiles.cgi";
  var pars = "type=lst";
  var myAjax = new Ajax.Request(url, {
    method: 'get',
    parameters: pars,
    onComplete: handleResponse
  });
}

/*
 * parses the return string
 * of form
 * 1 2 3 4 5 1 2 1 2 3 2
 * Denoting colors. Initializes the data.
 */
function handleInitResponse(req){
  var resp = req.responseText;
  
  var nums = resp.split(" ");   
  for (var i = 0; i < nums.length; i++) {
    nums[i] = parseInt(nums[i]);
  }
  drawTiles(HEIGHT, WIDTH, nums);
}

/*
 * parses the return string
 * of form
 * 1 2 3 4 5 1 2 1 2 3 2
 * Denoting colors. Initializes the data.
 */
function handleResponse(req){
  var resp = req.responseText;
  
  var nums = resp.split(" ");
  for (var i = 0; i < nums.length; i++) {
    nums[i] = parseInt(nums[i]);
  }
  updateTiles(HEIGHT, WIDTH, nums);
}

function nextColor(div){
  var next = (indexOf(div.getAttribute("class")) + 1) % 5;
  
  return next;
}
