/*
 BINViz, Bidirectional Interactive Network Visualization
 Copyright (C) 2007  Benjamin Weyers, University of Michigan, Ann Arbor, MI, U.S.

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @fileoverview Provides the PLUGIN class necessary for X
 * @author Benjamin Weyers, University of Duisburg-Essen, University of Michigan
 * @version 0.1
 */

/**
 * Constructor description
 * 
 * @constructor
 *  
 * @class Class description
 * 
 * @author Benjamin Weyers, University of Duisburg-Essen, University of Michigan
 * @version 0.1
 */
function ZoomPlugin()
{
	this.graphView;
	this.htmlElement;
	
	this.minimapWidth = 100;
	this.currentZoom = 1;
	this.zoomFactors = [1,.5,.33,.25,.2,.16,.14,.125,.11,.1];
}

ZoomPlugin.prototype = new Object();
ZoomPlugin.prototype.type = "ZoomPlugin";

ZoomPlugin.prototype.init=function(graphView, initData)
{
	this.graphView = graphView;
	this.graphView.registerViewChangeListener(this);
	
	this.htmlElement = this.createElement();
	if ( initData != null ) {
		this.minimapWidth = initData.minimapWidth || 100;
	}
}

ZoomPlugin.prototype.createElement=function()
{
	
	var container = document.createElement("div");
	container.style.width = "200px";
	container.style.height = "150px";
	// minimap
	
	this.map = document.createElement("div");
	this.map.width = this.minimapWidth;
	this.map.height = parseInt(this.minimapWidth * ( parseInt(this.graphView.canvas.style.height.replace("px","")) / parseInt(this.graphView.canvas.style.width.replace("px","")) ));
	this.map.style.width = this.map.width + "px";
	this.map.style.height = this.map.height + "px";
	this.map.style.backgroundColor="lightgray";
	this.map.style.position="absolute";
	this.map.style.top="20px";
	this.map.style.left="0px";
	
	this.innerMap = document.createElement("div");
	$(this.innerMap).css({'width':this.map.width,'height':this.map.height,'backgroundColor':'gray'})
	this.innerMap.width = this.map.width;
	this.innerMap.height = this.map.height;

	this.map.appendChild(this.innerMap);
	
	// zoom factor box
	this.zoom = document.createElement("select");
	for ( var i = 1; i <= 10; i++ ) {
		var attr = document.createElement("option");
		attr.appendChild(document.createTextNode((i * 50) + "%"));
		this.zoom.appendChild(attr);
	}
	this.zoom.style.width = "100px";
	this.zoom.style.height = "20px";
	this.zoom.style.position = "absolute";
	this.zoom.style.top = "0px";
	this.zoom.style.left= "0px";
	this.zoom.selectedIndex = 1;

	var t = this;
	this.innerMapDrag = $(this.innerMap).Draggable(
        {
            'ghosting': true,
            'opacity': .5,
			'containment' : "parent",
            'onDrag': function(x,y) { 
				t.generateMappingFunction();
				t.graphView.scrollPane.scrollLeft = t.xArray[x];t.graphView.scrollPane.scrollTop = t.yArray[y];
				t.graphView.scrollOffsetX = t.graphView.scrollPane.scrollLeft;t.graphView.scrollOffsetY = t.graphView.scrollPane.scrollTop;
            },
			'onStop': function() {
				t.generateMappingFunction();
				t.graphView.scrollPane.scrollLeft = ( t.xArray[parseInt(t.innerMap.style.left.replace("px",""))] );
				t.graphView.scrollPane.scrollTop = ( t.yArray[parseInt(t.innerMap.style.top.replace("px",""))] );
				t.graphView.scrollOffsetX = t.graphView.scrollPane.scrollLeft;
				t.graphView.scrollOffsetY = t.graphView.scrollPane.scrollTop;
			}
    	});
	var zo = this.zoom;
	this.zoom.onchange = function(e){
		if ( zo.options[zo.selectedIndex].text == "50%" )  t.handleZoomEvent(0);
		if ( zo.options[zo.selectedIndex].text == "100%" ) t.handleZoomEvent(1);
		if ( zo.options[zo.selectedIndex].text == "150%" ) t.handleZoomEvent(2);
		if ( zo.options[zo.selectedIndex].text == "200%" ) t.handleZoomEvent(3);
		if ( zo.options[zo.selectedIndex].text == "250%" ) t.handleZoomEvent(4);
		if ( zo.options[zo.selectedIndex].text == "300%" ) t.handleZoomEvent(5);
		if ( zo.options[zo.selectedIndex].text == "350%" ) t.handleZoomEvent(6);
		if ( zo.options[zo.selectedIndex].text == "400%" ) t.handleZoomEvent(7);
		if ( zo.options[zo.selectedIndex].text == "450%" ) t.handleZoomEvent(8);
		if ( zo.options[zo.selectedIndex].text == "500%" ) t.handleZoomEvent(9);
	}
	container.appendChild(this.zoom);
	container.appendChild(this.map);
	$(container).css({'width':this.minimapWidth});
	return container;
}

ZoomPlugin.prototype.handleZoomEvent=function(factor)
{
	//this.graphView.zoom(this.zoomFactors[this.currentZoom][factor]);
	//alert((factor + 1) * this.zoomFactors[this.currentZoom]);
	this.zoomGraph((factor + 1) * this.zoomFactors[this.currentZoom]);
	this.currentZoom = factor;
}

ZoomPlugin.prototype.setInnerMapPosition=function(x,y)
{
	this.graphView.scrollOffsetX = x;
	this.graphView.scrollOffsetY = y;
	this.innerMap.style.left = this.mapBigToSmall(x, this.xArray) + "px";
	this.innerMap.style.top = this.mapBigToSmall(y, this.yArray) + "px";
}

