var log = function(str) {
return;
	if (console && console.log) { 
		console.log(str); 
	} else { 
		//alert(str); 
	}
};
log("wtf");

// This rounded rectangle function is adapted from an example from:
// http://developer.mozilla.org/en/Canvas_tutorial/Drawing_shapes
// Prolly should incorporate this as a part of the Camima class
var roundedRect = function(ctx,x,y,width,height,radius){
  ctx.beginPath();
  ctx.moveTo(x,y+radius);
  ctx.lineTo(x,y+height-radius);
  ctx.quadraticCurveTo(x,y+height,x+radius,y+height);
  ctx.lineTo(x+width-radius,y+height);
  ctx.quadraticCurveTo(x+width,y+height,x+width,y+height-radius);
  ctx.lineTo(x+width,y+radius);
  ctx.quadraticCurveTo(x+width,y,x+width-radius,y);
  ctx.lineTo(x+radius,y);
  ctx.quadraticCurveTo(x,y,x,y+radius);
  ctx.fill();
  ctx.stroke();
}



log('loading camima');
//////////////////////////////////////////////////////////////////////////
// Camima - a canvas based mind map tool
// Written by Mikael Roos
// Copyright Nodeta Oy 2008
//////////////////////////////////////////////////////////////////////////
//
// DONE:
// * children of children
// * active node - nodes can be activated by clicking them
//  * active node is used as parent when new nodes are created   
// * children ordered by their position going counter-clockwise starting from top-right
//  * Key navigation for moving between nodes
//   * Up-key for parent 
//   * Down key for first child
//   * Left and right keys for siblings in the order of the array
// TODO:
//   * What keys for creating new child/sibling? Maybe (+) and (=) keys for creating new child 
//
// * Undo
//  * Store a history of root node states
//  * Store states by making a custom event handler and firing custom events in all modifying functions
//  * Whe undoing, render the whole thing from scratch
//  * Same thing with redoing
//  * On undo + new action, wipe the "redo buffer" clean
// 
// * Accepting nodes that are not positioned
//  * Make it possible to accept nodes without positions so that a position will be determined for them 
//	  based on their order in the array and other nodes' positions
//  * This way it is easier to use the tool in combination with other "clients" that might not determine 
//	  the positions - say an iPhone interface
//
// * Persisting the data
//  * Callbacks for persisting: "onchange"
//	* Only send changed parts
//	* Full support for node IDs

Camima = Class.create();
Camima.prototype = {
	initialize: function(container, root, options) {
		this.container = container;		
		this.root = new CamimaNode(root || {
			content: "Subject",
			position: {top: 300, left: 300}
		});
		this.root.camima = this;
		this.root.render();
		this.container.observe('dblclick', this.handleDoubleClicks.bindAsEventListener(this));
		this.container.observe('click', this.handleClicks.bindAsEventListener(this));
		document.observe('keypress', this.handleKeyPresses.bindAsEventListener(this));
    this.setActiveNode(this.root);
    
	},
  handleClicks: function(event) {
//    this.setActiveNode(null);
  },
	handleDoubleClicks: function(event) {
		var element = event.element();
		if (!element.match('div.Camima')) {
			event.stop();
			return;
		}

		(this.activeNode || this.root).addChild(new CamimaNode({
			position: {left: event.pointerX(), top: event.pointerY()},
			content: '-edit-'
		}));
		
	},
	handleKeyPresses: function(event) {
	  console.log(event);
		if (event.keyCode == Event.KEY_DOWN) {
		  var node = (this.activeNode && this.activeNode.children.first()) ? this.activeNode.children[0] : this.root;
		  this.setActiveNode(node);
		} else if ((event.keyCode == Event.KEY_UP) && this.activeNode) {
		  this.setActiveNode(this.activeNode.parent);
	  } else if (event.keyCode == Event.KEY_RIGHT && this.activeNode && this.activeNode.parent) {
	    var children = this.activeNode.parent.children;
	    this.setActiveNode(children[children.indexOf(this.activeNode) + 1] || children.first());
	  } else if (event.keyCode == Event.KEY_LEFT && this.activeNode && this.activeNode.parent) {
	    var children = this.activeNode.parent.children;
	    this.setActiveNode(children[children.indexOf(this.activeNode) - 1] || children.last());
	  } else if (event.keyCode == Event.KEY_RETURN) {
	    this.activeNode.editContent();
	  } else if (event.keyCode == Event.KEY_BACKSPACE) {
	    this.activeNode.destroy();
	  } else if (event.charCode == 43) {// plus sign
	    var node = (this.activeNode || this.root);
	    var os = node.container.cumulativeOffset();
  		node.addChild(new CamimaNode({
  			position: {left: os.left+60, top: os.top+60},
  			content: '-edit-'
  		}));
	  }
	  
	},
	setActiveNode: function(node) {
	  if (this.activeNode)
	    this.activeNode.container.removeClassName('active');
	  if(node)
	    node.container.addClassName('active');
	  this.activeNode = node;
	  // remove class from prev
	  // set class to node
	  // set node as active
	}
	// Toolbar stuff etc.
};


