/// This library contains token types used by the html5 tokenizer.
library token;

import 'dart:collection';
import 'package:source_span/source_span.dart';

/// An html5 token.
abstract class Token {
  FileSpan span;

  int get kind;
}

abstract class TagToken extends Token {
  String name;

  bool selfClosing;

  TagToken(this.name, this.selfClosing);
}

class StartTagToken extends TagToken {
  /// The tag's attributes. A map from the name to the value, where the name
  /// can be a [String] or [AttributeName].
  LinkedHashMap<dynamic, String> data;

  /// The attribute spans if requested. Otherwise null.
  List<TagAttribute> attributeSpans;

  bool selfClosingAcknowledged;

  /// The namespace. This is filled in later during tree building.
  String namespace;

  StartTagToken(String name, {this.data, bool selfClosing: false,
      this.selfClosingAcknowledged: false, this.namespace})
      : super(name, selfClosing);

  int get kind => TokenKind.startTag;
}

class EndTagToken extends TagToken {
  EndTagToken(String name, {bool selfClosing: false})
      : super(name, selfClosing);

  int get kind => TokenKind.endTag;
}

abstract class StringToken extends Token {
  StringBuffer _buffer;

  String _string;
  String get data {
    if (_string == null) {
      _string = _buffer.toString();
      _buffer = null;
    }
    return _string;
  }

  StringToken(string)
      : _string = string,
        _buffer = string == null ? new StringBuffer() : null;

  StringToken add(String data) {
    _buffer.write(data);
    return this;
  }
}

class ParseErrorToken extends StringToken {
  /// Extra information that goes along with the error message.
  Map messageParams;

  ParseErrorToken(String data, {this.messageParams}) : super(data);

  int get kind => TokenKind.parseError;
}

class CharactersToken extends StringToken {
  CharactersToken([String data]) : super(data);

  int get kind => TokenKind.characters;

  /// Replaces the token's [data]. This should only be used to wholly replace
  /// data, not to append data.
  void replaceData(String newData) {
    _string = newData;
    _buffer = null;
  }
}

class SpaceCharactersToken extends StringToken {
  SpaceCharactersToken([String data]) : super(data);

  int get kind => TokenKind.spaceCharacters;
}

class CommentToken extends StringToken {
  CommentToken([String data]) : super(data);

  int get kind => TokenKind.comment;
}

class DoctypeToken extends Token {
  String publicId;
  String systemId;
  String name = "";
  bool correct;

  DoctypeToken({this.publicId, this.systemId, this.correct: false});

  int get kind => TokenKind.doctype;
}

/// These are used by the tokenizer to build up the attribute map.
/// They're also used by [StartTagToken.attributeSpans] if attribute spans are
/// requested.
class TagAttribute {
  String name;
  String value;

  // The spans of the attribute. This is not used unless we are computing an
  // attribute span on demand.
  int start;
  int end;
  int startValue;
  int endValue;

  TagAttribute();
}

class TokenKind {
  static const int spaceCharacters = 0;
  static const int characters = 1;
  static const int startTag = 2;
  static const int endTag = 3;
  static const int comment = 4;
  static const int doctype = 5;
  static const int parseError = 6;
}
