/**
 * 
 * @author Hahm Myung Sun (hms1475@gmail.com)
 *
 * Copyright (c) 2011 JinoTech (http://www.jinotech.com) 
 * Licensed under the LGPL v3.0 license (http://www.gnu.org/licenses/lgpl.html).
 */

var removeGradient = function(node){
	bodyAttr = node.body.attr();
	delete bodyAttr.gradient;
	node.body.attr({fill: node.background_color, stroke: node.edge.color});
}
	
///////////////////////////////////////////////////////////////////////////////
/////////////////////////// jNodeController ///////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

jNodeController = function(map){
	this.map = map;
}

jNodeController.prototype.type= "jNodeController";


jNodeController.prototype.mousedown = function(e){
	var selectedNodes = jMap.getSelecteds();
	
	// 마우스 오른쪽 버튼
	// IE : e.button == 2
	// FF : e.button == 2, e.which == 3
	// Mac : e.button == 2, e.which == 3
	if(e.button == 2){
		jMap.mouseRightClicked = true;
		jMap.mouseRightSelectedNode = this;
	}
	
	// 노드 하일라이팅
	if (e.ctrlKey){
		if(selectedNodes.contains(this))
			this.blur();
		else this.focus(false);	// control키 조합시 중복 선택
	} 
	else{
		if(!selectedNodes.contains(this)) {
			this.focus(true);
		}
	}
	
	//e.preventDefault && e.preventDefault();
}

jNodeController.prototype.mouseup = function(e){
	e = e || window.event;
	
	// 오른쪽 마우스 땠을때
	if(jMap.mouseRightClicked) {
		var mouseRightSelectedNode = jMap.mouseRightSelectedNode;
		jMap.mouseRightClicked = false;
		//this.blur();
		if(mouseRightSelectedNode == this) return;
		
//		var arrow = new ArrowLink(this);
		var arrowlink = null;
		switch(jMap.layoutManager.type) {
			case "jMindMapLayout" :
				arrowlink = new CurveArrowLink(this);
				break;
			case "jTreeLayout" :
				arrowlink = new RightAngleArrowLink(this);
				break;
			default :
		}
		
		mouseRightSelectedNode.addArrowLink(arrowlink);
		jMap.layoutManager.layout(true);
	}
	
	// 움직이는 노드를 놓았을 때
	if (jMap.movingNode && !jMap.movingNode.removed) {
		var srcNodes = jMap.positionChangeNodes;
		var targNode = this;
		
		if (srcNodes && !srcNodes.contains(targNode)) {
			jMap.movingNode.connection && jMap.movingNode.connection.line.remove();
			jMap.movingNode.remove();
			
			// 자식 밑으로 옮기는지 체크. 그렇다면 무시..
			for (var i = 0; i < srcNodes.length; i++) {
				if (srcNodes[i].hadChildren(targNode)) {
					removeGradient(targNode);
					//targNode.body.animate({"fill-opacity": 0}, 500);
					jMap.positionChangeNodes = false;
					return;
				}
			}
			
			var offsetX = (e.offsetX) ? e.offsetX : e.layerX - this.getLocation().x;
			var widthHalf = this.body.getBBox().width / 2;
			//var pos = (this.isLeft()) ? (offsetX > widthHalf) : (offsetX < widthHalf);
			var isleftPos = (offsetX < widthHalf);
			
			// 노드를 자식으로 옮기는 함수
			var toChild = function() {
				
				// 노드를 펼친다.
				targNode.folded && targNode.setFolding(false);
				
				var position = null;
				if (targNode.isRootNode()) 
					position = isleftPos ? "left" : "right";
				
				jMap.changePosition(targNode, srcNodes, position);
				
			}
			// 노드를 형제로 옮기는 함수
			var toSibling = function() {
				
				var position = null;
				if (targNode.getParent().isRootNode()) 
					position = targNode.position;
				var nextSibling = targNode.nextSibling();
				
				jMap.changePosition(targNode.getParent(), srcNodes, position, targNode);
				
			}
			
			if (srcNodes) {
				if (targNode.isRootNode()) {
					toChild();
				} else {
					switch(jMap.layoutManager.type) {
						case "jMindMapLayout" :
							if(this.isLeft()){
								isleftPos? toChild():toSibling();
							} else {
								isleftPos? toSibling():toChild();
							}	
							break;
						case "jTreeLayout" :
							isleftPos? toSibling():toChild();
							break;
						default :			
					}
				}				
				// 노드 옮김 완료!
			}
			
			removeGradient(targNode);
			jMap.initFolding(targNode);
			jMap.layoutManager.updateTreeHeightsAndRelativeYOfWholeMap();
			//		jMap.layoutManager.updateTreeHeightsAndRelativeYOfDescendants(targNode.isRootNode()? targNode : targNode.parent);
			jMap.layoutManager.layout(true);
			targNode.focus(true);
		}
		
		jMap.positionChangeNodes = false;
	}
}

