// Copyright 2008 ProjectWizards GmbH. All rights reserved.

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

var GanttVMLView = GanttView.extend({
	constructor: function(scrollView, container, ganttRuler, environment, drawShadows)
	{    
		this.base(environment, ganttRuler, scrollView, drawShadows);
		this.container = container;
		this.container.style.overflowX = "auto";
		this.rulerWidth = 0;
		this.outlineHeight= 0;	
		this.leftBorderSize = 20;
		this.rightBorderSize = 20;
		this.endDate = new Date();
		this.topLevelDiv = $(document.createElement("div"));
		this.topLevelDiv.style.position = "absolute";
		this.topLevelDiv.style.top = "0px";
		this.topLevelDiv.style.left = "0px";
		this.topLevelDiv.style.height = "10px";
		this.topLevelDiv.style.width = "10px";
		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();	
		var oldLabelContainer = this.labelContainer;
		if(refreshAll){
			this.recreateLabelContainer();
			this.labelContainer.style.height = "1px";
			this.labelContainer.style.overflow = "hidden";
			this.drawnRows = [];
			this.drawnRelations = [];
			this.leftMargin = 0;	
			this.backgrounds = [];
			this.whiteBackgrounds = [];					
		}
		this.newLabels = [];
		var urisOfDrawnRows = [];
		var oldRowContainer = this.rowContainer;
		var oldRelationshipContainer = this.relationshipContainer;
		var oldBackgroundContainer = this.backgroundContainer;
		if(rows && rows.length){
			var canvasWidth = this.scrollView.ganttContainer.cachedOffsetWidth;
			if(refreshAll){
                var topStyle = !document.documentMode || document.documentMode<8 ? "-1px" : "-2px";
				var w = this.minCanvasWidthWithPreferedWidth(this.rulerWidth);
				var h = this.outlineHeight;
				this.rowContainer = $(document.createElement("v:group"));
				this.rowContainer.style.position = "absolute";
				this.rowContainer.style.top = topStyle;
				this.rowContainer.style.left = "0px";
				this.rowContainer.style.width = Math.max(w, 0)+"px";
				this.rowContainer.style.height = h+"px";
                this.rowContainer.setAttribute("coordsize", (w+" "+h));	 
				this.rowContainer.setAttribute("coordorigin", "0 0");	 
				this.relationshipContainer = $(document.createElement("v:group"));
				this.relationshipContainer.style.position = "absolute";
				this.relationshipContainer.style.top = topStyle;
				this.relationshipContainer.style.left = "0px";
				this.relationshipContainer.style.width = Math.max(w, 0)+"px";
				this.relationshipContainer.style.height = h+"px";					
				this.relationshipContainer.style.zIndex = "3";
				this.relationshipContainer.setAttribute("coordsize", (w+" "+h));	 
				this.relationshipContainer.setAttribute("coordorigin", "0 0");
				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.backgroundContainer.whiteSelectionDivs = [];				
			}else{
				this.rowContainer = oldRowContainer;
				this.relationshipContainer = oldRelationshipContainer;
				this.backgroundContainer = oldBackgroundContainer;
			}

			var row;
			var activity;
			var top;
			for(var i=0; i<rows.length; i++){
				row = rows[i];				
				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;
					row.cachedOffsetHeight = row.heightInPixel+2;
					top = row.cachedOffsetTop;
					if(uri == 0)
						this.endDate = activity.valueForKey("expectedEndDate");				
					this.createActivityInRow(activity, row, this.ruler, top, row.cachedOffsetHeight, canvasWidth, this.rowContainer);				
				}
			}
			this.calculateMinMax();
			if(urisOfDrawnRows.length)
				this.adjustLeftMargin(this.minX, this.minDate, this.maxX);			
			if(this.viewOptions.showRelationships){
				this.createRelationships(this.relationshipContainer, this.drawnRows);
			}			

			if(refreshAll){
				if(oldBackgroundContainer)
					this.container.replaceChild(this.backgroundContainer , oldBackgroundContainer);
				else
					this.container.appendChild(this.backgroundContainer );

				if(oldRowContainer)
					this.container.replaceChild(this.rowContainer , oldRowContainer);
				else
					this.container.appendChild(this.rowContainer );
				if(oldRelationshipContainer)
					this.container.replaceChild(this.relationshipContainer , oldRelationshipContainer);
				else
					this.container.appendChild(this.relationshipContainer);
				this.labelContainer.style.height = null;	
				this.labelContainer.style.overflow = "visible";

			}

		}
		this.refreshDidFinish();	
	},
	
	adjustLeftMargin: function(minX, minDate, maxX)
	{
		if(this.oldMinX != minX || this.oldMaxX != maxX || !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.style.left = this.leftMargin+"px";
			this.relationshipContainer.style.left = this.leftMargin+"px";
			this.labelContainer.style.left = this.leftMargin + "px";		
			this.oldMinX = minX;
			this.oldMinDate = minDate;
			this.oldMaxX = maxX;				
			this.rulerWidthChanged(this.width());
		}
		this.refreshRuler();
	},

	rulerWidthChanged: function(width)
	{
		this.rulerWidth = width;	
		var w = this.minCanvasWidthWithPreferedWidth(width);
		this.cachedWidth = w;
		if(this.labelContainer)
			this.labelContainer.style.right = (this.scrollView.hasVerticalScrollbar() ? PWUtils.scrollbarWidth() : 0)+"px";
		if(this.backgroundContainer)
			this.backgroundContainer.style.width = Math.max(w, 0) + "px";
		this.topLevelDiv.style.width = Math.max(w, 0) + "px";
		this.scrollView.refreshRulerFillView();	
	},

	height: function()
	{
		return this.outlineHeight;
	},

	setHeight: function(height)
	{
		this.outlineHeight = height;
		this.topLevelDiv.style.height = height + "px";
		this.refreshGantt();
	},	

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

	drawRelationship: function(relation, group) 
	{
		var r1 = this.connectShapeRects[relation.valueForKey("previousActivity").uri()];
		var r2 = this.connectShapeRects[relation.valueForKey("nextActivity").uri()];
		var prevRect = {x:Math.floor(r1.x), y:Math.floor(r1.y), w:Math.floor(r1.w), h:Math.floor(r1.h)};
		var nextRect = {x:Math.floor(r2.x), y:Math.floor(r2.y), w:Math.floor(r2.w), h:Math.floor(r2.h)};
		var allowZig = relation.valueForKeyPath("nextActivity.isMilestone");
		var color = "black";
		var width = relation.valueForKey("isCritical") && this.viewOptions.showCriticalPath ? 2 : 1;
		var kind = relation.valueForKey("kind");
		
		if(kind == MEActivityRelationship.MEFinishToStartRelationship)
			this.drawLineFromRightOfRectToLeftOfRectInVMLGroup(group, prevRect, nextRect, width, color, allowZig);
		else if(kind == MEActivityRelationship.MEStartToStartRelationship)
			this.drawLineFromLeftOfRectToLeftOfRectInVMLGroup(group, prevRect, nextRect, width, color);
		else if(kind == MEActivityRelationship.MEFinishToFinishRelationship)
			this.drawLineFromRightOfRectToRightOfRectInVMLGroup(group, prevRect, nextRect, width, color);
		else if(kind == MEActivityRelationship.MEStartToFinishRelationship)
			this.drawLineFromLeftOfRectToRightOfRectInVMLGroup(group, prevRect, nextRect, width, color, allowZig);
	},

	drawShapeWithPathInVMLGroup: function(path, group, fillColor, strokeColor, shadow, strokeWidth)
	{
		var bar = document.createElement("v:shape");
		bar.style.position = "absolute";
		bar.style.top = "0px";
		bar.style.left = "0px";
		bar.style.width = group.style.width;
		bar.style.height = group.style.height;
		bar.setAttribute("fill", "true");	
		bar.setAttribute("fillcolor", fillColor);	
		bar.setAttribute("strokecolor", strokeColor);	
		bar.setAttribute("strokeweight", strokeWidth + "px");	
		bar.setAttribute("path", path);	
		var s = document.createElement('v:shadow'); 
		s.setAttribute("on", "t");	 
		s.setAttribute("type", "double");	 
		s.setAttribute("opacity", "0.3");	 
		s.setAttribute("offset", shadow ? "1px,1px" : "0px,0px");
		s.setAttribute("color", "#333333");	 
		s.setAttribute("color2", "#aaaaaa");
		s.setAttribute("offset2", shadow ? "3px,3px" : "0px,0px");
		bar.appendChild(s);
		group.appendChild(bar);	
	},
	 
	drawRightArrowInVMLGroup: function(group, x, y, size)
	{
		var path = "m "+x+" "+y+" l "+(x-size)+" "+(y-size/2)+" l "+(x-size)+" "+(y+size/2)+" l "+x+" "+y;
		GanttVMLView.drawPathInVMLGroup(path, group, this.fillColor, this.strokeColor, false, true, 1);
	},

	drawLeftArrowInVMLGroup: function(group, x, y, size)
	{
		var path = "m "+x+" "+y+" l "+(x+size)+" "+(y-size/2)+" l "+(x+size)+" "+(y+size/2)+" l "+x+" "+y;
		GanttVMLView.drawPathInVMLGroup(path, group, this.fillColor, this.strokeColor, false, true, 1);
	},

	drawDownArrowInVMLGroup: function(group, x, y, size)
	{
		var path = "m "+x+" "+y+" l "+(x-size/2)+" "+(y-size)+" l "+(x+size/2)+" "+(y-size)+" l "+x+" "+y;
		GanttVMLView.drawPathInVMLGroup(path, group, this.fillColor, this.strokeColor, false, true, 1);
	},

	drawUpArrowInVMLGroup: function(group, x, y, size)
	{
		var path = "m "+x+" "+y+" l "+(x-size/2)+" "+(y+size)+" l "+(x+size/2)+" "+(y+size);+" l "+x+" "+y;
		GanttVMLView.drawPathInVMLGroup(path, group, this.fillColor, this.strokeColor, false, true, 1);
	},

	drawLineFromRightOfRectToLeftOfRectInVMLGroup: function(vmlGroup, startRect, endRect, width, color, zig)
	{
		var start = {	x: Math.floor(startRect.x+startRect.w), 
						y: Math.floor(startRect.y+startRect.h*0.5)};
		var end   = {	x: Math.floor(endRect.x), 
						y: Math.floor(endRect.y+endRect.h*0.5)};

		var zigDistance = Math.floor(endRect.h/2 + 3);
		var connectThreshold = endRect.h
		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;
			GanttVMLView.drawPathInVMLGroup(d, vmlGroup, color, color, false, false, width);
			this.drawRightArrowInVMLGroup(vmlGroup, end.x, 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;
				GanttVMLView.drawPathInVMLGroup(d, vmlGroup, color, color, false, false, width);
				this.drawRightArrowInVMLGroup(vmlGroup, end.x, end.y, 6);
			}else{
				var d = "m "+start.x+" "+start.y+" l "+sideEnd.x+" "+start.y+" l "+sideEnd.x+" "+sideEnd.y;
				GanttVMLView.drawPathInVMLGroup(d, vmlGroup, color, color, false, false, width);
				if(end.y>start.y)
					this.drawDownArrowInVMLGroup(vmlGroup, sideEnd.x, sideEnd.y, 6);
				else
					this.drawUpArrowInVMLGroup(vmlGroup, sideEnd.x, sideEnd.y, 6);
			}
		}
	},

	drawLineFromLeftOfRectToLeftOfRectInVMLGroup: function(vmlGroup, startRect, endRect, width, color)
	{
		var start = {	x:Math.floor(startRect.x), 
						y:Math.floor(startRect.y+startRect.h/2)+1};
		var end   = {	x:Math.floor(endRect.x), 
						y:Math.floor(endRect.y+endRect.h/2)+1};
		var minX = Math.min(start.x, end.x);
		var zigDistance = Math.floor((endRect.h/2)+3);			
		var d = "m "+start.x+" "+start.y+" l "+(minX-zigDistance)+" "+start.y+" l "+(minX-zigDistance)+" "+end.y+" l "+end.x+" "+end.y;
		GanttVMLView.drawPathInVMLGroup(d, vmlGroup, color, color, false, false, width);
		this.drawRightArrowInVMLGroup(vmlGroup, end.x, end.y, 6);
	},

	drawLineFromRightOfRectToRightOfRectInVMLGroup: function(vmlGroup, startRect, endRect, width, color)
	{
		var start = {	x:Math.floor(startRect.x+startRect.w), 
						y:Math.floor(startRect.y+startRect.h/2)+1};
		var end   = {	x:Math.floor(endRect.x+endRect.w), 
						y:Math.floor(endRect.y+endRect.h/2)+1};
		var maxX = Math.max(start.x, end.x);
		var zigDistance = Math.floor(Math.max(endRect.h, startRect.h)/2)+3;
		var d = "m "+start.x+" "+start.y+" l "+(maxX+zigDistance)+" "+start.y+" l "+(maxX+zigDistance)+" "+end.y+" l "+end.x+" "+end.y;
		GanttVMLView.drawPathInVMLGroup(d, vmlGroup, color, color, false, false, width);
		this.drawLeftArrowInVMLGroup(vmlGroup, end.x, end.y, 6);
	},

	drawLineFromLeftOfRectToRightOfRectInVMLGroup: function(vmlGroup, startRect, endRect, width, color, zig)
	{	
		var start = {	x: Math.floor(startRect.x)+1, 
						y: Math.floor(startRect.y+startRect.h/2)+1};
		var end   = {	x: Math.floor(endRect.x+endRect.w), 
						y: Math.floor(endRect.y+endRect.h/2)+1};	
		var zigDistance = Math.floor(endRect.h/2 + 3);
		var connectThreshold = endRect.h;
		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;
			GanttVMLView.drawPathInVMLGroup(d, vmlGroup, color, color, false, false, width);
			if(end.y>start.y)
				this.drawDownArrowInVMLGroup(vmlGroup, end.x, end.y, 6);
			else
				this.drawUpArrowInVMLGroup(vmlGroup, 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;
			GanttVMLView.drawPathInVMLGroup(d, vmlGroup, color, color, false, false, width);
			this.drawLeftArrowInVMLGroup(vmlGroup, 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;
			GanttVMLView.drawPathInVMLGroup(d, vmlGroup, color, color, false, false, width);
			this.drawLeftArrowInVMLGroup(vmlGroup, end.x, end.y, 6);
		}	
	},
	
	
	// ************************************************************************************************************
	// *****
	// *****										High level drawing methods
	// *****


	drawGroupTriangleInVMLGroup: function(x, y, width, h, color, shadow, group)
	{
		var path = "m "+(x-h)+" "+(y+h)+" r "+h+" "+h+" r "+h+" -"+h;
		this.drawShapeWithPathInVMLGroup(path, group,  color, color, shadow, 1);
		path = "m "+(x+width-h)+" "+(y+h)+" r "+h+" "+h+" r "+h+" -"+h;
		this.drawShapeWithPathInVMLGroup(path, group, color, color, shadow, 1);		
	},
	
	drawGroup: function(x, y, width, completeWidth, height, fillColor, strokeColor, strokeWidth, shadow, group)
	{
		var h = Math.floor(height/3.0);
		var x = Math.floor(x);
		var y = Math.floor(y);
		y += Math.floor((height-2*h)/2.0);		
		var width = Math.floor(width);
		var strokeWidth = Math.floor(strokeWidth);
		this.drawBar(x-h, y, width+2*h, completeWidth, h, 0, fillColor, strokeColor, strokeWidth, shadow, group);
		this.drawGroupTriangleInVMLGroup(x, y, width, h, strokeColor, shadow, group);
	},

	drawMilestone: function(x, y, h, backgroundColor, color, borderWidth, group)
	{
		x = Math.floor(x);
		y = Math.floor(y);
		h = Math.floor(h);
		borderWidth = Math.floor(borderWidth);
		var path = "m "+(x-h)+" "+(y+h)+" r "+h+" "+h+" r "+h+" -"+h+" r -"+h+" -"+h+" r -"+h+" "+h;
		this.drawShapeWithPathInVMLGroup(path, group, backgroundColor, color, true, borderWidth);			
	},
	
	drawBar: function(x, y, width, completeWidth, height, radius, fillColor, strokeColor, strokeWidth, shadow, group, dashed)
	{
		x = Math.floor(x);
		y = Math.floor(y);
		width = Math.floor(width);
		height = Math.floor(height);
		strokeWidth = Math.floor(strokeWidth);
		var bar = document.createElement("v:roundrect");
		bar.style.position = "absolute";
		bar.style.top = y+"px";
		bar.style.left = x+"px";
		bar.style.width = Math.max(width, 0)+"px";
		bar.style.height = height+"px";
		bar.setAttribute("fill", "true");
		bar.setAttribute("fillcolor", fillColor);	
		bar.setAttribute("strokecolor", strokeColor);	
		bar.setAttribute("strokeweight", strokeWidth + "px");	
		if(radius)
			bar.setAttribute("arcsize", 0.12);
		var s = document.createElement('v:shadow'); 
		s.setAttribute("on", "t");	 
		s.setAttribute("type", "double");	 
		s.setAttribute("opacity", "0.3");	 
		s.setAttribute("offset", shadow ? "1px,1px" : "0px,0px");
		s.setAttribute("color", "#333333");	 
		s.setAttribute("color2", "#aaaaaa");
		s.setAttribute("offset2", shadow ? "3px,3px" : "0px,0px");
		bar.appendChild(s);
		group.appendChild(bar);
	}
	
},

	// ************************************************************************************************************
	// *****
	// *****										Class Interface
	// *****

{
	drawPathInVMLGroup: function(path, group, fillColor, strokeColor, shadow, fill, strokeWeight)
	{
		var shape = document.createElement("v:shape");
		shape.style.position = "absolute";
		shape.style.top = "0px";
		shape.style.left = "0px";
		shape.style.width = group.style.width;
		shape.style.height = group.style.height;					
		shape.setAttribute("strokecolor", strokeColor);	
		shape.setAttribute("strokeweight", strokeWeight);	
		shape.setAttribute("fillcolor", fillColor);
		shape.setAttribute("path", path);
		if(!fill){
			var f = document.createElement('v:fill'); 
			f.setAttribute("on", "f");
			shape.appendChild(f);
		}
		var s = document.createElement('v:shadow'); 
		s.setAttribute("on", "t");	 
		s.setAttribute("type", "double");	 
		s.setAttribute("opacity", "0.3");	 
		s.setAttribute("offset", shadow ? "1px,1px" : "0px,0px");
		s.setAttribute("color", "#333333");	 
		s.setAttribute("color2", "#aaaaaa");
		s.setAttribute("offset2", shadow ? "3px,3px" : "0px,0px");
		shape.appendChild(s);
		group.appendChild(shape);	
	}
});