// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax;

namespace Microsoft.AspNetCore.Razor.Language.Legacy
{
    internal abstract class LanguageCharacteristics<TTokenizer>
        where TTokenizer : Tokenizer
    {
        public abstract string GetSample(SyntaxKind type);
        public abstract TTokenizer CreateTokenizer(ITextDocument source);
        public abstract SyntaxKind FlipBracket(SyntaxKind bracket);
        public abstract SyntaxToken CreateMarkerToken();

        public virtual IEnumerable<SyntaxToken> TokenizeString(string content)
        {
            return TokenizeString(SourceLocation.Zero, content);
        }

        public virtual IEnumerable<SyntaxToken> TokenizeString(SourceLocation start, string input)
        {
            using (var reader = new SeekableTextReader(input, start.FilePath))
            {
                var tok = CreateTokenizer(reader);
                SyntaxToken token;
                while ((token = tok.NextToken()) != null)
                {
                    yield return token;
                }
            }
        }

        public virtual bool IsWhitespace(SyntaxToken token)
        {
            return IsKnownTokenType(token, KnownTokenType.Whitespace);
        }

        public virtual bool IsNewLine(SyntaxToken token)
        {
            return IsKnownTokenType(token, KnownTokenType.NewLine);
        }

        public virtual bool IsIdentifier(SyntaxToken token)
        {
            return IsKnownTokenType(token, KnownTokenType.Identifier);
        }

        public virtual bool IsKeyword(SyntaxToken token)
        {
            return IsKnownTokenType(token, KnownTokenType.Keyword);
        }

        public virtual bool IsTransition(SyntaxToken token)
        {
            return IsKnownTokenType(token, KnownTokenType.Transition);
        }

        public virtual bool IsCommentStart(SyntaxToken token)
        {
            return IsKnownTokenType(token, KnownTokenType.CommentStart);
        }

        public virtual bool IsCommentStar(SyntaxToken token)
        {
            return IsKnownTokenType(token, KnownTokenType.CommentStar);
        }

        public virtual bool IsCommentBody(SyntaxToken token)
        {
            return IsKnownTokenType(token, KnownTokenType.CommentBody);
        }

        public virtual bool IsUnknown(SyntaxToken token)
        {
            return IsKnownTokenType(token, KnownTokenType.Unknown);
        }

        public virtual bool IsKnownTokenType(SyntaxToken token, KnownTokenType type)
        {
            return token != null && (token.Kind == GetKnownTokenType(type));
        }

        public virtual Tuple<SyntaxToken, SyntaxToken> SplitToken(SyntaxToken token, int splitAt, SyntaxKind leftType)
        {
            var left = CreateToken(token.Content.Substring(0, splitAt), leftType, RazorDiagnostic.EmptyArray);

            SyntaxToken right = null;
            if (splitAt < token.Content.Length)
            {
                right = CreateToken(token.Content.Substring(splitAt), token.Kind, token.GetDiagnostics());
            }

            return Tuple.Create(left, right);
        }

        public abstract SyntaxKind GetKnownTokenType(KnownTokenType type);

        public virtual bool KnowsTokenType(KnownTokenType type)
        {
            return type == KnownTokenType.Unknown || (GetKnownTokenType(type) != GetKnownTokenType(KnownTokenType.Unknown));
        }

        protected abstract SyntaxToken CreateToken(string content, SyntaxKind type, RazorDiagnostic[] errors);
    }
}
