package CType::Array;

use 5.6.0;
use strict;
use warnings;

use CType;

our @ISA = qw/CType/;

sub new
  {
    my $this = shift;
    my $class = ref($this) || $this;
    my $type = shift;
    my $size = shift;
    my $attributes = shift;

    my $self = {type => $type,
                size => $size,
                attributes => $attributes,
               };
    bless $self, $class;

    $self->process_attributes($attributes);

    return $self;
  }

sub size
  {
    my $self = shift;
    return $self->{size};
  }

sub element_type
  {
    my $self = shift;
    return $self->{type}->type;
  }

sub layout
  {
    my $self = shift;
    my $accept_incomplete = shift;
    my $namespace = shift;

    return if exists $self->{width};

    if ($self->{size})
      {
        $self->{size}->layout(0, $namespace);
        $self->element_type->layout($accept_incomplete, $namespace);
        $self->{width} = $self->element_type->width * $self->{size}->compute;
      }
    else
      {
        $self->{width} = undef;
      }
  }

sub alignment
  {
    my $self = shift;
    return $self->element_type->alignment;
  }

sub alignment_exprs
  {
    my $self = shift;
    return $self->element_type->alignment_exprs;
  }

sub describe
  {
    my $self = shift;

    my $size = $self->{size} ? $self->{size}->compute . " element " : "";
    my $type = $self->{type}->describe;

    return $size . "array of $type";
  }

sub capture_declarator
  {
    return 1;
  }

sub dump_c
  {
    my $self = shift;
    my $skip_cpp = shift;
    my $name = shift;

    my $str = '';

    my $declarator = $name || "";
    my $size = $self->{size} ? $self->{size}->dump_c($skip_cpp) : '';

    if ($self->{type}->capture_declarator)
      {
        $str .= $self->{type}->dump_c($skip_cpp, "$declarator\[$size]");
      }
    else
      {
        my $type = $self->{type}->dump_c($skip_cpp);
        $str .= "$type $declarator\[$size]";
      }

    return $str;
  }

sub _check_interface
  {
    my $self = shift;
    my $other = shift;

    return 'both' unless $other->isa('CType::Array');

    my @ret;

    my $size = $self->{size} ? $self->{size}->compute : "x";
    my $other_size = $other->{size} ? $other->{size}->compute : "x";

    if ($size ne $other_size)
      {
        push @ret, 'abi';
      }
    push @ret, $self->{type}->check_interface($other->{type});

    return @ret;
  }

sub get_refs
  {
    my $self = shift;
    return ($self->{type}->get_refs, $self->{size} ? $self->{size}->get_refs : ());
  }

1;
