
function RectMenu(width, heightPerItem, numItems, canvas) {
  this._left = 0;
  this._top = 0;
  this._numItems = numItems;
  this._width = width;
  this._heightPerItem = heightPerItem;
  this._ctx = canvas.getContext("2d");
  this._visible = false;
  this._lastChosen = null;
  this._oldSlice = null;
}
RectMenu.prototype = {
  onMouseDown: function( x, y ) {
    this._left = x;
    this._top = y;
    this._ctx.beginPath();
    this._ctx.moveTo(x, y);
    this._ctx.lineTo(x+ this._width, y);
    var bottom = y + this._numItems * this._heightPerItem;
    this._ctx.lineTo(x + this._width, bottom);
    this._ctx.lineTo(x, bottom);
    this._ctx.lineTo(x, y);
    this._ctx.stroke();

    this._ctx.mozTextStyle = "14pt sans serif";
    this._ctx.fillStyle = "black";

    for (var i = 0; i < this._numItems; i++) {
      this._ctx.beginPath();
      this._ctx.moveTo(x, y + i * this._heightPerItem);
      this._ctx.lineTo(x + this._width, y + i * this._heightPerItem);
      this._ctx.stroke();
      this._ctx.save();
      this._ctx.translate( x + (this._width / 2 ), y + (i + 0.5)* this._heightPerItem);
      this._ctx.mozDrawText(i);
      this._ctx.restore();
    }
    this._lastChosen = null;
    this._visible = true;
    this._oldSlice = null;
  },
  onMouseUp: function( x, y ) {
    redrawCanvas(this._ctx);
    this._lastChosen = this.getSliceNumFromPoint(x,y);
    this._visible = false;
  },
  onMouseMove: function( x, y ) {
    var slice = this.getSliceNumFromPoint(x, y);
    if (this._visible && slice != this._oldSlice) {
      if (this._oldSlice != null)
        this.fillSlice(this._oldSlice, "white");
      if (slice != null)
        this.fillSlice(slice, "red");
      this._oldSlice = slice;
    }    
  },
  getLastChosen: function() {
    return this._lastChosen;
  },
  getSliceNumFromPoint: function( x, y ) {
    if (x < this._left || x > this._left + this._width ) {
      return null;
    }
    if (y < this._top || y > this._top + this._heightPerItem * this._numItems ) {
      return null;
    }
    return Math.floor(( y - this._top ) / this._heightPerItem );
  },
  fillSlice: function( sliceNum, color ) {
    this._ctx.fillStyle = color;
    this._ctx.beginPath();
    this._ctx.moveTo(this._left, this._top + sliceNum * this._heightPerItem);
    this._ctx.lineTo(this._left + this._width, this._top+ sliceNum * this._heightPerItem);
    this._ctx.lineTo(this._left + this._width, this._top+ (sliceNum + 1) * this._heightPerItem);
    this._ctx.lineTo(this._left, this._top+ (sliceNum + 1) * this._heightPerItem);
    this._ctx.lineTo(this._left, this._top + sliceNum * this._heightPerItem);
    this._ctx.fill();
    this._ctx.stroke();
    this._ctx.save();
    this._ctx.mozTextStyle = "14pt sans serif";
    this._ctx.fillStyle = "black";
    this._ctx.translate( this._left + (this._width / 2 ), this._top + (sliceNum + 0.5)* this._heightPerItem);
    this._ctx.mozDrawText(sliceNum);
    this._ctx.restore();
  }
};


