import { Color } from './highlighter/properties/color.js';
import { Cursor } from './highlighter/properties/cursor.js';
import { Font } from './highlighter/properties/font.js';
import { Link } from './highlighter/properties/link.js';
import { Span } from './highlighter/span.js';
import { Token } from './tokenizer/token.js';
import { CommentToken } from './tokenizer/tokens/comment.js';
import { DOCTYPEToken } from './tokenizer/tokens/doctype.js';
import { EndTagToken } from './tokenizer/tokens/endTag.js';
import { StartTagToken } from './tokenizer/tokens/startTag.js';

export class Highlighter {
    public spans: Array<Span> = new Array<Span>();

    public finished: boolean = false;

    public constructor(private tokens: Array<Token>) {
    }

    public spin(): void {
        for (const token of this.tokens) {
            if (token instanceof CommentToken) {
                this.spans.push(Span.createFromRange(token, token.range, Color.Comment, Font.Italic));
            }

            if (token instanceof DOCTYPEToken) {
                this.spans.push(Span.createFromRange(token, { start: token.range.start.copy().decrement(8), end: token.range.start }, Color.Tag));
                this.spans.push(Span.createFromRange(token, { start: token.range.start, end: token.range.end }, Color.Attribute, Font.Italic));
                this.spans.push(Span.createFromRange(token, { start: token.range.start.copy().decrement(10), end: token.range.start.copy().decrement(9) }, Color.Punctuator));
                this.spans.push(Span.createAt(token, token.range.end, Color.Punctuator));
            }

            if (token instanceof StartTagToken || token instanceof EndTagToken) {
                this.spans.push(Span.createFromRange(token, token.range, Color.Tag));

                for (const attribute of token.attributes.list) {
                    this.spans.push(Span.createFromRange(attribute, attribute.nameRange, Color.Attribute, Font.Italic));

                    if (attribute.valueRange !== undefined) {
                        if (attribute.name === 'href') {
                            this.spans.push(Span.createAnchorFromRange(attribute, attribute.valueRange, Color.String, Font.Underline, Cursor.Pointer, Link.of(attribute.value)));
                        } else {
                            this.spans.push(Span.createFromRange(attribute, attribute.valueRange, Color.String));
                        }

                        if (attribute.quoted) {
                            this.spans.push(Span.createAt(attribute, attribute.valueRange.start, Color.Punctuator));
                            this.spans.push(Span.createAt(attribute, attribute.valueRange.end, Color.Punctuator));
                        }
                    }

                    if (attribute.equalsPosition !== undefined)
                        this.spans.push(Span.createAt(attribute, attribute.equalsPosition, Color.Punctuator));
                }

                if (token instanceof StartTagToken) {
                    this.spans.push(Span.createAt(token, token.range.start.copy().decrement(1), Color.Punctuator));
                    this.spans.push(Span.createAt(token, token.range.end, Color.Punctuator));
                }

                if (token instanceof EndTagToken) {
                    this.spans.push(Span.createFromRange(token, { start: token.range.start.copy().decrement(2), end: token.range.start.copy().decrement(1) }, Color.Punctuator));
                    this.spans.push(Span.createAt(token, token.range.end, Color.Punctuator));
                }
            }
        }

        this.finished = true;
    }
}