jNodeController.prototype.mousemove = function(e){
	e = e || window.event;
	
	// 폴딩되는 노드라면 커서 모양 변경
	if(!jMap.positionChangeNodes && this.isFoldingHit(e) && !this.isRootNode() && !this.getChildren().isEmpty()) {
		document.body.style.cursor = "url('/images/folding_blue.png'),default";
		//document.body.style.cursor = "crosshair";
	} else {
		document.body.style.cursor = "auto";
	}
	
}

jNodeController.prototype.mouseover = function(e){
	e = e || window.event;
	
//		if (this.note) {
//			// Remove default browser tooltips
//			this.t = this.note;
//			this.title = '';
//			this.alt = '';
//						
//			jMap.tootipHandle.html(this.t).fadeIn('fast');
//		}

	if (jMap.positionChangeNodes && !jMap.getSelecteds().contains(this)) {
		if(jMap.movingNode && !jMap.movingNode.removed){
			jMap.movingNode.hide();
			jMap.movingNode.connection && jMap.movingNode.connection.line.hide();
		}
		
		var offsetX = (e.offsetX)? e.offsetX : e.layerX - this.getLocation().x;		
		var widthHalf = this.body.getBBox().width/2;
						
		if (jMap.positionChangeNodes) {
			//			   270
			//	  -------------------
			//	0 |					| 180
			//	  -------------------
			//			   90
			var angleLeft = 0;
			var angleRight = 0;
			
			switch(jMap.layoutManager.type) {
				case "jMindMapLayout" :
					if(this.isRootNode()) {
						angleLeft = 0;
						angleRight = 180;
					} else {
						angleLeft = (this.isLeft())? 0 : 270;
						angleRight = (this.isLeft())? 270 : 180;
					}
					break;
				case "jTreeLayout" :
					if(this.isRootNode()) {
						angleLeft = 180;
						angleRight = 180;
					} else {
						angleLeft = 0;	// 원래 0 이지만 jMindMapLayout와 호환을 위해 (mouseup 이벤트의 내용도  jTreeLayout를 고려한다면 0으로 해도 좋다)
						angleRight = 90;	// 이도 역시.. 90이지만 0으로..
					}
					break;
				default :			
			}
			
			//var pos = (this.isLeft())? (offsetX > widthHalf) : (offsetX < widthHalf);
			if(offsetX < widthHalf)	// 마우스가 노드 왼쪽 편에 있으면 true
				//this.body.attr({gradient: angleRight + "-#ffffff-"+NODE_DROP_FOCUS_COLOR, stroke: NODE_DROP_FOCUS_COLOR});
				this.body.attr({gradient: angleLeft + "-" + NODE_DROP_FOCUS_COLOR + "-#ffffff", stroke: NODE_DROP_FOCUS_COLOR});
			else
				//this.body.attr({gradient: angleLeft + "-#ffffff-"+NODE_DROP_FOCUS_COLOR, stroke: NODE_DROP_FOCUS_COLOR});
				this.body.attr({gradient: angleRight + "-" + NODE_DROP_FOCUS_COLOR + "-#ffffff", stroke: NODE_DROP_FOCUS_COLOR});
	    }		
	}
	
	
	if(jMap.mouseRightClicked){		
		this.focus(false);
	}
	
}

jNodeController.prototype.mouseout = function(e){
	document.body.style.cursor = "auto";
	
//		if (this.t) {
//            this.title = this.t;
//            jMap.tootipHandle.hide();
//        }
	
	if(jMap.movingNode && !jMap.movingNode.removed){
		jMap.movingNode.show();
		jMap.movingNode.connection && jMap.movingNode.connection.line.show();
	}
	
	if (jMap.positionChangeNodes && !jMap.getSelecteds().contains(this)) {
		removeGradient(this);			
    }
	
	
	if(jMap.mouseRightClicked) {
		if(jMap.mouseRightSelectedNode == this) return;
		this.blur();
	}
	
}

jNodeController.prototype.click = function(e){
	var targ;
	if (!e) var e = window.event;
	if (e.target) targ = e.target;
	else if (e.srcElement) targ = e.srcElement;
	if (targ.nodeType == 3) // defeat Safari bug
		targ = targ.parentNode;
	
	// 노드의 끝쪽 부분을 클릭하면 폴딩 및 언폴딩	
	// ** 하이퍼링크를 클릭시에는 폴딩되지 말아야 한다.
	// ** 그래서 image를 검사한다. (hyperlink는 그림을 클릭하므로..)
	if (this.isFoldingHit(e) && targ.nodeName != "image") {
		// Folding & unFolding
		jMap.controller.foldingAction(this);		
	}
	
}

jNodeController.prototype.dblclick = function(e){		
	jMap.controller.startNodeEdit(this);
}

jNodeController.prototype.dragstart = function(e){
	// FF의 버그 때문에.. dragstart를 사용한다.
	// FF는 노드 드래그 이벤트가 두번째부터 먹는다.
	// 그런데 이 이벤트가 먹음 마우스업 이라든가 이런 이벤트는 무시된다.
	// 원인은 잘 모르겠지만 어차피 여기선 쓰지 못하므로 무시..
	e = e || window.event;
	if (e.preventDefault)
		e.preventDefault();
	else
		e.returnValue= false;
}

