class TestCase::Util::Node : public {
  
  use Cloner;
  use Array;
  
  # Fields
  has parent_node : public TestCase::Util::Node;
  
  has next_sibling : public TestCase::Util::Node;
  
  has previous_sibling : public TestCase::Util::Node;
  
  has first_child : public TestCase::Util::Node;
  
  has last_child : public TestCase::Util::Node;
  
  # Private Class Methods
  private static method copy_object_with_proto : object[] ($array : object[], $proto : object[], $cloner : Cloner = undef, $offset : int = 0, $length : int = -1) {
    
    unless ($array) {
      die "The array \$array must be defined.";
    }
    
    unless ($offset >= 0) {
      die "The offset \$offset must be greater than or equal to 0.";
    }
    
    my $array_length = @$array;
    if ($length < 0) {
      $length = $array_length - $offset;
    }
    
    unless ($offset + $length <= $array_length) {
      die "\$offset + \$length must be less than or equal to the length of \$array.";
    }
    
    unless ($proto) {
      $proto = $array;
    }
    
    my $new_array = Array->new_proto($proto, $length);
    
    if ($cloner) {
      for (my $i = 0; $i < $length; $i++) {
        $new_array->[$i] = $cloner->($array->[$offset + $i]);
      }
    }
    else {
      Array->memcpy_object_address($new_array, 0, $array, $offset, $length);
    }
    
    return $new_array;
  }
  
  private static method copy_object_address_with_proto : object[] ($array : object[], $proto : object[], $offset : int = 0, $length : int = -1) {
    return &copy_object_with_proto($array, $proto, undef, $offset, $length);
  }
  
  static method new : TestCase::Util::Node ($child_nodes : TestCase::Util::Node[] = undef) {
    
    my $self = new TestCase::Util::Node;
    
    $self->init($child_nodes);
    
    return $self;
  }
  
  protected method init : void ($child_nodes : TestCase::Util::Node[] = undef) {
    
    if ($child_nodes) {
      unless ($child_nodes is_type TestCase::Util::Node[]) {
        $child_nodes = (TestCase::Util::Node[])&copy_object_address_with_proto($child_nodes, new TestCase::Util::Node[0]);
      }
    }
    else {
      $child_nodes = new TestCase::Util::Node[0];
    }
    
    # Tree
    if ($child_nodes) {
      
      my $child_nodes_length = @$child_nodes;
      
      if ($child_nodes_length > 0) {
        
        $self->{first_child} = $child_nodes->[0];
        
        $self->{last_child} = $child_nodes->[$child_nodes_length - 1];
        
        for (my $i = 0; $i < $child_nodes_length; $i++) {
          my $child_node = $child_nodes->[$i];
          
          if ($i + 1 < $child_nodes_length) {
            my $next_sibling_node = $child_nodes->[$i + 1];
            $child_node->{next_sibling} = $next_sibling_node;
          }
          
          if ($i - 1 >= 0) {
            my $previous_sibling_node = $child_nodes->[$i - 1];
            $child_node->{previous_sibling} = $previous_sibling_node;
            weaken $child_node->{previous_sibling};
          }
          
          $child_node->{parent_node} = $self;
          weaken $child_node->{parent_node};
        }
      }
    }
  }
}
