package Sidef::Types::Array::Pair;

use utf8;
use 5.016;

use parent qw(
  Sidef::Types::Array::Array
);

use overload q{""} => \&_dump;

sub new {
    my (undef, $item1, $item2) = @_;
    bless [$item1, $item2], __PACKAGE__;
}

*call = \&new;

sub get_value {
    my %addr;

    my $sub = sub {
        my ($obj) = @_;

        my $refaddr = Scalar::Util::refaddr($obj);

        exists($addr{$refaddr})
          && return $addr{$refaddr};

        my @array;
        $addr{$refaddr} = \@array;

        foreach my $i (0, 1) {
            my $item = $obj->[$i];

            if (index(ref($item), 'Sidef::') == 0) {
                push @array, $item->get_value;
            }
            else {
                push @array, $item;
            }
        }

        $addr{$refaddr};
    };

    no warnings 'redefine';
    local *Sidef::Types::Array::Pair::get_value = $sub;
    $sub->($_[0]);
}

sub first : lvalue {
    $_[0][0];
}

*key = \&first;

sub second : lvalue {
    $_[0][1];
}

*value = \&second;

sub swap {
    my ($self) = @_;
    ($self->[0], $self->[1]) = ($self->[1], $self->[0]);
    $self;
}

sub to_hash {
    my ($self) = @_;
    Sidef::Types::Hash::Hash->new(@$self);
}

*to_h = \&to_hash;

sub to_array {
    my ($self) = @_;
    Sidef::Types::Array::Array->new(ref($self) ? [@$self] : $self);
}

*to_a = \&to_array;

sub _dump {

    my %addr;    # keeps track of dumped objects

    my $sub = sub {
        my ($obj) = @_;

        my $refaddr = Scalar::Util::refaddr($obj);

        exists($addr{$refaddr})
          and return $addr{$refaddr};

        $addr{$refaddr} = "Pair(#`($refaddr)...)";

        my $s;

        'Pair(' . join(', ', map { (ref($_) && ($s = UNIVERSAL::can($_, 'dump'))) ? $s->($_) : ($_ // 'nil') } @$obj) . ')';
    };

    no warnings 'redefine';
    local *Sidef::Types::Array::Pair::dump = $sub;
    $sub->($_[0]);
}

sub dump {
    Sidef::Types::String::String->new($_[0]->_dump);
}

*to_s   = \&dump;
*to_str = \&dump;

1
