<?xml version="1.0" encoding="utf-8"?>
<mx:Application
  xmlns:mx="http://www.adobe.com/2006/mxml"
  xmlns:s="library://ns.adobe.com/flex/spark" 
  xmlns:degrafa="http://www.degrafa.com/2007"
  xmlns:geom="components.*"
  xmlns="http://www.degrafa.com/2007"
  layout="absolute"
  width="600" height="500" 
  pageTitle="Degrafa Advanced Cubic Bezier"
  viewSourceURL="srcview/index.html"
  applicationComplete="test()"  >
  
  <mx:Style source="assets/style/style.css"/>
  <mx:Canvas id="background" x="50" y="90" width="500" height="360" backgroundColor="#FFFFFF" >
    <mx:Label x="10" y="300" text="Left stepper modifies t1, right modifies t2 or move interpolation points for new refinement." width="480" color="#000000" fontSize="12"/>
  </mx:Canvas>
  <mx:Label text="Quad Bezier Refinement" x="250" y="30" width="300" styleName="title"/>
  
  <mx:Canvas id="bezierLayer" />
  
  <geom:InteractivePoint id="P0" x="90" y="250" pointLabel="P0" radius="5" color="0x00ff00" width="100" height="20" />
  <geom:InteractivePoint id="P1" x="150" y="150" pointLabel="P1" radius="5" color="0x00ff00" width="100" height="20" />
  <geom:InteractivePoint id="P2" x="290" y="200" pointLabel="P2" radius="5" color="0x00ff00" width="100" height="20" />
  
  <mx:NumericStepper x="418" y="418" id="__t1__" stepSize="0.1" minimum="0.1" maximum="0.8" change="onT1Changed()"/>
  <mx:NumericStepper x="487" y="418" id="__t2__" minimum="0.2" maximum="0.9" stepSize="0.1" change="onT2Changed()"/>
  
  <AdvancedQuadraticBezier id="bezier" graphicsTarget="{[bezierLayer]}">
    <stroke> 
      <SolidStroke weight="2" color="#0000FF"/>
    </stroke>
  </AdvancedQuadraticBezier>
  
  <mx:Script>
    <![CDATA[
      import mx.events.PropertyChangeEvent;
      import mx.core.UIComponent;
      
      import com.degrafa.GraphicPointEX;
      import com.degrafa.core.collections.GraphicPointCollection;
      import com.degrafa.geometry.utilities.BezierUtils;
      
      // refinement bounds must be in open interval (0,1)
      private var __t1:Number = 0.2;
      private var __t2:Number = 0.6;
      
      private var __refinement:UIComponent = new UIComponent();
      
      private function test():void
      { 
        // restrict dragging for each point
        var bounds:Rectangle = new Rectangle(background.x, background.y, background.width, background.height);
        P0.restrict          = bounds;
        P1.restrict          = bounds;
        P2.restrict          = bounds;
        
        // actions when a property is changed on any InteractivePoint
        P0.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, onPropertyChanged);
        P1.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, onPropertyChanged);
        P2.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, onPropertyChanged);
        
        __t1__.value = __t1;
        __t2__.value = __t2;
          
        // assign the bezier data from script - the quad interpolates the three points and show initial refinement in [t1,t2]
        assignBezierInterpolationPoints();
        refineQuad();
        
        // arghh ....
        addChild(__refinement);
      }
      
      private function set t1(t:Number):void
      {
        if( t != __t1 && t < __t2 && t > 0 )
          __t1 = t;
      }
      
      private function set t2(t:Number):void
      {
        if( t != __t2 && t > __t1 && t < 1 )
          __t2 = t;
      }
      
      private function assignBezierInterpolationPoints():void
      {
        // property changes trigger redraw
        var t:Number = bezier.interpolate( [new Point(P0.x, P0.y), new Point(P1.x, P1.y), new Point(P2.x, P2.y)] );
      }
      
      private function onPropertyChanged(_e:PropertyChangeEvent):void
      {
        switch( _e.property )
        {
          case InteractivePoint.MOUSE_DOWN:
            var g:Graphics = __refinement.graphics;
            g.clear();
            
            addEventListener(Event.ENTER_FRAME, onPointMove);
          break;
          
          case InteractivePoint.MOUSE_UP:
            removeEventListener(Event.ENTER_FRAME, onPointMove);
            
            // refine at [t1,t2]
            refineQuad();
          break;
        }
      }
      
      // redraw control points and bezier curve when an InteractivePoint is moved
      private function onPointMove(_e:Event):void
      { 
        assignBezierInterpolationPoints();
      }
      
      // display refinement in [t1,t2]
      private function refineQuad():void
      {
        var g:Graphics = __refinement.graphics;
        g.clear();
        
        g.lineStyle(2,0xff0000);
        
        var quad:Object = BezierUtils.quadRefine(bezier, __t1, __t2);
        g.moveTo(quad.x0, quad.y0);
        g.curveTo(quad.cx, quad.cy, quad.x1, quad.y1);
      }
      
      // note that t2 must be strictly greater than t1
      private function onT1Changed():void
      {
        if( __t1__.value < __t2 )
        {
          t1 = __t1__.value;
          refineQuad();
        }
        else
          __t1__.value = __t1;
      }
      
      private function onT2Changed():void
      {
        if( __t2__.value > __t1 )
        {
          t2 = __t2__.value;
          refineQuad();
        }
        else
          __t2__.value = __t2;
      }  
      
    ]]>
  </mx:Script>
  
</mx:Application>