/* {{{ GPL

 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 2
 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, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

}}} */

var Figure = Class.extend({
    
  // {{{ init
  init: function( name ){

    this.name = name;
    this.id = null;
    this.root = new Root( 0, 0, this );

    this.palette = new Palette();
    this.palette.addColor( new Color( 0, 0, 0 ) );

    this.radius = null;
    this.handles = null;
  },
  // }}}

  // {{{ getRoot
  getRoot: function() {
    return this.root;
  },
  // }}}

  // {{{ translate
  translate: function( dx, dy ) {
    this.root.translate( dx, dy );
  },
  // }}}

  // {{{ rotate
  rotate: function( angle ) {
    for ( var i = 0; i < this.root.children.length; i ++ ) {
      var node = this.root.children[i];
      node.rotate( angle );
    }
  },
  // }}}
  
  // {{{ scale
  scale: function( sc ) {
    
    var toOrigin = Matrices.translation( - this.root.x, - this.root.y );
    var scale = Matrices.scale( sc, sc );
    var backAgain = Matrices.translation( this.root.x, this.root.y );
        
    var transformation = Matrices.combine( Matrices.combine( toOrigin, scale ), backAgain );

    for ( var i = 0; i < this.root.children.length; i ++ ) {
      var node = this.root.children[i];
      node.transform( transformation );
    }
    
    // Scale the line widths
    var iter = new NodeIterator( this.root );
    while ( iter.hasNext() ) {
      var node = iter.next();
      node.lineWidth *= sc;
    }
    
    if (this.radius) {
      this.radius *= sc;
    }
  },
  // }}}    

  // {{{ flipHorizontal
  flipHorizontal: function() {
    
    this.root.transform( Matrices.scale( -1, 1 ) );
    this.root.translate( - this.root.x * 2, 0 );
    var iter = new NodeIterator( this.root );
    while ( iter.hasNext() ) {
      var node = iter.next();
      if ( node.behaviour.flipped ) {
        node.behaviour = node.behaviour.flipped;
      }
    }        
  },
  // }}}
  
  // {{{ flipVertical
  flipVertical: function() {
    
    this.root.transform( Matrices.scale( 1, -1 ) );
    var iter = new NodeIterator( this.root );
    while ( iter.hasNext() ) {
      var node = iter.next();
      if ( node.behaviour.flipped ) {
        node.behaviour = node.behaviour.flipped;
      }
    }        
  },
  // }}}
  
  // {{{ center
  center: function( animation ) {
    this.log.debug( "Centering figure within", animation.width, animation.height );
    this.translate( animation.width / 2 - this.root.x, animation.height / 2 - this.root.y );
  },
  // }}}

  // {{{ draw
  draw: function( context, onionSkinning ) {
    if ( onionSkinning ) {
      this.root.draw( context, null );
    } else {
      this.root.draw( context, this.palette );
    }
  },
  // }}}

  // {{{ drawHandles
  drawHandles: function( context, zoom, drawStatic ) {
    var iter = new NodeIterator( this.root );
    while ( iter.hasNext() ) {
      var node = iter.next();
      if ( node.isStatic ) {
        if ( drawStatic ) {
          Handle.STATIC_HANDLE.drawHandle( node, context, zoom );
        }
      } else {
        node.drawHandle( context, zoom );
      }
    }

  },
  // }}}
  
  // {{{ findNodeAt
  findNodeAt: function( x, y ) {
    var iter = new NodeIterator( this.root );
    while ( iter.hasNext() ) {
      var node = iter.next();
      if ( node.isTouching( x, y ) ) {
        return node;
      }
    }
    return null;
  },
  // }}}
  
  // {{{ findHandleAt
  findHandleAt: function( x, y, zoom, includeStatic ) {
    this.log.debug( "findHandleAt", x, y, "verses", this.x, this.y );
    var iter = new NodeIterator( this.root );
    while ( iter.hasNext() ) {
      var node = iter.next();
      if ( includeStatic || (node.isStatic == false) ) {
        if ( node.isTouchingHandle( x, y, zoom ) ) {
          this.log.debug( "findHandleAt - found", this );
          return node;
        }
      }
    }
    return null;
  },
  // }}}
      
  // {{{ getRadius
  getRadius: function() {
  
    var largest2 = 0;
    var x = this.root.x;
    var y = this.root.y;
    
    var iter = new NodeIterator( this.root );
    while( iter.hasNext() ) {
      
      var node = iter.next();
      if ( ! node.isControl() ) {
        
        var dx = x - node.x;
        var dy = y - node.y;
        var r2 = dx * dx + dy * dy;
        if ( r2 > largest2 ) {
          largest2 = r2;
        }
        
      }
    }
    
    this.radius = Math.sqrt( largest2 ) * 1.05;
    return this.radius;
  },
  // }}}
    
  // {{{ createHandles
  createHandles: function() {

    this.deleteHandles();
    this.log.debug( "Creating handles" );
    this.getRadius();
      
    this.handles = [];

    var x = this.root.x;
    var y = this.root.y;
        
    var count = 3;
    var angle = - Math.PI / 2;
    for ( var i = 0; i < count; i ++ ) { 
      var hx = Math.cos( angle ) * this.radius;
      var hy = Math.sin( angle ) * this.radius;
      var handle = new Control( x + hx, y + hy );
      handle.behaviour = Behaviour.BOUNDING_BEHAVIOUR;
      this.root.addNode( handle );
      this.handles[ this.handles.length ] = handle;
      angle = angle + Math.PI * 2 / count;
    }
  },
  // }}}
  
  // {{{ deleteHandles
  deleteHandles: function() {
      
    if ( this.handles != null ) {
          
      this.log.debug( "Deleting handles" );
      for ( var i = 0; i < this.handles.length; i ++ ) {
        this.handles[ i ].remove();
      }
      this.handles = null;
    }
  },
  // }}}    

  // {{{ drawBounding
  drawBounding: function( context, zoom ) {
    if ( this.radius == null ) {
      return;
    }
      
    var x = this.root.x;
    var y = this.root.y;
        
    context.lineWidth = 2.0 / zoom;
    context.beginPath();
    // context.set_dash( [10.0 , 5.0] );
    context.arc( x, y, this.radius, 0, 2 * Math.PI, true );
    // context.set_dash( [] );

    // color = handle._control_color
    context.strokeStyle = "rgba( 0,0,100,0.5 )"; 
    context.stroke();
  },
  // }}}

  // {{{ cleansePalette
  // Removes unused and duplicate colors in the palette
  cleansePalette: function() {

    var newPalette = new Palette();
    var iter = new NodeIterator( this.getRoot() );
    
    while (iter.hasNext()) {
      var node = iter.next();

      if ( node.lineColorIndex != null )  {
        var oldIndex = node.lineColorIndex;
        var color = this.palette.getColor( oldIndex );
        var newIndex = newPalette.addColor( color.copy(), true );
        node.lineColorIndex = newIndex;
        this.log.debug( "Added back color", color, newIndex, newPalette.colors[ newIndex] );
      }
      
      if ( node.fillColorIndex != null ) {
        var oldIndex = node.fillColorIndex;
        var color = this.palette.getColor( oldIndex );
        var newIndex= newPalette.addColor( color.copy(), true );
        node.fillColorIndex = newIndex;
      }
        
    }
    
    this.palette = newPalette;
  },
  // }}}

  // {{{ copy
  copy: function() {

    this.log.debug( "Copying figure : " + this );
    
    var copy = new Figure( this.name );
    copy.id = this.id;
    
    var copyRoot = this.root.copy();
    copy.root.x = copyRoot.x;
    copy.root.y = copyRoot.y;
    for ( var i = 0; i < copyRoot.children.length; i ++ ) {
      copy.root.addNode( copyRoot.children[ i ] );
    }
    
    copy.palette = this.palette.copy();
    
    return copy;
  },
  // }}}
  
  // {{{ toString
  toString: function() {
    return "Figure{name: " + this.name + ", id: " + this.id + "}";
  }
  // }}}
  
}); 


Figure.prototype.log = new Log( "Figure" );

