package SPVM::Math::StringToNumber {
  has val : private ro string;

  sub _validate : void ($val : string) {
    my $length = length $val;
    unless ($length > 0) {
      die "value is empty";
    }
    if ($val->[0] == '.') {
      die "decimal cannot start with '.'";
    }
    # TODO: 1e008 などのためにコメントアウトする。あとでちゃんとJSONみたいなインターフェースにして直すのが良いと思う
    #if ($length > 2 && $val->[0] == '0' && $val->[1] != '.') {
    #  die "'.' must exist just after the first digit '0'. val: '$val'"; # TODO: Proper english
    #}
    if ($val->[$length - 1] == '.') {
      die "'.' cannot exist at the end of digits. val: '$val'";
    }
    my $found_dot = 0;
    for (my $i = 0; $i < $length; ++$i) {
      unless (('0' <= $val->[$i] && $val->[$i] <= '9') || $val->[$i] == '.' || $val->[$i] == '-') {
        die "decimal cannot contain not digit, '.' or '-' character. val: '$val'";
      }
      if ($val->[$i] == '.') {
        if ($found_dot) {
          die "decimal cannot contain multiple '.'";
        }
        $found_dot = 1;
      }
    }
  }

  sub from : SPVM::Math::StringToNumber ($val : string) {
    my $self = new SPVM::Math::StringToNumber;
    _validate($val);
    $self->{val} = $val;
    return $self;
  }

  sub to_int : int ($self : self) {
    # TODO: check value type (int, double, ...)
    my $ret : int = 0;
    my $begin = 0;
    my $sign = 1;
    if ($self->{val}->[0] == '-') {
      $sign = -1;
      ++$begin;
    }
    for (my $i = $begin; $i < length($self->{val}); ++$i) {
      $ret *= 10;
      $ret += $self->{val}->[$i] - '0';
    }
    return $ret * $sign;
  }

  sub to_long : long ($self : self) {
    # TODO: check value type (int, double, ...)
    my $ret : long = 0;
    my $begin = 0;
    my $sign = 1;
    if ($self->{val}->[0] == '-') {
      $sign = -1;
      ++$begin;
    }
    for (my $i = $begin; $i < length($self->{val}); ++$i) {
      $ret *= 10L;
      $ret += $self->{val}->[$i] - '0';
    }
    return $ret * $sign;
  }
}