CamimaNode = Class.create();
CamimaNode.prototype = {
	initialize: function(options) {
		//parent, children, position, size, content
		this.canvas = null;
		this.id = options.id;
		this.parent = options.parent;
		this.children = options.children ? options.children.map(function(node) {
			node.parent = this;
			return new CamimaNode(node);
		}.bind(this) ) : [];
		this.position = options.position;
		this.content = options.content;
		
		this.container = null;
		this.contentContainer = null;
		this.canvas = null;
	},
	render: function() {
		this.container = new Element('div', {
				'class': 'CamimaNode'
			}).setStyle({'left': this.position.left + 'px',
						 'top': this.position.top + 'px' });
						
		this.canvas = new Element('canvas', {'class': 'CamimaNodeCanvas' });	

		this.contentContainer = new Element('div', {'class': 'CamimaContent'});
		if (this.parent)
			this.container.addClassName('secondary');
		
		this.container.update(this.contentContainer);
		this.container.insert({top: this.canvas});

		this.camima.container.insert({bottom: this.container}); // Insert node into the Camima container

		this.container.observe('dblclick', this.handleDoubleClicks.bindAsEventListener(this));

    this.container.observe('click', this.handleClicks.bindAsEventListener(this));

		new Draggable(this.container, {
			onDrag: function(elem) {
				this.position = { 	left: parseInt(this.container.getStyle('left')),
									top: parseInt(this.container.getStyle('top')) }
				this.draw();
			}.bind(this),
			startEffect: null,
			endEffect: null
		});


		this.updateContent();

	},
	handleClicks: function(event) {
	  if (this.container.hasClassName('active')) return;
	  this.camima.setActiveNode(this);
	},
	handleDoubleClicks: function(event) { // DOUBLECLICKS!
		if (event.element().match('textarea')) return;
		this.editContent();
		event.stop();
	},
	addChild: function(node) {
		node.camima = this.camima;
		node.parent = this;
		this.children.push(node);
		node.render();
		node.editContent(node);
	},
	editContent: function() {
		var editor;
		editor = new Element('textarea', {'style':  'width: ' + this.contentContainer.getWidth() + 'px; ' +
													'height: ' + this.contentContainer.getHeight() + 'px;'});
		editor.update(this.content);
		this.contentContainer.update(editor);
		this.cachedStopEditing = this.stopEditing.curry(editor).bindAsEventListener(this);
		this.cachedKeypressHandler = this.handleEditorKeypresses.bindAsEventListener(this);
		document.observe('click', this.cachedStopEditing);
		editor.observe('keypress', this.cachedKeypressHandler);
		editor.select();
		this.draw();
	},
	handleEditorKeypresses: function(event) {
		log(event);
		var editor = event.element();
		if (event.keyCode == Event.KEY_RETURN) {
			this.stopEditing(editor, event);
		} else if (event.charCode!=0 || [Event.KEY_BACKSPACE, Event.KEY_DELETE].include(event.keyCode)) {
			var actualWidth = editor.getWidth();
			editor.setStyle({width: ((editor.scrollWidth > actualWidth) ? editor.scrollWidth+10 : actualWidth+3) + 'px',
							 height: editor.scrollHeight + 'px'});
			this.draw();
		}		
	},
	stopEditing: function(editor, event) {
		var element = event.element();
		if (element.match('textarea') && event.type == 'click') return;
		document.stopObserving('click', this.cachedStopEditing);
		editor.stopObserving('keypress', this.cachedKeypressHanler);
		this.cachedStopEditing = null;
		this.cachedKeypressHandler = null;
		this.setContent(editor.value);
		this.camima.setActiveNode(this);
		event.stop();
	},
	setContent: function(content) {
		this.content = content;
		this.updateContent();
	},
	updateContent: function() {
		this.contentContainer.update(this.content);
		this.draw();
	},
	draw: function() {
		// get fresh dimensions
		
		var height, width;

		// Set width first, because it may change the height
		width = this.contentContainer.getWidth();
		this.container.setStyle({'width': width + 'px'});

		// then get height and set it
		height = this.contentContainer.getHeight();
		this.container.setStyle({'height': height + 'px'});

		this.canvas.width = width;
		this.canvas.height = height;

		// get context and config some styles
		ctx = this.canvas.getContext('2d');
//		log(ctx);
		log(this.canvas);
		ctx.lineJoin = "round";
		if (this.parent) {
			ctx.fillStyle = "rgb(220,220,12)"			
			ctx.lineWidth = 1;
		} else { // is root
			ctx.fillStyle = "rgb(32,90,200)";
			ctx.lineWidth = 2;
		}
		ctx.lineStyle = "rgb(0,0,50)";
		ctx.lineCap = 'round';

		// TODO: clear canvas
log(width);
log(height);
		// draw on canvas
//		ctx.shadowColor = 'rgba(0, 0, 20, 0.63)';
//	    ctx.shadowOffsetX = 4;
//	    ctx.shadowOffsetY = 4;
//		ctx.shadowBlur = 10;

		roundedRect(ctx,1,1,width-2,height-2, 15);
		

//		ctx.fillRect (0, 0, width, height);
//		ctx.strokeRect(0, 0, width, height);
		
		// TODO: draw all connections to children and parent
		if (this.parent)
			this.drawConnectionTo(this.parent);

		this.children.each(this.drawConnectionTo.bind(this));
	},
	drawConnectionTo: function(node) {
log('drawing connection from ' + this.content + ' to ' + node.content);
		var pos1, pos2, left1, left2, top1, top2, left, top, width, height, controlX, controlY, canvasPadding, ctx;
		canvasPadding = 20;
		pos1 = node.position;
		pos2 = this.position;
		left1 = pos1.left + node.container.getWidth()/2;
		left2 = pos2.left + this.container.getWidth()/2;
		top1 = pos1.top + node.container.getHeight()/2;
		top2 = pos2.top + this.container.getHeight()/2;
		
		
		left = Math.min(left1,left2);
		width = Math.abs(left1-left2);
		top = Math.min(top1,top2);
		height = Math.abs(top1-top2);
		
		controlX = width/2;
		controlY = (height/2)-30;
		//Math.abs(left1-left2), Math.abs(top1-top2)
		
		// resolve child
		child = ((this.parent == node) ? this : node);
		if (child.parentConnectionCanvas) {
			child.parentConnectionCanvas.remove();
			child.parentConnectionCanvas = null;
		}
		
		child.parentConnectionCanvas = new Element('canvas', {
			'class': 'CamimaRelationCanvas',
			'height': height+2*canvasPadding,
			'width': width+2*canvasPadding
		}).setStyle({
			'left': left-canvasPadding+'px',
			'top': top-canvasPadding+'px'
		});
		
		ctx = child.parentConnectionCanvas.getContext('2d');
		ctx.lineStyle = "rgb(0,0,50)";
		ctx.lineWidth = 2;
		ctx.moveTo(left1-left+canvasPadding, top1-top+canvasPadding);
		ctx.quadraticCurveTo(controlX+canvasPadding, controlY+canvasPadding, left2-left+canvasPadding, top2-top+canvasPadding);
		ctx.stroke();
		this.camima.container.insert({bottom: child.parentConnectionCanvas});
	},
	getData: function() {
		return { children: this.children.invoke("getData"), position: this.position, content: this.content };
	},
	toJSON: function() {
		return Object.toJSON(this.getData());
	},
	destroy: function() {
	  this.container.remove();
    if (this.parentConnectionCanvas)
	    this.parentConnectionCanvas.remove();
	  this.children.invoke('destroy');
	}

};
