package
{
    import be.mrhenry.controls.Label;
    
    import com.adobe.viewsource.ViewSource;
    
    import flash.display.Graphics;
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.events.MouseEvent;

    
    [SWF("0xEFEFEF",width="490", height="340")]
    public class TheObserver extends Sprite
    {
        
        private var numberOfPoints : Number = 20;
        private var radius : Number = 100;
        private var distanceOfObserver : Number = 20;
        private var dots : Array;
        private var circle : Sprite;
        private var observer : Sprite;
        private var axis : Sprite;
        private var angle : Number;
        private var paused : Boolean = false;
        private var vx : Number;
        private var vy : Number;
        private var mouseDown : Boolean = false;
        private var currentDot : Sprite;
        private var label : Label;
        
        public function TheObserver()
        {
            super ();

            init ();
        }
        
        private function init () : void
        {
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.frameRate = 31;
            
            createLabel();
            createCircle ();
            createAxis ();
            plotPointsOnACircle ();
            createObserver ();
            positionChildren (null);
            startObserving ();
            
            stage.addEventListener( Event.RESIZE, positionChildren, false, 0, true );
        }
        

        private function createCircle() : void
        {
            circle = new Sprite();
            
            var g : Graphics = circle.graphics;
            g.lineStyle( 1, 0xFF0000, .2 );
            g.drawCircle( 0,0, radius );
            
            g.lineStyle( 0 );
            g.beginFill( 0 );
            g.drawCircle( 0,0,3 );
            
            // axis of circle
            g.lineStyle(1,0x003487,0.1);
            g.moveTo( 0, -radius );
            g.lineTo( 0, radius );
            g.moveTo( -radius, 0 );
            g.lineTo( radius, 0 );

            g.endFill();
            
            addChild( circle );
        }
        
        private function plotPointsOnACircle () : void
        {
            angle = Math.PI * 2 / numberOfPoints;
            var dot : Sprite;
            dots = new Array( numberOfPoints );
            
            
            var c : Number = 0xFF9A1B;
            
            for( var i : int = 0; i < numberOfPoints; i++ )
            {
                dot = circle.addChild( getDot(c) ) as Sprite;
                dot.x = radius * Math.cos( angle * i );
                dot.y = radius * Math.sin( angle * i );
                dots[i] = dot;
                
            }
            
            currentDot = dot;
            onDot(null);
        }
        
        private function createLabel () : void
        {
            label = new Label();
            addChild( label );
        }
        
        private function createObserver () : void
        {
            observer = new Sprite ();
            var g : Graphics = observer.graphics;
            var b : Number = 10;
            g.beginFill(0xEFEFEF,1);
            g.lineStyle(6,0x999999);
            g.drawCircle(0,0,b );
            
            addChild( observer );
            
            observer.addEventListener( MouseEvent.MOUSE_DOWN, dragObserver, false, 0, true );
            observer.addEventListener( MouseEvent.MOUSE_UP, stopDragObserver, false, 0, true );
        }
        
        
        
        private function createAxis () : void
        {
            axis = new Sprite;
            var f : Number = 1.4;
            var g : Graphics = axis.graphics;
            g.lineStyle(1,0,.2);
            g.moveTo( 0, -radius*f );
            g.lineTo( 0, radius*f );
            g.moveTo( -radius*f, 0 );
            g.lineTo( radius*f, 0 );
            
            
            g.lineStyle(2,0,.4);
            g.moveTo( -4, -radius );
            g.lineTo( 4, -radius );
            
            g.moveTo( radius, -4 );
            g.lineTo( radius, 4 );
            
            g.endFill();
            
            axis.alpha = 1;
            
            var tf : Label = new Label();
            tf.text.text = "0";
            tf.x = 3;
            tf.y -= 22;
            axis.addChild( tf );
            
            tf = new Label();
            tf.text.text = "100";
            tf.x = radius + 4;
            tf.y -= 22;
            axis.addChild( tf );
            
            tf = new Label();
            tf.text.text = "100";
            tf.x = 3;
            tf.y = - radius - tf.height -4;
            
            axis.addChild( tf );
            
            addChildAt( axis, 0 );
        }
        
        private function positionChildren ( e : Event ) : void
        {

            circle.x = stage.stageWidth/2 ;
            circle.y = stage.stageHeight/2;
            axis.x  = circle.x;
            axis.y = circle.y;
            observer.x = 45;
            observer.y = 45;

        }
        
        private function startObserving () : void
        {
            this.addEventListener( Event.ENTER_FRAME, observe, false, 0, true );
        }
        
        private function onDot ( m : MouseEvent ) : void
        {
            var dotGraphics : Graphics;
            
            if( currentDot != null )
            {
                dotGraphics = currentDot.graphics;
                dotGraphics.clear();
                dotGraphics.beginFill( 0xEFEFEF );
                dotGraphics.lineStyle(4,0xFF9A1B,1);
                dotGraphics.drawCircle( 0,0, 8 );
                dotGraphics.endFill();
            }
            
            if( m != null )
                currentDot = m.target as Sprite;
            

            
            if( currentDot != null )
            {
                dotGraphics = currentDot.graphics;
                dotGraphics.clear();
                dotGraphics.beginFill( 0xFFFFFF );
                dotGraphics.lineStyle(5,0xFF0000,1);
                dotGraphics.drawCircle( 0,0, 8 );
                dotGraphics.endFill();
            }
        }

        private function observe ( e : Event ) : void
        {

            
            var g : Graphics = this.graphics;
            g.clear();
            
            var dot : Sprite;
            var da : Number; 
            var dx : Number = 0;
            var dy : Number = 0;
            var a : Number = circle.rotation * Math.PI / 180; // convert to radians
            var i : int = 0;
            
            for( ; i < numberOfPoints; i++ )
            {
                dot = dots[i]; // get next dot in line
                
                da = angle * i; // angle of the dot on the circle ( orginal angle )
                da += a; // add rotation of the circle, the circle which contains the dot also has a rotation of it's own
                dx = Math.cos( da ) * radius; // calculate new x coordinate relative to the observer, taking the circle's rotation into account
                dy = Math.sin( da ) * radius; // calculate new y coordinate relative to the observer
                
                // draw the colourful lines
                
                
                if (currentDot != null && dot == currentDot )
                {
                    g.lineStyle(2,0,1);
                    g.moveTo( circle.x + dx, circle.y + dy); 
                    g.lineTo( observer.x, observer.y );
                    
                    
                    var totalX : Number = circle.x + dx - observer.x;
                    var totalY : Number = circle.y + dy - observer.y;
                    
                    var dist : Number = Math.sqrt( totalX*totalX + totalY*totalY );
                    label.text.text = "distance from observer to red dot: " + Math.round(dist);
                }else{
                    g.lineStyle(1,0x333333,.2);
                    g.moveTo( circle.x + dx, circle.y + dy); 
                    g.lineTo( observer.x, observer.y );
                }    
            }
            
            if( currentDot == null )
            {
                label.text.text = "click to select a dot";
            }
            
            g.endFill();

            circle.rotation-=1;
            
            
        }
        
        private function getDot ( color : Number ) : Sprite
        {
            var dot : Sprite = new Sprite;
            dot.addEventListener( MouseEvent.CLICK, onDot, false, 0, true );
            dot.useHandCursor = true;
            dot.buttonMode = true;
            dot.mouseChildren = false;
            var g : Graphics = dot.graphics;
            g.beginFill(0xEFEFEF,1);
            g.lineStyle(4,color,1);
            g.drawCircle( 0,0, 8 );
            g.endFill();
            return dot;
        }
        
        private function dragObserver( m : MouseEvent ) : void
        {
            observer.startDrag();
            mouseDown = true;
        }
        
        private function stopDragObserver ( m : MouseEvent ) : void
        {
            observer.stopDrag();
            mouseDown = false;
        }
    }
}