import flash.display.Stage;

class WMBase {
  static public var useRelative = true;
  static public var scaleBase:Float = 0.0;
  static public var characteristicSize:Float = 0.0025;

  static public function splitString( s:String ):Array< String > {
    var v0:EReg = ~/^\s*/;
    var v1:EReg = ~/\s*$/;
    var v2:EReg = ~/\s+/g;
    var mystr:String = v0.replace( s, "" );
    mystr = v1.replace( mystr, "" );
    mystr = v2.replace( mystr, " " );
    return( mystr.split( " " ) );
  }

  static public function setScaleBase( st:Stage ):Void {
    scaleBase = Math.min( st.stageWidth, st.stageHeight );
    scaleBase *= characteristicSize;
  }

  static public function getRelative( r:Float ):Float {
    if ( !useRelative ) return( r );
    // if not initialized, use width and height of root stage
    if ( scaleBase == 0.0 ) setScaleBase( flash.Lib.current.stage );
    return( r * scaleBase );
  }

  static public function parseColor( c:String ):Int {
    var v:EReg = ~/\s+/g;
    var s:String = v.replace( c, "" );
    if ( s.charAt(0) == '0' ) return( Std.parseInt( s ) );
    switch( s.toLowerCase() ) {
      case "white": return( 0xFFFFFF );
      case "silver": return( 0xC0C0C0 );
      case "gray": return( 0x808080 );
      case "black": return( 0x000000 );
      case "cyan": return( 0x00FFFF );
      case "navy": return( 0x000080 );
      case "blue": return( 0x0000FF );
      case "lime": return( 0x00FF00 );
      case "green": return( 0x008000 );
      case "springgreen": return( 0x00FF7F );
      case "limegreen": return( 0x32CD32 );
      case "darkgreen": return( 0x006400 );
      case "khaki": return( 0xF0E68C );
      case "orange": return( 0xFFA500 );
      case "yellow": return( 0xFFFF00 );
      case "brown": return( 0xA52A2A );
      case "chocolate": return( 0xD2691E );
      case "gold": return( 0xFFD700 );
      case "violet": return( 0xEE82EE );
      case "salmon": return( 0xFA8072 );
      case "purple": return( 0x800080 );
      case "red": return( 0xFF0000 );
      case "magenta": return( 0xFF00FF );
      case "pink": return( 0xFFC0CB );
      default:
        var r0:EReg = ~/[a-z]/;
        if ( r0.match( s ) ) {
          trace( "warning: unknown color? : " + s );
        }
        return( Std.parseInt( s ) );
    }
  }

  public var radius( __getRadius, __setRadius ):Float;
  public var color0( __getColor0, __setColor0 ):Int;
  public var color1( __getColor1, __setColor1 ):Int;
  public var alpha( __getAlpha, __setAlpha ):Float;
  public var offset( __getOffset, __setOffset ):Float;
  public var quality( __getQuality, __setQuality ):Int;

  public var ambient( __getAmbient, __setAmbient ):Float;
  public var diffuse( __getDiffuse, __setDiffuse ):Float;
  public var specular( __getSpecular, __setSpecular ):Float;
  public var gloss( __getGloss, __setGloss ):Float;
  public var shader( __getShaderName, __setShaderName ):String;

  public function new( ?r:Float = 0.0,
                       ?c0:Int = 0x000000,
                       ?c1:Int = 0x000000,
                       ?a:Float = 1.0,
                       ?o:Float = 0.0,
                       ?q:Int = 0,
                       ?ag:Float = 0.3,
                       ?d:Float = 0.5,
                       ?sp:Float = 0.2,
                       ?gl:Float = 20.0,
                       ?sh:String = "Phong" ):Void {
    set( r, c0, c1, a, o, q, ag, d, sp, gl, sh );
  }

  public function set( ?r:Float = 0.0,
                       ?c0:Int = 0x000000,
                       ?c1:Int = 0x000000,
                       ?a:Float = 1.0,
                       ?o:Float = 0.0,
                       ?q:Int = 0,
                       ?ag:Float = 0.3,
                       ?d:Float = 0.5,
                       ?sp:Float = 0.2,
                       ?gl:Float = 20.0,
                       ?sh:String = "Phong" ):Void {
    radius = r;
    color0 = c0;
    color1 = c1;
    alpha = a;
    offset = o;
    quality = q;
    ambient = ag;
    diffuse = d;
    specular = sp;
    gloss = gl;
    shader = sh;
  }

  public function clear( ?def:WMDefaults = null ):Void {
    if ( def != null ) {
      copyFrom( def.Atom );
    } else {
      radius = 0.0;
      color0 = 0x000000;
      color1 = 0x000000;
      alpha = 1.0;
      offset = 0.0;
      quality = 0;
      ambient = 0.3;
      diffuse = 0.5;
      specular = 0.2;
      gloss = 20.0;
      shader = "Phong";
    }
  }