ZoomPlugin.prototype.resizeInnerMap=function()
{
	
}

ZoomPlugin.prototype.generateMappingFunction=function()
{
	var widthFactor  = parseInt( parseInt(this.graphView.canvas.style.width.replace("px",""))  / this.map.width) + 1;
	var heightFactor = parseInt( parseInt(this.graphView.canvas.style.height.replace("px","")) / this.map.height) + 1;
	
	this.xArray = new Array();
	this.yArray = new Array();
	
	var temp = 0;
	for ( var i = 0; i <= this.map.width; i++ ) {
		this.xArray[i] = temp;
		temp += widthFactor;
	}
	var temp = 0;
	for ( var i = 0; i <= this.map.height; i++) {
		this.yArray[i] = temp;
		temp += heightFactor;
	}
}

ZoomPlugin.prototype.mapBigToSmall=function(big, array)
{
	var i = 0;
	while ( array[i] < big ) i++;
	return ++i;
}

ZoomPlugin.prototype.moveNodeEventPerformed=function(nodeData, x, y){}

ZoomPlugin.prototype.newGraphAddedPerformed=function(graph){}

ZoomPlugin.prototype.canvasResizedPerformed=function(width, height)
{
	//alert(width + ", " + height);
	// width of minimap is fixed to this.minimapWidth
	var fac = parseInt(this.minimapWidth * ( height / width ) ) + 1;
	this.map.style.height  = fac + "px"; 
	this.map.height = fac; 
	this.map.width = this.minimapWidth;
	this.resizeCanvas(this.findDividerWidth(width) * this.minimapWidth, this.findDividerHeight(height));
	
	//this.back.style.height = fac + "px";
	this.generateMappingFunction();
	
	//this.frame.setHeight( parseInt(this.map.style.height.replace("px",""))  + 60 );
	
	var widthIndex = this.mapBigToSmall(parseInt(this.graphView.scrollPane.style.width.replace("px","")), this.xArray);
	var heightIndex = this.mapBigToSmall(parseInt(this.graphView.scrollPane.style.height.replace("px","")), this.yArray);
	
	
	this.innerMap.style.width = widthIndex + "px";
	this.innerMap.width = widthIndex;
	this.innerMap.style.height = heightIndex + "px";
	this.innerMap.height = heightIndex;
}

ZoomPlugin.prototype.findDividerWidth=function(width)
{
	return (parseInt(width / this.minimapWidth) + 1);
}

ZoomPlugin.prototype.findDividerHeight=function(height, factor)
{
	return (parseInt(height / factor) + 1);
}

ZoomPlugin.prototype.resizeCanvas=function(width, height)
{
	this.graphView.canvas.style.width = width + "px";
	this.graphView.canvas.style.height = height + "px";
	this.graphView.canvas.width = width;
	this.graphView.canvas.height = height;
	if ( this.graphView.glassPane != null ) {
		this.graphView.glassPane.style.width = width + "px";
		this.graphView.glassPane.style.height = height + "px";
		this.graphView.glassPane.width = width;
		this.graphView.glassPane.height = height;
	}
}

ZoomPlugin.prototype.canvasScrolledPerformed=function(offsetX, offsetY){
	this.setInnerMapPosition(offsetX, offsetY);
}

ZoomPlugin.prototype.zoomGraph=function(faktor)
{
	var layout = this.graphView.currentGraph.getLayout();
	for ( var i = 0; i < this.graphView.currentGraph.getNodes().length; i++ ) {
		var localX = layout.getNodePosition(this.graphView.currentGraph.getNodes()[i].getId()).x - layout.getCenter().x;
		var localY = layout.getNodePosition(this.graphView.currentGraph.getNodes()[i].getId()).y - layout.getCenter().y;
		this.graphView.currentGraph.getNodes()[i].setPosition( new Point((faktor * localX + layout.getCenter().x),  
											                   (faktor * localY + layout.getCenter().y)) );
	}
	
	layout = this.graphView.currentGraph.getLayout();
	if ( layout.minX < 0 ) var translateX = -layout.minX;
	else var translateX = 0;
	if ( layout.minY < 0 ) var translateY = -layout.minY;
	else var translateY = 0;
	
	if ( translateX != 0 || translateY != 0 ) this.translateGraph(translateX, translateY);

	layout = this.graphView.currentGraph.getLayout();
	this.graphView.resizeCanvas(layout.maxX + parseInt(this.graphView.addedNodeViewsHash[0][layout.maxXID].htmlElement.style.width.replace("px","")), 
					  layout.maxY + parseInt(this.graphView.addedNodeViewsHash[0][layout.maxYID].htmlElement.style.height.replace("px","")));
	for ( var i = 0; i < this.graphView.changeListener.length; i++ )
			this.graphView.changeListener[i].canvasScrolledPerformed(this.graphView.scrollPane.scrollLeft, this.graphView.scrollPane.scrollTop);
}

ZoomPlugin.prototype.translateGraph=function(x,y)
{
	var layout = this.graphView.currentGraph.getLayout();
	for ( var i = 0; i < this.graphView.currentGraph.getNodes().length; i++ ) {
		var localX = layout.getNodePosition(this.graphView.currentGraph.getNodes()[i].getId()).x;
		var localY = layout.getNodePosition(this.graphView.currentGraph.getNodes()[i].getId()).y;
		this.graphView.currentGraph.getNodes()[i].setPosition( new Point((localX + x),(localY + y)) );
	}
	
	for ( var i = 0; i < this.graphView.addedNodeViews.length; i++ ) {
		this.graphView.repaintEdges(this.graphView.addedNodeViews[i].id);
	}
}
