class TestCase::Operator::New::Array {
  use TestCase::Minimal;
  use Fn;
  use Array;
  use Point;
  
  our $BIG_INDEX : int;
  INIT {
    $BIG_INDEX = 200_000_000;
  }

  static method array_store_undef : int () {
    my $minimals = new TestCase::Minimal[3];
    $minimals->[0] = TestCase::Minimal->new;
    $minimals->[0] = undef;
    
    if ($minimals->[0] == undef) {
      return 1;
    }
    return 0;
  }
  
  static method array_set_and_get_array_element_first : int () {
    
    my $nums = new int[3];
    $nums->[0] = 345;
    
    return $nums->[0];
  }
  
  static method array_set_and_get_array_element_last : int () {
    
    my $nums = new int[3];
    $nums->[2] = 298;
    
    return $nums->[2];
  }
  
  static method array_culcurate_sum_by_for : int () {
    
    my $nums = new int[3];
    $nums->[0] = 1;
    $nums->[1] = 2;
    $nums->[2] = 3;
    
    my $total = 0;
    for (my $i = 0; $i < @$nums; $i++) {
      $total = $total + $nums->[$i];
    }
    
    return $total;
  }
  
  static method array_default_zero_not_memory_pool : int () {
    my $values_byte = new byte[1000000];
    my $values_short = new short[1000000];
    my $values_int = new int[1000000];
    my $values_long = new long[1000000];
    my $values_float = new float[1000000];
    my $values_double = new double[1000000];
    my $values_object = new TestCase::Minimal[1000000];
    unless ($values_byte->[0] == 0) {
      return 0;
    }
    unless ($values_byte->[999999] == 0) {
      return 0;
    }
    unless ($values_short->[0] == 0) {
      return 0;
    }
    unless ($values_short->[999999] == 0) {
      return 0;
    }
    unless ($values_int->[0] == 0) {
      return 0;
    }
    unless ($values_int->[999999] == 0) {
      return 0;
    }
    unless ($values_long->[0] == 0L) {
      return 0;
    }
    unless ($values_long->[999999] == 0L) {
      return 0;
    }
    unless ($values_float->[0] == 0f) {
      return 0;
    }
    unless ($values_float->[999999] == 0f) {
      return 0;
    }
    unless ($values_double->[0] == 0.0) {
      return 0;
    }
    unless ($values_double->[999999] == 0.0) {
      return 0;
    }
    
    return 1;
  }
  static method array_default_zero_memory_pool : int () {
    my $values_byte = new byte[10];
    my $values_short = new short[10];
    my $values_int = new int[10];
    my $values_long = new long[10];
    my $values_float = new float[10];
    my $values_double = new double[10];
    my $values_object = new TestCase::Minimal[10];
    unless ($values_byte->[0] == 0) {
      return 0;
    }
    unless ($values_byte->[9] == 0) {
      return 0;
    }
    unless ($values_short->[0] == 0) {
      return 0;
    }
    unless ($values_short->[9] == 0) {
      return 0;
    }
    unless ($values_int->[0] == 0) {
      return 0;
    }
    unless ($values_int->[9] == 0) {
      return 0;
    }
    unless ($values_long->[0] == 0L) {
      return 0;
    }
    unless ($values_long->[9] == 0L) {
      return 0;
    }
    unless ($values_float->[0] == 0f) {
      return 0;
    }
    unless ($values_float->[9] == 0f) {
      return 0;
    }
    unless ($values_double->[0] == 0.0) {
      return 0;
    }
    unless ($values_double->[9] == 0.0) {
      return 0;
    }
    
    return 1;
  }


  static method array_max_index_byte : int () {
    my $nums = new byte[Fn->INT32_MAX()];
    
    $nums->[0] = 1;
    $nums->[Fn->INT32_MAX() - 1] = 2;
    
    unless ($nums->[0] == 1) {
      return 0;
    }
    
    unless ($nums->[Fn->INT32_MAX() - 1] == 2) {
      return 0;
    }
    
    eval {
      $nums->[Fn->INT32_MAX()];
    };
    unless ($@) {
      return 0;
    }
    
    # Additional use memory
    my $nums1 = new byte[Fn->INT32_MAX()];
    my $nums2 = new byte[Fn->INT32_MAX()];
    my $nums3 = new byte[Fn->INT32_MAX()];
    
    return 1;
  }

  static method array_big_index_byte : int () {
    my $index = $BIG_INDEX;
    my $nums = new byte[$index];
    
    $nums->[0] = 1;
    $nums->[$index - 1] = 2;
    
    unless ($nums->[0] == 1) {
      return 0;
    }
    
    unless ($nums->[$index - 1] == 2) {
      return 0;
    }
    
    eval {
      $nums->[$index];
    };
    unless ($@) {
      return 0;
    }
    
    return 1;
  }

