using Microsoft.CodeAnalysis.CSharp.Syntax;
using Semmle.Extraction.Kinds;
using Microsoft.CodeAnalysis;
using Semmle.Extraction.CSharp.Populators;
using Microsoft.CodeAnalysis.CSharp;

namespace Semmle.Extraction.CSharp.Entities.Expressions
{
    class Literal : Expression<LiteralExpressionSyntax>
    {
        Literal(ExpressionNodeInfo info) : base(info.SetKind(GetKind(info)) ) { }

        public static Expression Create(ExpressionNodeInfo info) => new Literal(info).TryPopulate();

        protected override void Populate() { }

        static ExprKind GetKind(ExpressionNodeInfo info)
        {
            switch(info.Node.Kind())
            {
                case SyntaxKind.DefaultLiteralExpression:
                    return ExprKind.DEFAULT;
                case SyntaxKind.NullLiteralExpression:
                    info.Type = Type.Create(info.Context, null);  // Don't use converted type.
                    return ExprKind.NULL_LITERAL;
            }

            var type = info.Type.symbol;

            switch (type.SpecialType)
            {
                case SpecialType.System_Boolean:
                    return ExprKind.BOOL_LITERAL;

                case SpecialType.System_Int16:
                case SpecialType.System_Int32:
                case SpecialType.System_Byte:       // ??
                    return ExprKind.INT_LITERAL;

                case SpecialType.System_Char:
                    return ExprKind.CHAR_LITERAL;

                case SpecialType.System_Decimal:
                    return ExprKind.DECIMAL_LITERAL;

                case SpecialType.System_Double:
                    return ExprKind.DOUBLE_LITERAL;

                case SpecialType.System_Int64:
                    return ExprKind.LONG_LITERAL;

                case SpecialType.System_Single:
                    return ExprKind.FLOAT_LITERAL;

                case SpecialType.System_String:
                    return ExprKind.STRING_LITERAL;

                case SpecialType.System_UInt16:
                case SpecialType.System_UInt32:
                case SpecialType.System_SByte:      // ??
                    return ExprKind.UINT_LITERAL;

                case SpecialType.System_UInt64:
                    return ExprKind.ULONG_LITERAL;

                default:
                    info.Context.ModelError(info.Node, "Unhandled literal type");
                    return ExprKind.UNKNOWN;
            }
        }
    }
}
