package Whatpm::CSS::MediaQueryParser;
use strict;
our $VERSION=do{my @r=(q$Revision: 1.2 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};

use Whatpm::CSS::Tokenizer qw(:token);

sub new ($) {
  my $self = bless {
    onerror => sub { },
    level => {
      must => 'm',
      uncertain => 'u',
    },
  }, shift;
  #$self->{href} = \(uri in which the MQ appears);
  return $self;
} # new

sub parse_char_string ($$) {
  my $self = $_[0];

  my $s = $_[1];
  pos ($s) = 0;

  my $tt = Whatpm::CSS::Tokenizer->new;
  $tt->{onerror} = $self->{onerror};
  $tt->{line} = 1;
  $tt->{column} = 1;
  $tt->{get_char} = sub {
    if (pos $s < length $s) {
      $tt->{column} = 1 + pos $s;
      return ord substr $s, pos ($s)++, 1;
    } else {
      return -1;
    }
  }; # $tt->{get_char}
  $tt->init;

  my $t = $tt->get_next_token;
  $t = $tt->get_next_token while $t->{type} == S_TOKEN;

  my $r;
  ($t, $r) = $self->_parse_mq_with_tokenizer ($t, $tt);
  return undef unless defined $r;

  if ($t->{type} != EOF_TOKEN) {
    $self->{onerror}->(type => 'mq syntax error',
                       level => $self->{level}->{must},
                       uri => \$self->{href},
                       token => $t);
    return undef;
  }

  return $r;
} # parse_char_string

sub _parse_mq_with_tokenizer ($$$) {
  my ($self, $t, $tt) = @_;

  my $r = [];

  A: {
    ## NOTE: Unknown media types are converted into 'unknown', since
    ## Opera and WinIE do so and our implementation of the CSS
    ## tokenizer currently normalizes numbers in NUMBER or DIMENSION tokens
    ## so that the original representation cannot be preserved (e.g. '03d'
    ## is covnerted to '3' with unit 'd').

    if ($t->{type} == IDENT_TOKEN) {
      my $type = lc $t->{value}; ## TODO: case
      if ({
        all => 1, braille => 1, embossed => 1, handheld => 1, print => 1,
        projection => 1, screen => 1, tty => 1, tv => 1,
        speech => 1, aural => 1,
        'atsc-tv' => 1, 'dde-tv' => 1, 'dvb-tv' => 1,
        dark => 1, emacs => 1, light => 1, xemacs => 1,
      }->{$type}) {
        push @$r, [['#type', $type]];
      } else {
        push @$r, [['#type', 'unknown']];
        $self->{onerror}->(type => 'unknown media type',
                           level => $self->{level}->{uncertain},
                           uri => \$self->{href},
                           token => $t);
      }
      $t = $tt->get_next_token;
    } elsif ($t->{type} == NUMBER_TOKEN or $t->{type} == DIMENSION_TOKEN) {
      push @$r, [['#type', 'unknown']];
      $self->{onerror}->(type => 'unknown media type',
                         level => $self->{level}->{uncertain},
                         uri => \$self->{href},
                         token => $t);
      $t = $tt->get_next_token;
    } else {
      $self->{onerror}->(type => 'mq syntax error',
                         level => $self->{level}->{must},
                         uri => \$self->{href},
                         token => $t);    
      return ($t, undef);
    }

    $t = $tt->get_next_token while $t->{type} == S_TOKEN;
    if ($t->{type} == COMMA_TOKEN) {
      $t = $tt->get_next_token;
      $t = $tt->get_next_token while $t->{type} == S_TOKEN;
      redo A;
    }
  } # A

  return ($t, $r);
} # _parse_mq_with_tokenizer

1;
