package tests
{
    public class ComplexType
    {
    public var number : Number;
    public var date : Date;
    public var nullableDate:Date;
    public var str : String;
    public var array : Array;
    public var complexArray : Array;
    public var map : Object;
    public var complexType : ComplexType;
        
      // primitive fields

      public var intField:Number;
      public var floatField:Number;
      public var longField:Number;
      public var shortField:Number;
      public var byteField:Number;
      public var doubleField:Number;
      
      // primitive wrappers fields
      public var intWrapperField:Object;
      public var floatWrapperField:Object;
      public var longWrapperField:Object;
      public var shortWrapperField:Object;
      public var byteWrapperField:Object;
      public var doubleWrapperField:Object;
      // string
      public var stringField:String;
      public var stringBufferField:String;

      // arrays of primitives
      public var intArrayField:Object;
      public var shortArrayField:Object;
      public var longArrayField:Object;
      public var byteArrayField:Object;
      public var doubleArrayField:Object;
      public var floatArrayField:Object;
      // arrays of wrappers
      public var intWrapperArrayField:Object;
      public var shortWrapperArrayField:Object;
      public var longWrapperArrayField:Object;
      public var byteWrapperArrayField:Object;
      public var doubleWrapperArrayField:Object;
      public var floatWrapperArrayField:Object;
      // collections
      public var collectionField:Object;
      public var abstractCollectionField:Object;
      public var listCollectionField:Object;
      public var abstractListField:Object;
      public var abstractSequentialListField:Object;
      public var stackField:Object;
      public var vectorField:Object;
      public var linkedLIstField:Object;
      public var arrayListField:Object;
      public var setField:Object;
      public var sortedSetField:Object;
      public var abstractSetField:Object;
      public var treeSetField:Object;
      public var mapSetField:Object;
      public var abstractMapField:Object;
      public var propertiesField:Object;
      public var treeMapField:Object;    
    
    public function ComplexType( depth : Number )
    {
        this.number = depth;
        this.date = new Date( 2004 - depth );
        this.nullableDate = new Date( 2004 - depth );
        this.str = depth + " ";
        this.array = getArray( depth );
        this.complexArray = getComplexArray( depth );
        this.map = getMap( depth );
        
      // primitive fields

          intField = depth; 
        floatField = depth;
        longField = depth;
        shortField = depth;
        byteField = depth;
        doubleField = depth;
      // primitive wrappers fields
        intWrapperField = depth;
        floatWrapperField = depth;
        longWrapperField = depth;
        shortWrapperField = depth;
        byteWrapperField = depth;
        doubleWrapperField = depth;
      // string
        stringField = depth + "";
        stringBufferField = depth + "";
      // arrays of primitives
        intArrayField = this.array;
        shortArrayField = this.array;
        longArrayField = this.array;
        byteArrayField = this.array;
        doubleArrayField = this.array;
        floatArrayField = this.array;
      // arrays of wrappers
        intWrapperArrayField = this.array;
        shortWrapperArrayField = this.array;
        longWrapperArrayField = this.array;
        byteWrapperArrayField = this.array;
        doubleWrapperArrayField = this.array;
        floatWrapperArrayField = this.array;
    
      // collections
        collectionField = this.array;      
        abstractCollectionField = this.array;
        listCollectionField = this.array;
        abstractListField = this.array;
        
        abstractSequentialListField = this.array;
        stackField = this.array;
        vectorField = this.array;
        linkedLIstField = this.array;
        
        arrayListField = this.array;
        
        setField = this.array;
        sortedSetField = this.array;
        abstractSetField = this.array;
        treeSetField = this.array;        
        
        mapSetField = this.map;        
        abstractMapField = this.map;
        propertiesField = this.map;
        treeMapField = this.map    ;
        
        if( depth > 0 )
          this.complexType = getComplexType( depth - 1 );
    }
    
    public function equals( compType : Object ) : Boolean
    {
        if( compType.number == number &&
           compType.date.getTime() == date.getTime() &&
           compType.nullableDate.getTime() == date.getTime() &&
           compType.str == str &&
           ObjectComparator.equals( compType.array, array ) &&
           ObjectComparator.equals( compType.complexArray, complexArray ) &&
           ObjectComparator.equals( compType.map, map ) &&
           ObjectComparator.equals( complexType, compType.complexType ) &&

           compType.intField == intField &&
           compType.floatField == floatField &&
           compType.longField == longField &&
           compType.shortField == shortField &&
           compType.byteField == byteField &&
           compType.doubleField == doubleField &&
           compType.intWrapperField == intWrapperField &&
           compType.floatWrapperField == floatWrapperField &&
           compType.longWrapperField == longWrapperField &&
           compType.shortWrapperField == shortWrapperField &&
           compType.byteWrapperField == byteWrapperField &&
           compType.doubleWrapperField == doubleWrapperField &&
           compType.stringField == stringField &&
           compType.stringBufferField == stringBufferField &&
           ObjectComparator.equals( compType.intArrayField, intArrayField ) &&
           ObjectComparator.equals( compType.shortArrayField, shortArrayField ) &&
           ObjectComparator.equals( compType.longArrayField, longArrayField ) &&
           ObjectComparator.equals( compType.byteArrayField, byteArrayField ) &&
           ObjectComparator.equals( compType.doubleArrayField, doubleArrayField ) &&
           ObjectComparator.equals( compType.floatArrayField, floatArrayField ) &&
           ObjectComparator.equals( compType.intWrapperArrayField, intWrapperArrayField ) &&
              ObjectComparator.equals( compType.shortWrapperArrayField, shortWrapperArrayField ) &&
              ObjectComparator.equals( compType.longWrapperArrayField, longWrapperArrayField ) &&
              ObjectComparator.equals( compType.byteWrapperArrayField, byteWrapperArrayField ) &&
              ObjectComparator.equals( compType.doubleWrapperArrayField, doubleWrapperArrayField ) &&

              ObjectComparator.equals( compType.collectionField, collectionField ) &&
              ObjectComparator.equals( compType.abstractCollectionField, abstractCollectionField ) &&
              ObjectComparator.equals( compType.listCollectionField, listCollectionField ) &&
              ObjectComparator.equals( compType.abstractListField, abstractListField ) &&
              compType.stackField.length == stackField.length &&
              ObjectComparator.equals( compType.vectorField, vectorField ) &&
              ObjectComparator.equals( compType.linkedLIstField, linkedLIstField ) &&
              ObjectComparator.equals( compType.arrayListField, arrayListField )  &&
              compType.setField.length == setField.length  &&
           compType.sortedSetField.length == sortedSetField.length &&
           compType.treeSetField.length == treeSetField.length &&                   
              ObjectComparator.equals( compType.mapSetField, mapSetField ) &&
              ObjectComparator.equals( compType.propertiesField, propertiesField ) &&
              ObjectComparator.equals( compType.treeMapField, treeMapField ))
        return true;
    else
        return false;
    }
    
    private static function getComplexType( i:int ):*
    {
        if( Cache.complexTypes[ i ] == undefined )
            Cache.complexTypes[ i ] = new ComplexType( i );

        return Cache.complexTypes[ i ];          
    }
    
    public static function getArray( size:int ):Array
    {
        var array:Array = new Array();
        
        for( var i:int = 0; i < size; i++ )
          array.push( i );
          
        return array;
    }
    
    public static function getComplexArray( size:int ):Array
    {
        if( Cache.complexArrays[ size ] != undefined )
          return Cache.complexArrays[ size ];
          
        var complexArray:Array = new Array();
        
        for( var i:int = 0; i < size; i++ )
        {
            if( i % 2 == 0 )
              complexArray.push( i + " string object" );
            else if( i % 3 == 0 )
              complexArray.push( getMap( i ) );
            else if( i % 5 == 0 )
              complexArray.push( getArray( i ) );
            else
              complexArray.push( getComplexType( i ) );    
        }
        
        Cache.complexArrays[ size ] = complexArray;
        return complexArray;
    }
    
    public static function getMap( size:int ):Object
    {
        if( Cache.maps[ size ] != undefined )
          return Cache.maps[ size ];
        
        var map:Object = new Object();
        
        for( var i:int = 0; i < size ; i++ )
        {
          
            if( i % 2 == 0 )
                map[ i + "item" ] = i + " string object";    
            else if( i % 3 == 0 )
                map[ i + "item" ] = getMap( i );    
            else if( i % 5 == 0 )
                map[ i + "item" ] = getArray( i );            
            else
              map[ i + "item" ] = getComplexType( i );
          
        }
        Cache.maps[ size ] = map;
        return map;
    }
    
    private static function getArrayOfObject( depth : Number, object:Object ):Array
    {
        var array:Array = new Array();
        
        for( var i:int = 0; i < depth; i++ )
        {
            array.push( object );
        }
        
        return array;
    }
    
    private static function get2DimArrayOfObject( depth : Number, object:Object ):Array
    {
        var array:Array = [depth];
        
        for( var i:int = 0; i < depth; i++ )
        {
            array[ i ] = [];
            
          for( var j:int = 0; j < depth; j++ )
          {
            array[ i ][ j ] = object;
          }
        }
            
        return array;
    }    
    
    private static function get3DimArrayOfObject( depth : Number, object:Object ):Array
    {
        var array:Array = [depth];
        
        for( var i:int = 0; i < depth; i++ )
        {
            array[ i ] = [];
            
          for( var j:int = 0; j < depth; j++ )
          {
              array[ i ][ j ] = [];
              
              for( var q:int = 0; q < depth; q++ )          
                   array[ i ][ j ][ q ] = object;
          }
        }
            
        return array;
    }
    }
}