function PieMenu(innerRadius, outerRadius, numSpokes, canvas, subMenuSliceNum) {
  this._centerX = 0;
  this._centerY = 0;
  //this._optionsList = optionsList;
  this._numSpokes = numSpokes;
  this._innerRadius = innerRadius;
  this._outerRadius = outerRadius;
  this._visible = false;
  this._ctx = canvas.getContext("2d");
  this._lastChosen = null;
  this._oldSlice = null;
  this._subMenuSliceNum = subMenuSliceNum;
  this._subMenuVisible = false;
}
PieMenu.prototype = {
  onMouseDown: function( x, y ) {
    this.setCenter(x, y);
    this.draw();
    this._visible = true;
  },

  onMouseUp: function( x, y ) {
    this._lastChosen = this.getSliceNumFromPoint(x, y);
    redrawCanvas(this._ctx);
    this._oldSlice = null;
    this._visible = false;
  },
  onMouseMove: function( x, y ) {
    if (!this._visible) {
      return;
    }

    var slice = this.getSliceNumFromPoint(x, y);
    if (slice == this._subMenuSliceNum) {
      this.drawSubMenu();
      this._subMenuVisible = true;
    } else if (slice > this._numSpokes) {
      // mouse is in submenu
    } else if (this._subMenuVisible) {
      this.eraseSubMenu();
      this._subMenuVisible = false;
    }
    if (slice != this._oldSlice) {
      if (this._oldSlice != null)
        this.fillSlice(this._oldSlice, "white");
      if (slice != null)
        this.fillSlice(slice, "red");
      this._oldSlice = slice;
    }
  },
  getLastChosen: function() {
    return this._lastChosen;
  },
  setCenter: function( x, y ) {
    this._centerX = x;
    this._centerY = y;
  },
  moveToPolar: function( angle, distance ) {
    this._ctx.moveTo( this._centerX + distance * Math.cos(angle),
                      this._centerY + distance * Math.sin(angle) );
  },
  lineToPolar: function( angle, distance ) {
    this._ctx.lineTo( this._centerX + distance * Math.cos(angle),
                      this._centerY + distance * Math.sin(angle) );
  },
  renderTextPolar: function( angle, distance, text ) {
    this._ctx.mozTextStyle = "14pt sans serif";
    this._ctx.fillStyle = "black";
    this._ctx.save();
    this._ctx.translate(this._centerX + distance * Math.cos(angle),
                     this._centerY + distance * Math.sin(angle));
    this._ctx.mozDrawText(text);
    this._ctx.restore();
  },
  draw: function() {
    this._ctx.beginPath();
    this._ctx.arc(this._centerX, this._centerY, this._outerRadius,0,Math.PI*2,false);
    this._ctx.stroke();
    this._ctx.beginPath();
    this._ctx.arc(this._centerX, this._centerY, this._innerRadius,0,Math.PI*2,false);
    this._ctx.stroke();

    // The spokes:
    var angle = - Math.PI/this._numSpokes - Math.PI/2;
    for (var theta = 0; theta < this._numSpokes; theta++) {
      this._ctx.beginPath();
      this.moveToPolar(angle, this._innerRadius );
      this.lineToPolar(angle, this._outerRadius );
      this._ctx.stroke();
      this.renderTextPolar( angle + Math.PI/this._numSpokes, this._outerRadius * 3/4, 
                            (this._subMenuSliceNum == theta)?"Etc...":theta);
      angle += Math.PI * 2 / this._numSpokes;
    }
  },

  drawSubMenu: function() {
    var angleOfSlice = Math.PI*2 / this._numSpokes;

    var startAngle = this._subMenuSliceNum * angleOfSlice - Math.PI/4 - Math.PI/2;
    var endAngle = this._subMenuSliceNum * angleOfSlice + Math.PI/4 - Math.PI/2;
    this._ctx.beginPath();
    this.moveToPolar(startAngle, this._outerRadius );
    this.lineToPolar(startAngle, this._outerRadius * 2 );
    this._ctx.arc(this._centerX, this._centerY, this._outerRadius * 2, startAngle, endAngle, false);
    this.lineToPolar(endAngle, this._outerRadius );
    this._ctx.stroke();

    for (var theta = 0; theta < 4; theta++ ) {
      this._ctx.beginPath();
      this.moveToPolar( startAngle + theta*Math.PI/8, this._outerRadius);
      this.lineToPolar( startAngle + theta*Math.PI/8, this._outerRadius*2);
      this._ctx.stroke();
      this.renderTextPolar( startAngle + theta*Math.PI/8 + Math.PI/16, this._outerRadius * 3/2, 
                            this._numSpokes + theta);
    }
  },

  eraseSubMenu: function() {
    var angleOfSlice = Math.PI*2 / this._numSpokes;

    var startAngle = this._subMenuSliceNum * angleOfSlice - Math.PI/4 -0.01 - Math.PI/2;
    var endAngle = this._subMenuSliceNum * angleOfSlice + Math.PI/4 + 0.01- Math.PI/2;
    this._ctx.beginPath();
    this.moveToPolar(startAngle, this._outerRadius );
    this.lineToPolar(startAngle, this._outerRadius * 2 + 2 );
    this._ctx.arc(this._centerX, this._centerY, this._outerRadius * 2 + 2 , startAngle, endAngle, false);
    this.lineToPolar(endAngle, this._outerRadius );
    this._ctx.arc(this._centerX, this._centerY, this._outerRadius, endAngle, startAngle, true);
    this._ctx.fillStyle = "white";
    this._ctx.fill();
  },

  getSliceNumFromPoint: function( x, y ) {
    var deltaX = x - this._centerX;
    var deltaY = y - this._centerY;
    var distance = Math.sqrt( deltaX * deltaX + deltaY * deltaY );
    if (distance < this._innerRadius)
      return null;

    var angle = Math.atan2( deltaX, -1 * deltaY );
     if (angle < 0 ) {
      angle += Math.PI * 2;
    }
    var sliceWidth = Math.PI * 2 / this._numSpokes;
    angle += sliceWidth/2

    if (distance > this._outerRadius && this._subMenuVisible) {
        return this._numSpokes + 1;
    }

    var sliceNum = Math.floor( angle  / sliceWidth );
    while (sliceNum >= this._numSpokes)
      sliceNum -= this._numSpokes;
    while (sliceNum < 0)
      sliceNum += this._numSpokes;
    return sliceNum;
  },

  fillSlice: function( sliceNum, color ) {
    this._ctx.fillStyle = color;
    var sliceWidth = Math.PI * 2 / this._numSpokes;

    if (sliceNum >= this._numSpokes) {
      // a sub-menu item
      var newAngleStart = this._subMenuSliceNum * sliceWidth - Math.PI/4 - Math.PI/2;
      var theta = sliceNum - this._numSpokes;
      this._ctx.beginPath();
      this.moveToPolar( newAngleStart + theta*Math.PI/8, this._outerRadius);
      this.lineToPolar( newAngleStart + theta*Math.PI/8, this._outerRadius*2);
      this._ctx.arc(this._centerX, this._centerY, this._outerRadius * 2, newAngleStart + theta*Math.PI/8, newAngleStart + (theta+1)*Math.PI/8, false);
      this.lineToPolar( newAngleStart + (theta + 1)*Math.PI/8, this._outerRadius*2);
      this._ctx.arc(this._centerX, this._centerY, this._outerRadius, newAngleStart + (theta+1)*Math.PI/8, newAngleStart + theta*Math.PI/8, true);
      this.lineToPolar( newAngleStart + theta*Math.PI/8, this._outerRadius);
      this._ctx.fill();
      this._ctx.stroke();
      this.renderTextPolar( newAngleStart + theta*Math.PI/8 + Math.PI/16, this._outerRadius * 3/2, 
                            sliceNum );
    } else {
     // a main-menu item


      var newAngleStart = sliceNum * sliceWidth - Math.PI/2 - sliceWidth/2;
      var newAngleEnd = sliceNum * sliceWidth - Math.PI/2 + sliceWidth/2;

      this._ctx.beginPath();
      this._ctx.arc(this._centerX, this._centerY, this._innerRadius, newAngleStart, newAngleEnd, false);
      this._ctx.arc(this._centerX, this._centerY, this._outerRadius, newAngleEnd, newAngleStart, true);
      this._ctx.fill();
      this._ctx.stroke();
      this.renderTextPolar( (newAngleStart + newAngleEnd)/2,
                             this._outerRadius * 3/4,
                             (sliceNum == this._subMenuSliceNum)?"Etc...":sliceNum );
    }
  }
};

