// Copyright 2008 ProjectWizards GmbH. All rights reserved.

//console.log("GanttSVGView.js");

var GanttSVGView = GanttView.extend({
	constructor: function(scrollView, container, ganttRuler, environment, drawShadows){
		this.base(environment, ganttRuler, scrollView, drawShadows);
		this.svgns = "http://www.w3.org/2000/svg";
		this.container = container;
		this.container.style.overflowX = "auto";
		this.shadowColor = "#222222";
		this.shadowOpacity = 0.1;
		this.leftBorderSize = 30;
		this.rightBorderSize = 20;
		this.endDate = new Date();
		this.createGantt();
	},

	createGantt: function()	{
		this.recreateLabelContainer();
		this.canvas = $(document.createElementNS(this.svgns, "svg"));
		this.canvas.cachedWidth = 200;
		this.canvas.setAttributeNS(null, "width", "200px");
		this.canvas.setAttributeNS(null, "height", "200px");	
		this.canvas.setAttributeNS(null, "style", "top:0px, left:0px, position:absolute, overflow:hidden");			
		this.container.appendChild(this.canvas);
		this.topLevelDiv = $(document.createElement("div"));
		this.topLevelDiv.style.position = "absolute";
		this.topLevelDiv.style.top = "0px";
		this.topLevelDiv.style.left = "0px";
		this.topLevelDiv.style.height = this.height() + "px";
		this.topLevelDiv.style.zIndex = 20;
		this.handleClickInGanttEventListener = this.handleClickInGantt.bindAsEventListener(this);
		PWUtils.observe(this.topLevelDiv, "click", this.handleClickInGanttEventListener, true);
		this.container.appendChild(this.topLevelDiv);
	},


	_refreshGanttWithRows: function(rows, refreshAll)	{
		this.refreshWillStart();
		if(refreshAll){
			this.recreateLabelContainer();
			this.drawnRows = [];
			this.drawnRelations = [];
			this.leftMargin = 0;
		}
		this.newLabels = [];		
		var urisOfDrawnRows = [];
		var oldRowContainer = this.rowContainer;
		var oldBackgroundContainer = this.backgroundContainer;
		if(rows && rows.length){
			var canvasWidth = this.scrollView.ganttContainer.cachedOffsetWidth;
			if(refreshAll){
				this.rowContainer = $(document.createElementNS(this.svgns, "g"));
				this.backgroundContainer = $(document.createElement("div"));
				this.backgroundContainer.style.position = "absolute";
				this.backgroundContainer.style.top = "0px";
				this.backgroundContainer.style.left = "0px";
				this.backgroundContainer.style.height = this.height() + "px";
				this.backgroundContainer.style.zIndex = -1;
				this.backgrounds = [];
				this.whiteBackgrounds = [];
				this.backgroundContainer.whiteSelectionDivs = [];
			}else{
				this.backgroundContainer = oldBackgroundContainer;
				this.rowContainer = oldRowContainer;
			}
			var row;
			var height;
			var top = 0;			
			var oldRelationshipContainer = this.relationshipContainer;
			this.relationshipContainer = refreshAll ? $(document.createElementNS(this.svgns, "g")) : oldRelationshipContainer;
			for(var i=0; i<rows.length; i++){
				row = rows[i];				
				var activity = row.object;				
				if(!this.connectShapeRects[activity.uri()])
					this.connectShapeRects[activity.uri()] = {};
				var uri = activity.valueForKey(WRLSnapshotURIKey);
				if(!this.drawnRows[uri]){
					urisOfDrawnRows.push(uri);
					this.drawnRows[uri] = row;
					if(uri == 0)
						this.endDate = activity.valueForKey("expectedEndDate");				
					row.cachedOffsetHeight = row.heightInPixel+2;
					top = row.cachedOffsetTop;
					if(top == 0)
						this.endDate = activity.valueForKey("expectedEndDate");				
					this.createActivityInRow(activity, row, this.ruler, top, row.cachedOffsetHeight, canvasWidth, this.rowContainer);
				}
			}
			if(refreshAll){
				if(oldBackgroundContainer)
					this.container.replaceChild(this.backgroundContainer , oldBackgroundContainer);
				else
					this.container.appendChild(this.backgroundContainer );
				if(oldRowContainer)
					this.canvas.replaceChild(this.rowContainer , oldRowContainer);
				else
					this.canvas.appendChild(this.rowContainer );
				if(oldRelationshipContainer)
					this.canvas.replaceChild(this.relationshipContainer , oldRelationshipContainer);
				else
					this.canvas.appendChild(this.relationshipContainer);
			}
			if(this.viewOptions.showRelationships)
				this.createRelationships(this.relationshipContainer, this.drawnRows);
			this.calculateMinMax();
		}	
		if(urisOfDrawnRows.length)
			this.adjustLeftMargin(this.minX, this.minDate, this.maxX);
		this.refreshDidFinish();
	},

	adjustLeftMargin: function(minX, minDate, maxX)	{
		if(this.oldMinX != minX || this.oldMaxX != maxX || !this.oldMinDate || !this.oldMinDate.isEqual(minDate)){
			var oldActivityMinPos = this.ruler.dateToPos(this.minDate)-this.leftMargin;
			var suggestedStartDate = this.ruler.posToDate(this.minX+this.leftMargin);		
			var suggestedEndDate = this.ruler.posToDate(this.maxX+this.leftMargin);						
			this.ruler.adjustFromDateToDateOnlyByExpanding(suggestedStartDate, suggestedEndDate, true);
			this.leftMargin = this.ruler.dateToPos(this.minDate)-oldActivityMinPos;		
			this.rowContainer.setAttributeNS(null, "transform", "translate("+this.leftMargin+",0)");
			this.relationshipContainer.setAttributeNS(null, "transform", "translate("+this.leftMargin+",0)");
			this.labelContainer.style.left = this.leftMargin + "px";		
			this.oldMinX = minX;
			this.oldMinDate = minDate;
			this.oldMaxX = maxX;
			this.rulerWidthChanged(this.width());
			this.refreshRuler();
		}
		else
			this.rulerWidthChanged(this.rulerWidth);
	},
	
	rulerWidthChanged: function(width)	{
		this.rulerWidth = width;	
		var w = this.minCanvasWidthWithPreferedWidth(width);
		this.labelContainer.style.right = (this.scrollView.hasVerticalScrollbar() ? PWUtils.scrollbarWidth() : 0)+"px";
		this.canvas.cachedWidth = w;
		this.canvas.setAttributeNS(null, "width", w + "px");
		if(this.backgroundContainer)
			this.backgroundContainer.style.width = w + "px";
		this.topLevelDiv.style.width = w + "px";
		this.scrollView.refreshRulerFillView();		
	},

	height: function()	{
		return parseInt(this.canvas.getAttribute("height"));
	},

	setHeight: function(height)	{	
		if(height>=2)
			height-=2;
		this.canvas.setAttributeNS(null, "height", height + "px");
		this.labelContainer.style.height = height + "px";
		this.topLevelDiv.style.height = height + "px";
		this.refreshGantt();
	},

	// ************************************************************************************************************
	// *****
	// *****									Low level drawing methods
	// *****


	drawRightArrowInSVGGroup: function(group, x, y, size)	{
		path= document.createElementNS(this.svgns, "path");
		var d = "M "+x+" "+y+" L "+(x-size)+" "+(y-size/2)+" L "+(x-size)+" "+(y+size/2);
		path.setAttributeNS(null, "d", d);
		path.setAttributeNS(null, "stroke", this.strokeColor);	
		group.appendChild(path);
	},

	drawLeftArrowInSVGGroup: function(group, x, y, size)	{
		path= document.createElementNS(this.svgns, "path");
		var d = "M "+x+" "+y+" L "+(x+size)+" "+(y-size/2)+" L "+(x+size)+" "+(y+size/2);
		path.setAttributeNS(null, "d", d);
		path.setAttributeNS(null, "stroke", this.strokeColor);	
		group.appendChild(path);
	},

	drawDownArrowInSVGGroup: function(group, x, y, size)	{
		path= document.createElementNS(this.svgns, "path");
		var d = "M "+x+" "+y+" L "+(x-size/2)+" "+(y-size)+" L "+(x+size/2)+" "+(y-size);
		path.setAttributeNS(null, "d", d);
		path.setAttributeNS(null, "stroke", this.strokeColor);	
		group.appendChild(path);
	},

	drawUpArrowInSVGGroup: function(group, x, y, size)	{
		path= document.createElementNS(this.svgns, "path");
		var d = "M "+x+" "+y+" L "+(x-size/2)+" "+(y+size)+" L "+(x+size/2)+" "+(y+size);
		path.setAttributeNS(null, "d", d);
		path.setAttributeNS(null, "stroke", this.strokeColor);	
		group.appendChild(path);
	},

	drawLineFromRightOfRectToLeftOfRectInSVGGroup: function(svgGroup, startRect, endRect, width, color, zig)	{
		var offset = width <= 1 ? 0.5 : 0;
		var start = {	x: Math.floor(startRect.x+startRect.w)+offset, 
						y: Math.floor(startRect.y+startRect.h*0.5)+offset};
		var end   = {	x: Math.floor(endRect.x)+offset, 
						y: Math.floor(endRect.y+endRect.h*0.5)+offset};	
		var zigDistance = Math.floor(endRect.h*0.5+3);
		var connectThreshold = endRect.h
		path= document.createElementNS(this.svgns, "path");	
		path.setAttributeNS(null, "fill", "none");
		path.setAttributeNS(null, "stroke", color);	
		path.setAttributeNS(null, "stroke-width", width);			
		if(end.x - start.x > connectThreshold){
			var d = "M "+start.x+" "+start.y+" L "+(end.x-zigDistance)+" "+start.y+" L "+(end.x-zigDistance)+" "+end.y+" L "+end.x+" "+end.y;
			path.setAttributeNS(null, "d", d);
			svgGroup.appendChild(path);
			this.drawRightArrowInSVGGroup(svgGroup, end.x+1, end.y, 6);
		}else {	
			var sideEnd;
			if(end.y > start.y)
				sideEnd = {x:endRect.x, y:endRect.y};
			else
				sideEnd = {x:endRect.x, y:endRect.y+endRect.h};	
			sideEnd.x = Math.max(start.x, end.x) + zigDistance;
			if(zig || sideEnd.x>=endRect.x+endRect.w/2.0){				// um die Ecke malen
				var xBuf = zigDistance;
				var zigY = start.y < end.y ? end.y - xBuf : end.y + xBuf;
				var d = "M "+start.x+" "+start.y+" L "+(start.x+xBuf)+" "+start.y+" L "+(start.x+xBuf)+" "+zigY+" L "+(end.x-xBuf)+" "+zigY+" L "+(end.x-xBuf)+" "+end.y+" L "+end.x+" "+end.y;
				path.setAttributeNS(null, "d", d);
				svgGroup.appendChild(path);
				this.drawRightArrowInSVGGroup(svgGroup, end.x+1, end.y, 6);
			}else{
				var d = "M "+start.x+" "+start.y+" L "+sideEnd.x+" "+start.y+" L "+sideEnd.x+" "+sideEnd.y;
				path.setAttributeNS(null, "d", d);
				svgGroup.appendChild(path);
				if(end.y>start.y)
					this.drawDownArrowInSVGGroup(svgGroup, sideEnd.x, sideEnd.y+1, 6);
				else
					this.drawUpArrowInSVGGroup(svgGroup, sideEnd.x, sideEnd.y, 6);
			}
		}
	},

	drawLineFromLeftOfRectToLeftOfRectInSVGGroup: function(svgGroup, startRect, endRect, width, color)	{
		var offset = width <= 1 ? 0.5 : 0;
		var start = {	x:Math.floor(startRect.x)+offset, 
						y:Math.floor(startRect.y+startRect.h*0.5)+offset};
		var end   = {	x:Math.floor(endRect.x)+offset, 
						y:Math.floor(endRect.y+endRect.h*0.5)+1+offset};
		var minX = Math.min(start.x, end.x);
		var zigDistance = Math.floor(endRect.h*0.5+3);		
		path= document.createElementNS(this.svgns, "path");
		var d = "M "+start.x+" "+start.y+" L "+(minX-zigDistance)+" "+start.y+" L "+(minX-zigDistance)+" "+end.y+" L "+end.x+" "+end.y;
		path.setAttributeNS(null, "d", d);
		path.setAttributeNS(null, "fill", "none");	
		path.setAttributeNS(null, "stroke", color);	
		path.setAttributeNS(null, "stroke-width", width);	
		svgGroup.appendChild(path);
		this.drawRightArrowInSVGGroup(svgGroup, end.x, end.y, 6);
	},

	drawLineFromRightOfRectToRightOfRectInSVGGroup: function(svgGroup, startRect, endRect, width, color)	{
		var offset = width <= 1 ? 0.5 : 0;
		var start = {	x:Math.floor(startRect.x+startRect.w)+offset, 
						y:Math.floor(startRect.y+startRect.h*0.5)+offset};
		var end   = {	x:Math.floor(endRect.x+endRect.w)+offset, 
						y:Math.floor(endRect.y+endRect.h*0.5)+offset};
		var maxX = Math.max(start.x, end.x);
		var zigDistance = Math.floor(Math.max(endRect.h, startRect.h)/2)+3;
		path = document.createElementNS(this.svgns, "path");
		var d = "M "+start.x+" "+start.y+" L "+(maxX+zigDistance)+" "+start.y+" L "+(maxX+zigDistance)+" "+end.y+" L "+end.x+" "+end.y;
		path.setAttributeNS(null, "d", d);
		path.setAttributeNS(null, "fill", "none");	
		path.setAttributeNS(null, "stroke", color);	
		path.setAttributeNS(null, "stroke-width", width);	
		svgGroup.appendChild(path);
		this.drawLeftArrowInSVGGroup(svgGroup, end.x, end.y, 6);
	},

	drawLineFromLeftOfRectToRightOfRectInSVGGroup: function(svgGroup, startRect, endRect, width, color, zig)	{
		var offset = width <= 1 ? 0.5 : 0;
		var start = {	x: Math.floor(startRect.x)+offset, 
						y: Math.floor(startRect.y+startRect.h*0.5)+offset};
		var end   = {	x: Math.floor(endRect.x+endRect.w)+offset, 
						y: Math.floor(endRect.y+endRect.h*0.5)+offset};	
		var zigDistance = Math.floor(endRect.h*0.5+3);
		var connectThreshold = endRect.h;
		path= document.createElementNS(this.svgns, "path");	
		path.setAttributeNS(null, "fill", "none");	
		path.setAttributeNS(null, "stroke", color);	
		path.setAttributeNS(null, "stroke-width", width);		
		if(!zig && Math.abs(start.x - end.x) < connectThreshold){
			if(end.y > start.y)
				end.y = endRect.y;
			else
				end = endRect.y+endRect.h+1;		
			end.x = Math.min(start.x, end.x) - zigDistance;
			var d = "M "+start.x+" "+start.y+" L "+end.x+" "+start.y+" L "+end.x+" "+end.y;
			path.setAttributeNS(null, "d", d);
			svgGroup.appendChild(path);
			if(end.y>start.y)
				this.drawDownArrowInSVGGroup(svgGroup, end.x, end.y, 6);
			else
				this.drawUpArrowInSVGGroup(svgGroup, end.x, end.y, 6);
		}else if(start.x - end.x < connectThreshold){
			var xBuf = zigDistance;
			var zigY = start.y < end.y ? end.y - xBuf : end.y + xBuf;
			var d = "M "+start.x+" "+start.y+" L "+(start.x-xBuf)+" "+start.y+" L "+(start.x-xBuf)+" "+zigY+" L "+(end.x+xBuf)+" "+zigY+" L "+(end.x+xBuf)+" "+end.y+" L "+end.x+" "+end.y;
			path.setAttributeNS(null, "d", d);
			svgGroup.appendChild(path);
			this.drawLeftArrowInSVGGroup(svgGroup, end.x, end.y, 6);
		}else{
			var d = "M "+start.x+" "+start.y+" L "+(end.x+zigDistance)+" "+start.y+" L "+(end.x+zigDistance)+" "+end.y+" L "+end.x+" "+end.y;
			path.setAttributeNS(null, "d", d);
			svgGroup.appendChild(path);
			this.drawLeftArrowInSVGGroup(svgGroup, end.x, end.y, 6);
		}	
	},

	drawRelationship: function(relation, svgGroup) 	{
		var prevRect = this.connectShapeRects[relation.valueForKey("previousActivity").uri()];
		var nextRect = this.connectShapeRects[relation.valueForKey("nextActivity").uri()];
		var kind = relation.valueForKey("kind");
		var prevX = (kind == MEActivityRelationship.MEStartToStartRelationship || kind == MEActivityRelationship.MEStartToFinishRelationship) ? prevRect.x : prevRect.x+prevRect.w;
		var nextX = (kind == MEActivityRelationship.MEStartToStartRelationship || kind == MEActivityRelationship.MEFinishToStartRelationship) ? nextRect.x : nextRect.x+nextRect.w;
		var prevY = prevRect.y + prevRect.h/2;
		var nextY = nextRect.y + nextRect.h/2;
		var allowZig = relation.valueForKeyPath("nextActivity.isMilestone");
		var color = "black";
		var width = relation.valueForKey("isCritical") && this.viewOptions.showCriticalPath ? 1.5 : 0.5;
		

		if(kind == MEActivityRelationship.MEFinishToStartRelationship)
			this.drawLineFromRightOfRectToLeftOfRectInSVGGroup(svgGroup, prevRect, nextRect, width, color, allowZig);
		else if(kind == MEActivityRelationship.MEStartToStartRelationship)
			this.drawLineFromLeftOfRectToLeftOfRectInSVGGroup(svgGroup, prevRect, nextRect, width, color);
		else if(kind == MEActivityRelationship.MEFinishToFinishRelationship)
			this.drawLineFromRightOfRectToRightOfRectInSVGGroup(svgGroup, prevRect, nextRect, width, color);
		else if(kind == MEActivityRelationship.MEStartToFinishRelationship)
			this.drawLineFromLeftOfRectToRightOfRectInSVGGroup(svgGroup, prevRect, nextRect, width, color, allowZig);
	},
		

	// ************************************************************************************************************
	// *****
	// *****										Hig level drawing methods
	// *****


	drawGroup: function(x, y, width, completeWidth, height, fillColor, strokeColor, strokeWidth, shadow, group)	{
		var h = Math.floor(height/3.0);
		y = y + Math.floor((height-2*h)/2.0);
		if(shadow && this.drawShadows){
			var xs = x + 1;
			var ys = y + 2;
			var g = document.createElementNS(this.svgns, "rect");
			g.setAttributeNS(null, "x", xs-h);
			g.setAttributeNS(null, "y", ys);
			g.setAttributeNS(null, "width", width+h*2);
			g.setAttributeNS(null, "height", h);
			g.setAttributeNS(null, "fill", this.shadowColor);	
			g.setAttributeNS(null, "fill-opacity", this.shadowOpacity);	
			group.appendChild(g);	
			var path= document.createElementNS(this.svgns, "path");
			var d = "M "+(xs-h)+" "+(ys+h)+" l "+h+" "+h+" l "+h+" -"+h;
			path.setAttributeNS(null, "d", d);
			path.setAttributeNS(null, "fill", this.shadowColor);	
			path.setAttributeNS(null, "fill-opacity", this.shadowOpacity);	
			group.appendChild(path);						
			path= document.createElementNS(this.svgns, "path");
			d = "M "+(xs-h+width)+" "+(ys+h)+" l "+h+" "+h+" l "+h+" -"+h;		
			path.setAttributeNS(null, "d", d);
			path.setAttributeNS(null, "fill", this.shadowColor);	
			path.setAttributeNS(null, "fill-opacity", this.shadowOpacity);	
			group.appendChild(path);								
		}
		var g = document.createElementNS(this.svgns, "rect");
		g.setAttributeNS(null, "x", x-h);
		g.setAttributeNS(null, "y", y);
		g.setAttributeNS(null, "width", width+h*2);
		g.setAttributeNS(null, "height", h);
		g.setAttributeNS(null, "fill", fillColor);	
		g.setAttributeNS(null, "stroke", strokeColor);	
		g.setAttributeNS(null, "stroke-width",  strokeWidth);	
		group.appendChild(g);				
		if(completeWidth>0){
			var g = document.createElementNS(this.svgns, "rect");
			g.setAttributeNS(null, "x", x-h);
			g.setAttributeNS(null, "y", y);
			g.setAttributeNS(null, "width", completeWidth+h * (completeWidth >= width ? 2 : 1));
			g.setAttributeNS(null, "height", h);
			g.setAttributeNS(null, "fill", strokeColor);	
			group.appendChild(g);						
		}
		var path= document.createElementNS(this.svgns, "path");
		var d = "M "+(x-h-0.5)+" "+(y+h)+" l "+h+" "+h+" l "+h+" -"+h;
		path.setAttributeNS(null, "d", d);
		path.setAttributeNS(null, "fill", strokeColor);	
		group.appendChild(path);						
		path= document.createElementNS(this.svgns, "path");
		d = "M "+(x-h+width+1-0.5)+" "+(y+h)+" l "+h+" "+h+" l "+h+" -"+h;
		path.setAttributeNS(null, "d", d);
		path.setAttributeNS(null, "fill", strokeColor);	
		group.appendChild(path);		
	},

	drawMilestone: function(x, y, h, fillColor, strokeColor, strokeWidth, group)	{
		if(this.drawShadows) {
			var path= document.createElementNS(this.svgns, "path");
			var d = "M "+(x-h+2)+" "+(y+h+2)+" l "+h+" "+h+" l "+h+" -"+h+" l -"+h+" -"+h+" l -"+h+" "+h;
			path.setAttributeNS(null, "d", d);
			path.setAttributeNS(null, "fill", this.shadowColor);	
			path.setAttributeNS(null, "fill-opacity", this.shadowOpacity);	
			group.appendChild(path);						
		}
		var path= document.createElementNS(this.svgns, "path");
		var d = "M "+(x-h)+" "+(y+h)+" l "+h+" "+h+" l "+h+" -"+h+" l -"+h+" -"+h+" l -"+h+" "+h;
		path.setAttributeNS(null, "d", d);
		path.setAttributeNS(null, "fill", fillColor);	
		path.setAttributeNS(null, "stroke", strokeColor);	
		path.setAttributeNS(null, "stroke-width",  strokeWidth);	
		group.appendChild(path);	
	},
	
	drawBar: function(x, y, width, completeWidth, height, radius, fillColor, strokeColor, strokeWidth, shadow, group, dashed)	{
		if(shadow && this.drawShadows){
			var shadow = document.createElementNS(this.svgns, "rect");
			shadow.setAttributeNS(null, "x", x);
			shadow.setAttributeNS(null, "y", y);
			shadow.setAttributeNS(null, "width", width+2);
			shadow.setAttributeNS(null, "height", height+2);
			shadow.setAttributeNS(null, "rx", radius+2);
			shadow.setAttributeNS(null, "ry", radius)+2;
			shadow.setAttributeNS(null, "fill", this.shadowColor);	
			shadow.setAttributeNS(null, "fill-opacity", this.shadowOpacity);	
			group.appendChild(shadow);
		}
		var bar = document.createElementNS(this.svgns, "rect");
		bar.setAttributeNS(null, "x", x);
		bar.setAttributeNS(null, "y", y);
		bar.setAttributeNS(null, "width", width);
		bar.setAttributeNS(null, "height", height);
		bar.setAttributeNS(null, "rx", radius);
		bar.setAttributeNS(null, "ry", radius);
		bar.setAttributeNS(null, "fill", fillColor);	
		bar.setAttributeNS(null, "stroke", strokeColor);	
		bar.setAttributeNS(null, "stroke-width", strokeWidth);	
		if(dashed)
			bar.setAttributeNS(null, "stroke-dasharray", "2,2");
		group.appendChild(bar);
		if(completeWidth>0){
			var bar = document.createElementNS(this.svgns, "rect");
			bar.setAttributeNS(null, "x", x);
			bar.setAttributeNS(null, "y", y);
			bar.setAttributeNS(null, "width", completeWidth);
			bar.setAttributeNS(null, "height", height);
			bar.setAttributeNS(null, "fill", strokeColor);	
			group.appendChild(bar);
		}
	}
	
	
});