using System.IO;
using Microsoft.CodeAnalysis;
using Semmle.Extraction.CSharp.Util;
using Semmle.Extraction.Kinds;

namespace Semmle.Extraction.CSharp.Entities
{
    /// <summary>
    /// Represents the autogenerated backing field `field` for a property.
    /// It is only created for properties that use the `field` keyword in their getter or setter, and
    /// is not created for auto-properties.
    /// </summary>
    internal class PropertyField : Field
    {
        protected PropertyField(Context cx, IFieldSymbol init)
            : base(cx, init)
        {
        }

        public static new PropertyField Create(Context cx, IFieldSymbol field) => PropertyFieldFactory.Instance.CreateEntity(cx, (field, field.AssociatedSymbol), field);

        public override bool NeedsPopulation => true;

        public override void Populate(TextWriter trapFile)
        {
            PopulateNullability(trapFile, Symbol.GetAnnotatedType());

            var unboundFieldKey = PropertyField.Create(Context, Symbol.OriginalDefinition);
            var name = Symbol.AssociatedSymbol is not null ? $"{Symbol.AssociatedSymbol.GetName()}.field" : Symbol.Name;
            trapFile.fields(this, VariableKind.None, name, ContainingType!, Type.TypeRef, unboundFieldKey);
            trapFile.compiler_generated(this);

            PopulateModifiers(trapFile);

            if (Context.OnlyScaffold)
            {
                return;
            }

            if (Context.ExtractLocation(Symbol))
            {
                WriteLocationsToTrap(trapFile.field_location, this, Locations);
            }
        }

        private class PropertyFieldFactory : CachedEntityFactory<IFieldSymbol, PropertyField>
        {
            public static PropertyFieldFactory Instance { get; } = new PropertyFieldFactory();

            public override PropertyField Create(Context cx, IFieldSymbol init) => new PropertyField(cx, init);
        }
    }
}
