//$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/apps/igeoportal-standard/branches/2.5_testing/modules/mapeditor/vertexeditor.js $
/*----------------------------------------------------------------------------
 This file is part of deegree, http://deegree.org/
 Copyright (C) 2001-2009 by:
 - Department of Geography, University of Bonn -
 and
 - lat/lon GmbH -

 This library is free software; you can redistribute it and/or modify it under
 the terms of the GNU Lesser General Public License as published by the Free
 Software Foundation; either version 2.1 of the License, or (at your option)
 any later version.
 This library 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 Lesser General Public License for more
 details.
 You should have received a copy of the GNU Lesser General Public License
 along with this library; if not, write to the Free Software Foundation, Inc.,
 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

 Contact information:

 lat/lon GmbH
 Aennchenstr. 19, 53177 Bonn
 Germany
 http://lat-lon.de/

 Department of Geography, University of Bonn
 Prof. Dr. Klaus Greve
 Postfach 1147, 53001 Bonn
 Germany
 http://www.geographie.uni-bonn.de/deegree/

 e-mail: info@deegree.org
----------------------------------------------------------------------------*/

/**
* class for moving, adding/inserting and deleting vertices
* @param geometry geometry to be updated
* @param radius the radius to be considered when deleting/moving vertieces
* @param nearest if true just the vertex nearst to the refPoint will be considered
*/
function VertexEditor( geometry, radius, nearest ) {

	// attributes
	this.geometry = geometry;
	this.radius = radius;
	this.nearest = nearest;
	
	// methods
	this.moveVertex = moveVertex;
	this.insertVertex = insertVertex;
	this.deleteVertex = deleteVertex;
	this.mvHandlePoint = mvHandlePoint;
	this.mvHandlePolygon = mvHandlePolygon;
	this.findVertices = findVertices;
	this.isStartVertex = isStartVertex;
	this.delHandlePolygon = delHandlePolygon;
	this.insertHandlePolygon = insertHandlePolygon;
	this.insertHandleLinestring = insertHandleLinestring;
	
	
	// implementations
	
	/**
	* moves a vertex or a set of vertices (if nearest == true) to the passed
	* target point
	*/	
	function moveVertex(sourcePoint, targetPoint) {
		if ( getGeometryType( this.geometry ) == POINT ) {
			this.mvHandlePoint( targetPoint );
		} else if ( getGeometryType( this.geometry ) == LINESTRING ) {
			// TODO
		} else if ( getGeometryType( this.geometry ) == POLYGON ) {
			this.mvHandlePolygon( sourcePoint, targetPoint );
		} 
	}
	
	/**
	* move vertex of a point
	*/
	function mvHandlePoint(targetPoint) {
		if ( pointPointDistance( targetPoint, this.geometry ) <= this.radius ) {
			this.geometry.x = targetPoint.x;
			this.geometry.y = targetPoint.y;
		}
		return this.geometry;
	}
	
	/**
	* move vertex of a polygon
	*/
	function mvHandlePolygon(sourcePoint, targetPoint) {
		var vertices = this.findVertices( this.geometry.points, sourcePoint );
		for ( var i = 0; i < vertices.length; i++) {
			if ( this.isStartVertex( vertices[i] ) ) {
				// if vertex is startpoint of a polygon the endpoint must be moved too
				
				// relative movement
				this.geometry.points[0].x = vertices[i].x - (vertices[i].x - targetPoint.x);
				this.geometry.points[0].y = vertices[i].y - (vertices[i].y - targetPoint.y);
				this.geometry.points[this.geometry.points.length-1].x = this.geometry.points[0].x;
				this.geometry.points[this.geometry.points.length-1].y = this.geometry.points[0].y;
				
				// move to target point
				//this.geometry.points[0].x = targetPoint.x;
				//this.geometry.points[0].y = targetPoint.y;
				//this.geometry.points[this.geometry.points.length-1].x = this.geometry.points[0].x;
				//this.geometry.points[this.geometry.points.length-1].y = this.geometry.points[0].y;
			} else {
				// relative movement
				vertices[i].x = vertices[i].x - (vertices[i].x - targetPoint.x);
				vertices[i].y = vertices[i].y - (vertices[i].y - targetPoint.y);
				
				// move to target point
				//vertices[i].x = targetPoint.x;
				//vertices[i].y = targetPoint.y;
			}
		}
		return this.geometry;
	}
	
	/**
	* returns true if the passed vertex is the start node of current geometry; works
	* for polygons and linestrings
	*/
	function isStartVertex( vertex ) {
		return vertex.equals( this.geometry.points[0] );
	}
	
	/**
	* deletes a vertex from a geometry. If current geometry is a point a message will
	* be promt saying that delete vertex is not a valid operation on points
	*/
	function deleteVertex(targetPoint) {
		if ( getGeometryType( this.geometry ) == POINT ) {
			alert( "point can not be deleted by 'delete vertex' operation" );
		} else if ( getGeometryType( this.geometry ) == LINESTRING ) {
			// TODO
		} else if ( getGeometryType( this.geometry ) == POLYGON ) {
			this.delHandlePolygon( targetPoint );
		}
	}
	
	/**
	* removes a vertex from a polygon
	*/
	function delHandlePolygon(targetPoint) {
		var vertices = this.findVertices( this.geometry.points, targetPoint );
		for ( var i = 0; i < vertices.length; i++) {
			if ( this.isStartVertex( vertices[i] ) ) {
				// if vertex is startpoint of a polygon the endpoint must be deleted too
				this.geometry.points.splice( 0, 1 );
				this.geometry.points.splice( this.geometry.points.length-1, 1 );
				this.geometry.points.push( this.geometry.points[0] );
			} else {
				for (var j = 0; j < this.geometry.points.length; j++ ) {
					if ( this.geometry.points[j].equals( vertices[i] ) ) {
						this.geometry.points.splice( j, 1 );
					}
				}
			}
		}
	}
	
	/**
	* inserts a vertex into a geometry
	*/
	function insertVertex(vertex) {
		if ( getGeometryType( this.geometry ) == POINT ) {
			alert( 'A vertext Point can not be inserted into a point' );
		} else if ( getGeometryType( this.geometry ) == LINESTRING ) {
			this.insertHandleLinestring( vertex );
		} else if (getGeometryType( this.geometry ) == POLYGON ) {
			this.insertHandlePolygon( vertex );
		} 
	}

   /**
	* inserts a vertex into a polygon ring
	*/
	function insertHandleLinestring(vertex) {
		this.insertHandlePolygon( vertex );
	}
	
	/**
	* inserts a vertex into a polygon ring
	*/
	function insertHandlePolygon(vertex) {
		var idx = 0;
		var dist = 99999999;
		var points = this.geometry.points;
		for ( var i = 0; i < points.length-1; i++) {
			var tmp = pointLineSegDistance( points[i], points[i+1], vertex );
			if ( tmp < dist ) {
				idx = i;
				dist = tmp;				
			}
		}
		var p = new Array();
		for ( var i = 0; i < points.length; i++) {
			p.push( points[i] );
			if ( i == idx ) {
				p.push( vertex );
			}
		}
		this.geometry.points = p;
	}
		
	/**
	* returns a list of vertices within the current tolerance radius around the refPoint or 
	* just the nearest point within the radius if instance variable 'nearest' is true
	*/
	function findVertices(vertices, refPoint) {
		var result = new Array();
		var minDist = 999999999.0;
		for ( var i = 0; i < vertices.length; i++) {
			var d = pointPointDistance( refPoint, vertices[i] );
			if ( d <= this.radius ) {
				if ( this.nearest ) {
					if ( d < minDist ) {
						minDist = d;
						if ( result.length > 0 ) {
							result.shift();
						}	
						result.push( vertices[i] );
					}
				} else {
					result.push( vertices[i] );
				}
			}
		}
		return result;
	}
}