  static method array_big_index_short : int () {
    my $index = $BIG_INDEX;
    my $nums = new short[$index];
    
    $nums->[0] = 1;
    $nums->[$index - 1] = 2;
    
    unless ($nums->[0] == 1) {
      return 0;
    }
    
    unless ($nums->[$index - 1] == 2) {
      return 0;
    }
    
    eval {
      $nums->[$index];
    };
    unless ($@) {
      return 0;
    }
    
    return 1;
  }

  static method array_big_index_int : int () {
    my $index = $BIG_INDEX;
    my $nums = new int[$index];
    
    $nums->[0] = 1;
    $nums->[$index - 1] = 2;
    
    unless ($nums->[0] == 1) {
      return 0;
    }
    
    unless ($nums->[$index - 1] == 2) {
      return 0;
    }
    
    eval {
      $nums->[$index];
    };
    unless ($@) {
      return 0;
    }
    
    return 1;
  }

  static method array_big_index_long : int () {
    my $index = $BIG_INDEX;
    my $nums = new long[$index];
    
    $nums->[0] = 1;
    $nums->[$index - 1] = 2;
    
    unless ($nums->[0] == 1) {
      return 0;
    }
    
    unless ($nums->[$index - 1] == 2) {
      return 0;
    }
    
    eval {
      $nums->[$index];
    };
    unless ($@) {
      return 0;
    }
    
    return 1;
  }

  static method array_big_index_float : int () {
    my $index = $BIG_INDEX;
    my $nums = new float[$index];
    
    $nums->[0] = 1;
    $nums->[$index - 1] = 2;
    
    unless ($nums->[0] == 1) {
      return 0;
    }
    
    unless ($nums->[$index - 1] == 2) {
      return 0;
    }
    
    eval {
      $nums->[$index];
    };
    unless ($@) {
      return 0;
    }
    
    return 1;
  }

  static method array_big_index_double : int () {
    my $index = $BIG_INDEX;
    my $nums = new double[$index];
    
    $nums->[0] = 1;
    $nums->[$index - 1] = 2;
    
    unless ($nums->[0] == 1) {
      return 0;
    }
    
    unless ($nums->[$index - 1] == 2) {
      return 0;
    }
    
    eval {
      $nums->[$index];
    };
    unless ($@) {
      return 0;
    }
    
    return 1;
  }

  static method any_object_array : int () {
    
    # object[] - assign numeric object
    {
      # object[] can be assigned Int[] object
      my $obj_nums : object[] = [Int->new(1), Int->new(2), Int->new(3)];
      
      # Can get element
      my $obj_num0 = (Int)$obj_nums->[0];
      my $obj_num1 = (Int)$obj_nums->[1];
      my $obj_num2 = (Int)$obj_nums->[2];
      unless ((int)$obj_num0 == 1) {
        return 0;
      }
      unless ((int)$obj_num1 == 2) {
        return 0;
      }
      unless ((int)$obj_num2 == 3) {
        return 0;
      }
      
      # Array invalid range access
      eval {
        $obj_nums->[3];
      };
      unless ($@) {
        return 0;
      }
      
      # isa return real type
      unless ($obj_nums isa Int[]) {
        return 0;
      }
      
      # Int type can be assigned
      $obj_nums->[2] = Int->new(4);
      
      # If other type is assinged, runtime exception occur
      eval {
        $obj_nums->[0] = Long->new(2);
      };
      unless ($@) {
        return 0;
      }
      
      # Cast to Int[];
      my $obj_ints = (Int[])$obj_nums;
      unless ($obj_ints isa Int[]) {
        return 0;
      }
      
      # Cast to Invalid array type, runtime exception occur
      eval {
        (Long[])$obj_nums;
      };
      unless ($@) {
        return 0;
      }
      
      # Can assign undef
      {
        my $obj_elems : object[] = undef;
        unless ($obj_elems == undef) {
          return 0;
        }
      }
    }
    
    # Multi-Dimensional Array
    {
      my $objects : object[] = new Point[][3];
      $objects->(Point[][])->[0] = new Point[3];
      my $point : Point = $objects->(Point[][])->[0][0];
    }
    
    $@ = undef;
    return 1;
  }
  
  static method extra : int () {
    {
      my $nums : int[][] = new int[][3];
    }
    
    my $nums = new int[(byte)3];
    $nums->[2] = 4;
    if ($nums->[(byte)2] == 4) {
      return 1;
    }
  }
  
}
