import flash.display3D.Context3D;

import flash.xml.XML;
import flash.xml.XMLList;
import flash.xml.XMLParser;

// available objects and their params
// Cone: radius, height, quality
// Cube: x, y, z
// Cylinder: radius, height, quality
// Square: width, height

class WMObject3D extends WMObjBase {
  public var type( __getType, __setType ):String;
  public var xsize( __getX, __setX ):Float;
  public var ysize( __getY, __setY ):Float;
  public var zsize( __getZ, __setZ ):Float;
  public var pos( __getPos, __setPos ):Point3D;
  public var dir( __getDir, __setDir ):Point3D;

  public function new( ?r:Float = 1.0,
                       ?c0:Int = 0x00FF00,
                       ?c1:Int = 0x00FF00,
                       ?a:Float = 1.0,
                       ?o:Float = 0.0,
                       ?q:Int = 3,
                       ?ag:Float = 0.35,
                       ?d:Float = 0.7,
                       ?sp:Float = 0.8,
                       ?gl:Float = 20.0,
                       ?sh:String = "Phong" ) {
    super( r, c0, c1, a, o, q, ag, d, sp, gl, sh );
    type = "cone";
    xsize = ysize = zsize = 0.0;
    pos = null;
    dir = null;
    _polygon = null;
  }

  public override function clear( ?def:WMDefaults = null ):Void {
    if ( def != null ) {
      copyFrom( def.Object3D );
      type = def.Object3DType;
    } else {
      radius = 1.0;
      color0 = 0x00FF00;
      color1 = 0x00FF00;
      alpha = 1.0;
      offset = 0.0;
      quality = 3;
      ambient = 0.35;
      diffuse = 0.7;
      specular = 0.8;
      gloss = 20.0;
      shader = "Phong";
      type = "cone";
    }
    pos = null;
    dir = null;
    _polygon = null;
  }

  public override function loadFromXml( x:Xml,
                                        ?def:WMDefaults = null ):Void {
    super.loadFromXml( x, def );
    if ( !x.exists( "pos" ) ) {
      trace( "pos attribute is required for an <OBJ3D>" );
      return;
    }
    pos = Point3D.fromString( x.get( "pos" ) );
    if ( x.exists( "dir" ) ) dir = Point3D.fromString( x.get( "dir" ) );
    if ( x.exists( "x" ) ) xsize = Std.parseFloat( x.get( "x" ) );
    if ( x.exists( "y" ) ) ysize = Std.parseFloat( x.get( "y" ) );
    if ( x.exists( "z" ) ) zsize = Std.parseFloat( x.get( "z" ) );
    if ( x.exists( "type" ) ) type = x.get( "type" );
  }

  public function gen( c:Context3D ):Void {
    switch( type ) {
      case "cone":
        var myrad:Float = ( xsize == 0.0 ) ? radius : xsize;
        _polygon = new Cone3D( myrad, ysize, quality );
      case "cube":
        _polygon = new Cube3D( xsize, ysize, zsize );
      case "cylinder":
        var myrad:Float = ( xsize == 0.0 ) ? radius : xsize;
        _polygon = new Cylinder( myrad, ysize, quality );
      case "square":
        _polygon = new Square3D( xsize, ysize, true );
    }
    if ( dir != null ) _polygon.lookAt( dir );
    _polygon.translate( pos.x, pos.y, pos.z );
    _polygon.allocate( c, shader, color0, alpha );
  }

  public function __getType():String { return( type ); }
  public function __getX():Float { return( xsize ); }
  public function __getY():Float { return( ysize ); }
  public function __getZ():Float { return( zsize ); }
  public function __getPos():Point3D { return( pos ); }
  public function __getDir():Point3D { return( dir ); }
  public function __setType( s:String ):String {
    type = s;
    return( s );
  }
  public function __setX( x:Float ):Float {
    xsize = x;
    return( xsize );
  }
  public function __setY( y:Float ):Float {
    ysize = y;
    return( ysize );
  }
  public function __setZ( z:Float ):Float {
    zsize = z;
    return( zsize );
  }
  public function __setPos( p:Point3D ):Point3D {
    if ( p != null ) pos = p.clone();
    return( pos );
  }
  public function __setDir( d:Point3D ):Point3D {
    if ( d != null ) dir = d.clone();
    return( dir );
  }
  public function num():Int { return(1); }
  public function sumPos():Point3D { return( pos ); }
  public function translate( p:Point3D ):Void { pos.add( p ); }
  public function absmax():Point3D {
    return( new Point3D( Math.abs( pos.x ), Math.abs( pos.y ), Math.abs( pos.z ) ) );
  }
  public function scaleCoord( scale:Float ):Void {
    pos.multiply( scale );
    xsize *= scale;
    ysize *= scale;
    zsize *= scale;
  }
}
