class TestCase {
  use TestCase::Minimal;
  use TestCase::Simple;
  use Fn;
  use Array;

  our $CLASS_VAR_INT : int;
  our $CLASS_VAR_LONG : long;
  our $CLASS_VAR_MINIMAL : TestCase::Minimal;

  our $CLASS_VAR_INT2 : int;
  our $CLASS_VAR_LONG2 : long;
  our $CLASS_VAR_MINIMAL2 : TestCase::Minimal;

  has x_byte : rw public byte;
  has x_short : rw public short;
  has x_int : rw public int;
  has x_long : rw public long;
  has x_float : rw public float;
  has x_double : rw public double;
  has x_int_array : rw public int[];
  has x_byte_array : rw public byte[];
  has x_test_case : rw public TestCase;
  has minimal : rw public TestCase::Minimal;
  has private_field : private int;
  
  static method main : int ($current_file : string, $args : string[]) {
    warn("GGGGGGG $current_file $args->[0] $args->[1]");
  }
  
  static method INT : int () { return 127; }
  static method FLOAT_PRECICE : float () { return 16384.5f; }
  static method DOUBLE_PRECICE : double () { return 65536.5; }

  static method myapp_test : int ($num : int) {
    return $num * 2;
  }
  
  method get_private_field : int () {
    return $self->{private_field};
  }
  
  method get_x_byte : byte () {
    return $self->{x_byte};
  }

  method get_x_short : short () {
    return $self->{x_short};
  }

  method get_x_int : int () {
    return $self->{x_int};
  }

  method get_x_long : long () {
    return $self->{x_long};
  }

  method get_x_float : float () {
    return $self->{x_float};
  }

  method get_x_double : double () {
    return $self->{x_double};
  }
  
  # Only compile check
  static method eval_block_stack_check : void () {
    eval {
      my $obj_error1 = "Error1";
      
      die $obj_error1;
    };
    
    {
      my $obj_error2 = "Error2";
      
      die $obj_error2;
    }
  }
  
  static method new : TestCase () {
    return new TestCase;
  }
  
  static method my_var_in_loop_free : int () {
    for (my $i = 0; $i < 5; $i++) {
      my $minimal = TestCase::Minimal->new;
    }
  }
  
  static method class_var : int () {
    if ($TestCase::CLASS_VAR_INT == 0) {
      $TestCase::CLASS_VAR_INT = Fn->INT32_MAX();
      if ($TestCase::CLASS_VAR_INT == Fn->INT32_MAX()) {
        $TestCase::CLASS_VAR_LONG = Fn->INT64_MAX();
        if ($TestCase::CLASS_VAR_LONG == Fn->INT64_MAX()) {
          $TestCase::CLASS_VAR_MINIMAL = TestCase::Minimal->new();
          
          $TestCase::CLASS_VAR_MINIMAL->set_x(4);
          
          $TestCase::CLASS_VAR_MINIMAL->set_x(4);
          if ($TestCase::CLASS_VAR_MINIMAL->x) {
            $TestCase::CLASS_VAR_MINIMAL = undef;
            return 1;
          }
        }
      }
    }
    return 0;
  }

  static method class_var_rel_name : int () {
    $CLASS_VAR_INT = 2;
    
    if ($CLASS_VAR_INT == 2) {
      if ($TestCase::CLASS_VAR_INT == 2) {
        $CLASS_VAR_INT = 0;
        return 1;
      }
    }
    
    return 0;
  }

  static method class_var_other_class : int () {
    if ($TestCase::Simple::FOO == 0) {
      $TestCase::Simple::FOO = 1;
      if ($TestCase::Simple::FOO == 1) {
        return 1;
      }
    }
    return 0;
  }
  
  method get_minimal : TestCase::Minimal () {
    return $self->{minimal};
  }

  # Resorved word
  static method int : int ($obj : TestCase) {
    
    return 5;
  }
  
  static method use_reserved_word : int () {
    
    my $test_case = new TestCase;
    
    if (TestCase->int($test_case) == 5) {
      if (TestCase->int($test_case) == 5) {
        return 1;
      }
    }
    
    return 0;
  }
  
  static method concat : string () {
    "a" . "b";
    
    my $value = "a" . "b";
    
    return $value;
  }
  
  # string
  static method string_utf8 : string () {
    my $value = "あいうえお";
    
    return $value;
  }
  static method string_empty : string () {
    my $value = "";
    
    return $value;
  }

  static method my_var_scope : int () {
    my $ok1 = 0;
    my $ok2 = 0;
    my $ok3 = 0;
    
    my $var1 = 1;
    my $var2 = 2;
    
    if ($var1 == 1) {
      if ($var2 == 2) {
        $ok1 = 1;
      }
    }
    
    {
      my $var1 = 3;
      my $var2 = 4;
      my $var3 = 5;
      
      if ($var1 == 3) {
        if ($var2 == 4) {
          if ($var3 == 5) {
            $ok2 = 1;
          }
        }
      }
    }
    
    my $var3 = 6;
    
    if ($var1 == 1) {
      if ($var2 == 2) {
        if ($var3 == 6) {
          $ok3 = 1;
        }
      }
    }
    
    if ($ok1) {
      if ($ok2) {
        if ($ok3) {
          return 1;
        }
      }
    }
    
    return 0;
  }
  
  # My variable is initialized zero
  static method my_var_initialized_zero : int () {
    my $var1 : int;
    my $var2 : TestCase;
    
    if ($var1 == 0) {
      if ($var2 == undef) {
        return 1;
      }
    }
    return 0;
  }

  static method my_var_block : int () {
    my $success = 1;
    
    my $var1 = 1;
    if ($var1 != 1) {
      $success = 0;
    }
    
    {
      my $var1 = 2;
      if ($var1 != 2) {
        $success = 0;
      }
      
      {
        my $var1 = $var1;
        if ($var1 != 2) {
          $success = 0;
        }
        $var1 = 3;
      }
      if ($var1 != 2) {
        $success = 0;
      }
    }
    
    if ($success) {
      return 1;
    }
    return 0;
  }
  
  # new near small base_object_max_size_use_memory_pool
  static method new_near_small_base_object_max_size_use_memory_pool : int () {
    my $block = new byte[0xFFF0];
    
    return 1;
  }

  # Sum
  static method sum_byte : byte ($a : byte, $b :byte) {
    
    my $total = (byte)((int)$a + (int)$b);
    
    return $total;
  }

  static method sum_short : short ($a : short, $b :short) {
    
    my $total = (short)((int)$a + (int)$b);
    
    return $total;
  }

  static method sum_int : int ($a : int, $b :int) {
    
    my $total = $a + $b;
    
    return $total;
  }

  static method sum_long : long ($a : long, $b :long) {
    
    my $total = $a + $b;
    
    return $total;
  }

  static method sum_float : float ($a : float, $b :float) {
    
    my $total = $a + $b;
    
    return $total;
  }

  static method sum_double : double ($a : double, $b :double) {
    
    my $total = $a + $b;
    
    return $total;
  }
  
}
