package classes.away3d.core.base
{
	import classes.away3d.arcane;
	import classes.away3d.core.geom.*;
    import classes.away3d.core.vos.*;
    import classes.away3d.materials.*;

    use namespace arcane;
    
	 /**
	 * Dispatched when the material of the segment changes.
	 * 
	 * @eventType away3d.events.FaceEvent
	 */
	[Event(name="materialchanged",type="away3d.events.FaceEvent")]
	
    /**
    * A line element used in the wiremesh and mesh object
    * 
    * @see away3d.core.base.WireMesh
    * @see away3d.core.base.Mesh
    */
    public class Segment extends Element
    {
		/** @private */
        arcane var _v0:Vertex;
		/** @private */
        arcane var _v1:Vertex;
		/** @private */
        arcane var _material:Material;
		
  		private function addVertexAt(index:uint, vertex:Vertex, command:String):void
  		{
  			if (_vertices.length <= index)
  				_vertices.length = index + 1;
  			
  			if(_vertices[index] && _vertices[index] == vertex)
  				return;
  			
  			if (_vertices[index]) {
	  			_index = _vertices[index].parents.indexOf(this);
	  				if(_index != -1)
	  					_vertices[index].parents.splice(_index, 1);
	  		}
	  		
  			_commands[index] = segmentVO.commands[index] = command;
  			_vertices[index] = segmentVO.vertices[index] = vertex;
  			
  			if(index == 0)
  				_v0 = vertex;
  			else if(index == 1)
  				_v1 = vertex;
  			
  			vertex.parents.push(this);
  			
  			vertexDirty = true;
  		}
  		
  		public function moveTo(x:Number, y:Number, z:Number):void
  		{
  			var newVertex:Vertex = new Vertex(x, y, z);
  			addVertexAt(_vertices.length, newVertex, PathCommand.MOVE);
  			
			_pathCommands.push(new PathCommand(PathCommand.MOVE, _lastAddedVertex.position, null, newVertex.position));
  			_lastAddedVertex = newVertex;
  		}
  		
  		public function lineTo(x:Number, y:Number, z:Number):void
  		{
  			var newVertex:Vertex = new Vertex(x, y, z);
  			addVertexAt(_vertices.length, newVertex, PathCommand.LINE);
  			
  			_pathCommands.push(new PathCommand(PathCommand.LINE, _lastAddedVertex.position, null, newVertex.position));
  			_lastAddedVertex = newVertex;
  		}
  		
  		public function curveTo(cx:Number, cy:Number, cz:Number, ex:Number, ey:Number, ez:Number):void
  		{
  			var newControlVertex:Vertex = new Vertex(cx, cy, cz);
  			var newEndVertex:Vertex = new Vertex(ex, ey, ez);
  			addVertexAt(_vertices.length, newControlVertex, PathCommand.CURVE);
  			addVertexAt(_vertices.length, newEndVertex, "P");
  			
  			_pathCommands.push(new PathCommand(PathCommand.CURVE, _lastAddedVertex.position, newControlVertex.position, newEndVertex.position));
  			_lastAddedVertex = newEndVertex;
  		}
		
		public function defineSingleCurve(start:Vertex, control:Vertex, end:Vertex):void
  		{
			addVertexAt(_vertices.length, start, PathCommand.MOVE);
			addVertexAt(_vertices.length, control, PathCommand.CURVE);
  			addVertexAt(_vertices.length, end, "P");
			
			_commands.splice(0,1);
			segmentVO.commands.splice(0,1);
			_commands[0] = segmentVO.commands[0] = "NONE";
			_vertices.splice(0,1);
			segmentVO.vertices.splice(0,1);
		}
  		
		public var segmentVO:SegmentVO = new SegmentVO();
        
		/**
		 * Defines the v0 vertex of the segment.
		 */
        public function get v0():Vertex
        {
            return _v0;
        }

        public function set v0(value:Vertex):void
        {
            addVertexAt(0, value, "M");
        }
		
		/**
		 * Defines the v1 vertex of the segment.
		 */
        public function get v1():Vertex
        {
            return _v1;
        }

        public function set v1(value:Vertex):void
        {
            addVertexAt(1, value, "L");
        }
		
		/**
		 * Defines the material of the segment.
		 */
        public function get material():Material
        {
            return _material;
        }

        public function set material(value:Material):void
        {
            if (value == _material)
                return;
            
			if (_material != null && parent)
				parent.removeMaterial(this, _material);
			
            _material = segmentVO.material = value;
			
			if (_material != null && parent)
				parent.addMaterial(this, _material);
        }
		
		/**
		 * Returns the squared bounding radius of the segment.
		 */
        public override function get radius2():Number
        {
            var rv0:Number = _v0._x*_v0._x + _v0._y*_v0._y + _v0._z*_v0._z;
            var rv1:Number = _v1._x*_v1._x + _v1._y*_v1._y + _v1._z*_v1._z;

            if (rv0 > rv1)
                return rv0;
            else
                return rv1;
        }
        
    	/**
    	 * Returns the maximum x value of the segment
    	 * 
    	 * @see		away3d.core.base.Vertex#x
    	 */
        public override function get maxX():Number
        {
            if (_v0._x > _v1._x)
                return _v0._x;
            else
                return _v1._x;
        }
        
    	/**
    	 * Returns the minimum x value of the face
    	 * 
    	 * @see		away3d.core.base.Vertex#x
    	 */
        public override function get minX():Number
        {
            if (_v0._x < _v1._x)
                return _v0._x;
            else
                return _v1._x;
        }
        
    	/**
    	 * Returns the maximum y value of the segment
    	 * 
    	 * @see		away3d.core.base.Vertex#y
    	 */
        public override function get maxY():Number
        {
            if (_v0._y > _v1._y)
                return _v0._y;
            else
                return _v1._y;
        }
        
    	/**
    	 * Returns the minimum y value of the face
    	 * 
    	 * @see		away3d.core.base.Vertex#y
    	 */
        public override function get minY():Number
        {
            if (_v0._y < _v1._y)
                return _v0._y;
            else
                return _v1._y;
        }
        
    	/**
    	 * Returns the maximum z value of the segment
    	 * 
    	 * @see		away3d.core.base.Vertex#z
    	 */
        public override function get maxZ():Number
        {
            if (_v0._z > _v1._z)
                return _v0._z;
            else
                return _v1._z;
        }
        
    	/**
    	 * Returns the minimum y value of the face
    	 * 
    	 * @see		away3d.core.base.Vertex#y
    	 */
        public override function get minZ():Number
        {
            if (_v0._z < _v1._z)
                return _v0._z;
            else
                return _v1._z;
        }
    	
		/**
		 * Creates a new <code>Segment</code> object.
		 *
		 * @param	v0						The first vertex object of the segment
		 * @param	v1						The second vertex object of the segment
		 * @param	material	[optional]	The material used by the segment to render
		 */
        public function Segment(v0:Vertex = null, v1:Vertex = null, material:Material = null)
        {
        	if(v0)
            	this.v0 = v0;
            if(v1)
            	this.v1 = v1;
            
            this.material = material;
            
            //segmentVO.segment = this;
            
            vertexDirty = true;
        }
        
        public function drawPath(path:Path):void
        {
        	for each (var command:PathCommand in path.array) {
        		moveTo(command.pStart.x, command.pStart.y, command.pStart.z);
        		curveTo(command.pControl.x, command.pControl.y, command.pControl.z, command.pEnd.x, command.pEnd.y, command.pEnd.z);
        	}
        }
    }
}