  public function copyFrom( d:Dynamic ):Void {
    radius = d.radius;
    color0 = d.color0;
    color1 = d.color1;
    alpha = d.alpha;
    offset = d.offset;
    quality = d.quality;
    ambient = d.ambient;
    diffuse = d.diffuse;
    specular = d.specular;
    gloss = d.gloss;
    shader = d.shader;
  }

  public function loadFromXml( x:Xml,
                               ?def:WMDefaults = null ):Void {
    // radius: r, w, radius, width
    var strs = [ "width", "w", "radius", "r" ];
    for ( str in strs ) {
      if ( x.exists( str ) ) radius = Std.parseFloat( x.get( str ) );
    }
    // color: c, color
    strs = [ "color", "c" ];
    for ( str in strs ) {
      if ( x.exists( str ) ) color0 = color1 = WMBase.parseColor( x.get( str ) );
    }
    // color0: c0, col0, color0
    strs = [ "c0", "col0", "color0" ];
    for ( str in strs ) {
      if ( x.exists( str ) ) color0 = WMBase.parseColor( x.get( str ) );
    }
    // color1: c1, col1, color1
    strs = [ "c1", "col1", "color1" ];
    for ( str in strs ) {
      if ( x.exists( str ) ) color1 = WMBase.parseColor( x.get( str ) );
    }
    // alpha: a, alpha
    strs = [ "alpha", "a" ];
    for ( str in strs ) {
      if ( x.exists( str ) ) alpha = Std.parseFloat( x.get( str ) );
    }
    // offset: o, offset
    strs = [ "o", "offset" ];
    for ( str in strs ) {
      if ( x.exists( str ) ) offset = Std.parseFloat( x.get( str ) );
    }
    // quality: q, qua, quality
    strs = [ "q", "qua", "quality" ];
    for ( str in strs ) {
      if ( x.exists( str ) ) quality = Std.parseInt( x.get( str ) );
    }
    // ambient: am, amb, ambient
    strs = [ "am", "amb", "ambient" ];
    for ( str in strs ) {
      if ( x.exists( str ) ) ambient = Std.parseFloat( x.get( str ) );
    }
    // diffuse: d, dif, diff, diffuse
    strs = [ "d", "dif", "diff", "diffuse" ];
    for ( str in strs ) {
      if ( x.exists( str ) ) diffuse = Std.parseFloat( x.get( str ) );
    }
    // specular: s, spe, specular
    strs = [ "s", "spe", "spec", "specular" ];
    for ( str in strs ) {
      if ( x.exists( str ) ) specular = Std.parseFloat( x.get( str ) );
    }
    // gloss: g, gloss
    strs = [ "g", "gloss" ];
    for ( str in strs ) {
      if ( x.exists( str ) ) gloss = Std.parseFloat( x.get( str ) );
    }
    // shader: shade, shader, shading
    strs = [ "shade", "shader", "shading" ];
    for ( str in strs ) {
      if ( x.exists( str ) ) {
        var vstr:String = x.get( str ).toLowerCase();
        if ( vstr == "simple" ) {
          shader = "Simple";
        } else if ( vstr == "gouraud" ) {
          shader = "Gouraud";
        } else if ( vstr == "phong" ) {
          shader = "Phong";
        }
      }
    }
  }

  // getters and setters
  public function __getRadius():Float { return( radius ); }
  public function __getColor0():Int { return( color0 ); }
  public function __getColor1():Int { return( color1 ); }
  public function __getAlpha():Float { return( alpha ); }
  public function __getOffset():Float { return( offset ); }
  public function __getQuality():Int { return( quality ); }
  public function __getAmbient():Float { return( ambient ); }
  public function __getDiffuse():Float { return( diffuse ); }
  public function __getSpecular():Float { return( specular ); }
  public function __getGloss():Float { return( gloss ); }
  public function __getShaderName():String { return( shader ); }
  public function __setRadius( r:Float ):Float { radius = r; return( radius ); }
  public function __setColor0( c:Int ):Int { color0 = c; return( color0 ); }
  public function __setColor1( c:Int ):Int { color1 = c; return( color1 ); }
  public function __setAlpha( a:Float ):Float { alpha = a; return( alpha ); }
  public function __setOffset( o:Float ):Float { offset = o; return( offset ); }
  public function __setQuality( q:Int ):Int { quality = q; return( quality ); }
  public function __setAmbient( a:Float ):Float { ambient = a; return( ambient ); }
  public function __setDiffuse( d:Float ):Float { diffuse = d; return( diffuse ); }
  public function __setSpecular( s:Float ):Float { specular = s; return( specular ); }
  public function __setGloss( g:Float ):Float { gloss = g; return( gloss ); }
  public function __setShaderName( sn:String ):String { shader = sn; return( shader ); }
}
