'use strict';

exports.assign = function (tokenizer) {

//NOTE: obtain Tokenizer proto this way to avoid module circular references
var tokenizerProto = Object.getPrototypeOf(tokenizer);
tokenizer.tokenStartLoc = -1;
//NOTE: add location info builder method
tokenizer._attachLocationInfo = function (token) {
    token.location = {
        start: this.tokenStartLoc,
        end: -1
    };
};
//NOTE: patch token creation methods and attach location objects
tokenizer._createStartTagToken = function (tagNameFirstCh) {
    tokenizerProto._createStartTagToken.call(this, tagNameFirstCh);
    this._attachLocationInfo(this.currentToken);
};
tokenizer._createEndTagToken = function (tagNameFirstCh) {
    tokenizerProto._createEndTagToken.call(this, tagNameFirstCh);
    this._attachLocationInfo(this.currentToken);
};
tokenizer._createCommentToken = function () {
    tokenizerProto._createCommentToken.call(this);
    this._attachLocationInfo(this.currentToken);
};
tokenizer._createDoctypeToken = function (doctypeNameFirstCh) {
    tokenizerProto._createDoctypeToken.call(this, doctypeNameFirstCh);
    this._attachLocationInfo(this.currentToken);
};
tokenizer._createCharacterToken = function (type, ch) {
    tokenizerProto._createCharacterToken.call(this, type, ch);
    this._attachLocationInfo(this.currentCharacterToken);
};
//NOTE: patch token emission methods to determine end location
tokenizer._emitCurrentToken = function () {
    //NOTE: if we have pending character token make it's end location equal to the
    //current token's start location.
    if (this.currentCharacterToken)
        this.currentCharacterToken.location.end = this.currentToken.location.start;
    this.currentToken.location.end = this.preprocessor.pos + 1;
    tokenizerProto._emitCurrentToken.call(this);
};
tokenizer._emitCurrentCharacterToken = function () {
    //NOTE: if we have character token and it's location wasn't set in the _emitCurrentToken(),
    //then set it's location at the current preprocessor position
    if (this.currentCharacterToken && this.currentCharacterToken.location.end === -1) {
        //NOTE: we don't need to increment preprocessor position, since character token
        //emission is always forced by the start of the next character token here.
        //So, we already have advanced position.
        this.currentCharacterToken.location.end = this.preprocessor.pos;
    }
    tokenizerProto._emitCurrentCharacterToken.call(this);
};
//NOTE: patch initial states for each mode to obtain token start position
Object.keys(tokenizerProto.MODE)
    .map(function (modeName) {
        return tokenizerProto.MODE[modeName];
    })
    .forEach(function (state) {
        tokenizer[state] = function (cp) {
            this.tokenStartLoc = this.preprocessor.pos;
            tokenizerProto[state].call(this, cp);
        };
    });

};