jNodeController.prototype.dragenter = function(e){
	e = e || window.event;
	if (e.preventDefault)
		e.preventDefault();
	else
		e.returnValue= false;
		
	this.focus(true);
}

jNodeController.prototype.dragexit = function(e){
	e = e || window.event;
	if (e.preventDefault)
		e.preventDefault();
	else
		e.returnValue= false;
	
	this.blur();
//	var selectedNodes = jMap.getSelecteds();
//	var node = null;
//	while(node = selectedNodes.pop())
//		node.body.animate({fill: node.background_color,
//								stroke: node.edge.color,
//								"stroke-width": node.stroke_width}, 300);					
}

jNodeController.prototype.drop = function(e){
	e = e || window.event;
	if (e.preventDefault)
		e.preventDefault();
	else
		e.returnValue= false;
	
	var droptext = e.dataTransfer.getData('TEXT') || e.dataTransfer.getData('text/plain');	// TEXT는 IE, text/plain은 FF
	var urlText = e.dataTransfer.getData('URL');
	var isUpdateLayout = false;
	
	// 일반 텍스트라도 접두사가 http라면 url로 인식한다.
	if(droptext.substr(0,7) == "http://"){
		urlText = urlText || droptext;
		
		// 링크 설정
		if(urlText){
			this.setFoldingExecute(false);
			var newNode = jMap.createNodeWithCtrl(this, urlText);
			newNode.setHyperlink(urlText);
			isUpdateLayout = true;
		}
	} else {
		jMap.createNodeFromText(this, droptext);
		isUpdateLayout = true;
	}
	 
	if(isUpdateLayout) {
		jMap.layoutManager.updateTreeHeightsAndRelativeYOfDescendantsAndAncestors(this);
		jMap.layoutManager.layout(true);
	}
}


///////////////////////// extend ////////////////////////////////////


jNodeController.prototype.dragger = function () {
}

jNodeController.prototype.move = function (dx, dy, x, y) {
	if(jMap.mouseRightClicked) return;
	
	if(!jMap.movingNode || jMap.movingNode.removed && !jMap.mouseRightClicked){
		// 옮겨질 노드 설정
		var selectedNodes = jMap.getSelecteds();	
		jMap.positionChangeNodes = selectedNodes;
	
		// 쉐도우 노드 생성
		// jNode로 안만드는 이유는 jNode로 만들면 노드를 드래그 하는 동안 노드 밑에 위치한 노드를 잡아내지 못하기 때문이다.
		// mNode.toBack()을 하는 이유도 그런 이유이다.
		jMap.movingNode = RAPHAEL.rect();
		var mNode = jMap.movingNode;		
		
		mNode.ox = this.body.type == "rect" ? this.body.attr("x") : this.body.attr("cx");
	    mNode.oy = this.body.type == "rect" ? this.body.attr("y") : this.body.attr("cy");
		
		var bodyAttr = this.body.attr();						// body
		delete bodyAttr.scale;
		delete bodyAttr.translation;
		delete bodyAttr.gradient;	
		bodyAttr["fill-opacity"] = .2;
		bodyAttr.fill = this.background_color
		bodyAttr.stroke = this.edge.color;
		mNode.attr(bodyAttr);
		
		mNode.toBack();
		
		/*
		if(!this.isRootNode()){			
			mNode.edge_width = this.edge.width;
			mNode.connection = JinoUtil.connectionShadow(this.parent.body, mNode, this.connection.line.attr().stroke, this.isLeft()? true : false);
			mNode.connection.line.attr({fill: this.connection.line.attr().fill, "fill-opacity":.2, "stroke-opacity":.2});
		}
		*/
	}
	
	var mNode = jMap.movingNode;
//	mNode.setLocation(mNode.ox + dx, mNode.oy + dy);	// 노드를 복사하는 방법
	
	// 스케일된 상태에 따라 노드
	var sdx = dx / jMap.cfg.scale;
	var sdy = dy / jMap.cfg.scale;
	
	var att = mNode.type == "rect" ? {x: mNode.ox + sdx, y: mNode.oy + sdy} : {cx: mNode.ox + sdx, cy: mNode.oy + sdy};
	mNode.attr(att);
	//mNode.connection && JinoUtil.connectionShadow(mNode.connection, null, null, this.isLeft()? true : false);
	
}
		
jNodeController.prototype.up = function (dx, dy, x, y) {
	if(jMap.movingNode && !jMap.movingNode.removed){
		jMap.movingNode.connection && jMap.movingNode.connection.line.remove();
		jMap.movingNode.remove();
		
		var sdx = dx / jMap.cfg.scale;
		var sdy = dy / jMap.cfg.scale;
		
		var testMovePosX = (sdx>0)?sdx:-sdx;
		var testMovePosY = (sdy>0)?sdy:-sdy;		
		if(testMovePosX > NODE_MOVING_IGNORE || testMovePosY > NODE_MOVING_IGNORE)
			this.relativeCoordinate(sdx, sdy);
	}
}

///////////////////////// extend 끝////////////////////////////////////