function GridMenu( canvas, squareSize, stringList, isSubMenu ) {
  this._left = 0;
  this._top = 0;
  this._timeDelay = 250; //ms -- if mouse released before this time elapsed, stay open and wait for a 
   //second click.
  this._squareSize = squareSize;
  //this._optionsList = optionsList;
  this._visible = false;
  this._ctx = canvas.getContext("2d");
  this._lastChosen = null;
  this._oldCell = null;
  this._invokeTime = 0;

  if (isSubMenu) {
    this._isSubMenu = true;
  } else {
    this._isSubMenu = false;
  }

  if (stringList.length > 8 ) {
    this._stringList = stringList.slice(0, 7);
    this._stringList.push( ["Search...", null] );
    this._subMenu = new GridMenu( canvas, squareSize, stringList.slice( 7 ), true );
  } else {
    this._stringList = stringList;
    this._subMenu = null;
  }

  this._commands = [];
  for( var i = 0; i < this._stringList.length; i++ ) {
    this._commands.push( { name: this._stringList[i][0], icon: this._stringList[i][1]} );
  }
}
GridMenu.prototype = {
  onMouseDown: function(x, y) {
    if (this._visible) {
      return;
    }
    this._invokeTime = new Date().getTime();
    this._left = x - this._squareSize * 1.5;
    this._top = y - this._squareSize * 1.5;
    if (this._left < 0) {
      this._left = 0;
    }
    if (this._top < 0) {
      this._top = 0;
    }
    if (this._left > 600 - this._squareSize * 3 ) {
      this._left = 600 - this._squareSize * 3;
      if (this._isSubMenu) {
        this._top += this._squareSize;
      }
    }
    if (this._top > 600 - this._squareSize * 3 ) {
      this._top = 600 - this._squareSize * 3;
      if (this._isSubMenu) {
        this._left += this._squareSize;
      }
    }
    this._draw();
    this._visible = true;
  },
  onMouseUp: function(x, y) {
    if (this._visible) {
      var now = new Date().getTime();
      if ( now - this._invokeTime > this._timeDelay ) {
        redrawCanvas(this._ctx);
        this._lastChosen = this._getCellNumFromPoint( x, y );
        this._visible = false;
      }
    }
  },
  onMouseMove: function(x, y) {
    if (!this._visible) {
      return;
    }
    var cellNum = this._getCellNumFromPoint(x, y);
    if (cellNum >= 8 ) {
      return this._subMenu.onMouseMove(x, y);
    }

    if (this._subMenu) {
      if (cellNum == 7 && !this._subMenu._visible) {
        this._subMenu.onMouseDown(this._left + 3.5 * this._squareSize, this._top + 3.5 * this._squareSize);
      } else if (cellNum < 7 && this._subMenu._visible) {
        this._subMenu.onMouseUp(this._left + 3.5 * this._squareSize, this._top + 3.5 * this._squareSize);
        this._draw();
      }
    }
    if (cellNum != this._oldCell) {
      if (this._oldCell != null)
        this._fillSquare(this._oldCell, "white");
      if (cellNum != null)
        this._fillSquare(cellNum, "red");
      this._oldCell = cellNum;
    }
  },
  _getCellNumFromPoint: function( x, y ) {
    var col = Math.floor( ( x - this._left ) / this._squareSize );
    var row = Math.floor( ( y - this._top ) / this._squareSize );
    if ( this._subMenu && this._subMenu._visible && (col > 2 || row > 2) ) {
      return (this._subMenu._getCellNumFromPoint(x, y) + 8 );
    }
    if (col < 0) col = 0;
    if (col > 2) col = 2;
    if (row < 0) row = 0;
    if (row > 2) row = 2;
    return this._colRowToCellNum(col, row);
  },

  getLastChosen: function() {
    return this._lastChosen;
  },

  _draw: function() {
    this._ctx.moveTo( this._left, this._top );
    this._ctx.lineTo( this._left + 3 * this._squareSize, this._top );
    this._ctx.lineTo( this._left + 3 * this._squareSize, this._top + 3 * this._squareSize );
    this._ctx.lineTo( this._left, this._top + 3 * this._squareSize );
    this._ctx.lineTo( this._left, this._top );
    this._ctx.stroke();

    this._ctx.moveTo( this._left + this._squareSize, this._top );
    this._ctx.lineTo( this._left + this._squareSize, this._top + 3 * this._squareSize );
    this._ctx.stroke();

    this._ctx.moveTo( this._left + this._squareSize * 2, this._top );
    this._ctx.lineTo( this._left + this._squareSize * 2, this._top + 3 * this._squareSize );
    this._ctx.stroke();

    this._ctx.moveTo( this._left, this._top + this._squareSize);
    this._ctx.lineTo( this._left + this._squareSize * 3, this._top +  this._squareSize );
    this._ctx.stroke();

    this._ctx.moveTo( this._left, this._top + this._squareSize * 2);
    this._ctx.lineTo( this._left + this._squareSize * 3, this._top +  this._squareSize * 2);
    this._ctx.stroke();

    for (var i = 0; i < 8; i++) {
      if ( i < this._commands.length )
        this._renderTextInSquare(this._commands[i], i);
    }
  },

  _cellNumToColRow: function(cellNum) {
    var table;
    if (this._isSubMenu) {
      table = [[1, 0], [2, 0], [0, 1], [1, 1], [2, 1], [0, 2], [1, 2], [2, 2]];
    } else {
      table = [[0, 0], [1, 0], [2, 0], [0, 1], [2, 1], [0, 2], [1, 2], [2, 2]];
    } 
    return table[cellNum];
  },

  _colRowToCellNum: function(col, row) {
    var table;
    if (this._isSubMenu) {
      table = [[1, 0], [2, 0], [0, 1], [1, 1], [2, 1], [0, 2], [1, 2], [2, 2]];
    } else {
      table = [[0, 0], [1, 0], [2, 0], [0, 1], [2, 1], [0, 2], [1, 2], [2, 2]];
    } 
    for ( var i = 0; i < 8; i++ ) {
      if (table[i][0] == col && table[i][1] == row)
        return i;
    }
    return null;
  },

  _renderTextInSquare: function(commandObj, cellNum) {
    this._ctx.mozTextStyle = "12pt sans serif";
    this._ctx.fillStyle = "black";
    this._ctx.save();
    var colRow = this._cellNumToColRow(cellNum);
    var col = colRow[0];
    var row = colRow[1];
    var margin = 5; // five pixels
    this._ctx.translate(this._left + this._squareSize * col + margin, this._top + this._squareSize * (row + 1) - margin );
    this._ctx.mozDrawText(commandObj.name);
    this._ctx.restore();

    if (commandObj.icon) {
      var img = new Image();
      var ctx= this._ctx;
      var x = this._left + this._squareSize * col + margin;
      var y = this._top + this._squareSize * row + margin;
      img.onload = function(){ ctx.drawImage(img, x, y);  };
      img.src = commandObj.icon;
      /*this._ctx.save();
      this._ctx.translate(this._left + this._squareSize * col + margin, this._top + this._squareSize * (row) + 12 + margin );
      this._ctx.mozDrawText(commandObj.icon);
      this._ctx.restore();*/
    }
  },

  _fillSquare: function( cellNum, color ) {
    this._ctx.fillStyle = color;
    var colRow = this._cellNumToColRow(cellNum);
    var col = colRow[0];
    var row = colRow[1];
    this._ctx.beginPath();
    this._ctx.moveTo(this._left + this._squareSize * col, this._top + this._squareSize * row );
    this._ctx.lineTo(this._left + this._squareSize * col, this._top + this._squareSize * (row + 1) );
    this._ctx.lineTo(this._left + this._squareSize * (col + 1), this._top + this._squareSize * (row + 1) );
    this._ctx.lineTo(this._left + this._squareSize * (col + 1), this._top + this._squareSize * row );
    this._ctx.lineTo(this._left + this._squareSize * col, this._top + this._squareSize * row );
    this._ctx.fill();
    this._ctx.fillStyle = "black";
    this._ctx.stroke();
    if (cellNum < this._commands.length )
      this._renderTextInSquare(this._commands[cellNum], cellNum);
  }
};

function redrawCanvas(context) {
  context.fillStyle = "white";
  context.clearRect(0, 0, 600, 600);
  context.beginPath();
  context.moveTo(1, 1);
  context.lineTo(599, 1);
  context.lineTo(599, 599);
  context.lineTo(1, 599);
  context.lineTo(1, 1);
  context.stroke();
}


function writeOnCanvas( message, canvas ) {
  var ctx = canvas.getContext("2d");
  redrawCanvas(ctx);
  ctx.mozTextStyle = "14pt sans serif";
  ctx.fillStyle = "black";
  ctx.save();
  ctx.translate(250, 250);
  ctx.mozDrawText(message);
  ctx.restore();
}
