/*
<copyright file="BGDatabaseSetField.cs" company="BansheeGz">
    Copyright (c) 2018-2021 All Rights Reserved
</copyright>
*/

using System;
using System.Collections.Generic;
using Unity.VisualScripting;

namespace BansheeGz.BGDatabase
{
    [UnitCategory("BansheeGz")]
    public class BGDatabaseSetField : BGDatabaseGetFieldA
    {
        public enum FieldSourceEnum
        {
            Object,
            String,
            Int,
            Float,
            Bool,
            Entity,
            EntityList
        }

        [DoNotSerialize] public ControlInput _in;
        [DoNotSerialize] public ControlOutput _out;

        [DoNotSerialize] public ValueInput fieldSource;
        [DoNotSerialize] public ValueInput objectValue;
        [DoNotSerialize] public ValueInput stringValue;
        [DoNotSerialize] public ValueInput intValue;
        [DoNotSerialize] public ValueInput floatValue;
        [DoNotSerialize] public ValueInput boolValue;
        [DoNotSerialize] public ValueInput entityValue;
        [DoNotSerialize] public ValueInput entityListValue;

        protected override void Definition()
        {
            _in = ControlInput("_in", Enter);
            _out = ControlOutput("_out");
            Succession(_in, _out);

            base.Definition();

            fieldSource = ValueInput<FieldSourceEnum>("Field source", FieldSourceEnum.Object);
            objectValue = ValueInput<object>("objectValue");
            stringValue = ValueInput<string>("stringValue", "");
            intValue = ValueInput<int>("intValue", 0);
            floatValue = ValueInput<float>("floatValue", 0f);
            boolValue = ValueInput<bool>("boolValue", false);
            entityValue = ValueInput<BGEntity>("entityValue");
            entityListValue = ValueInput<List<BGEntity>>("entityListValue");
        }

        private ControlOutput Enter(Flow flow)
        {
            var meta = GetMeta(flow);
            var field = GetField(flow, meta);
            var row = GetEntity(flow, meta);
            var fieldSourceValue = flow.GetValue<FieldSourceEnum>(fieldSource);
            switch (fieldSourceValue)
            {
                case FieldSourceEnum.Object:
                    if (objectValue.hasValidConnection) field.SetValue(row.Index, flow.GetValue(objectValue));
                    break;
                case FieldSourceEnum.String:
                    SetValue<string>(flow, field, row, stringValue);
                    break;
                case FieldSourceEnum.Int:
                    SetValue<int>(flow, field, row, intValue);
                    break;
                case FieldSourceEnum.Float:
                    SetValue<float>(flow, field, row, floatValue);
                    break;
                case FieldSourceEnum.Bool:
                    SetValue<bool>(flow, field, row, boolValue);
                    break;
                case FieldSourceEnum.Entity:
                    SetValue<BGEntity>(flow, field, row, entityValue);
                    break;
                case FieldSourceEnum.EntityList:
                    SetValue<List<BGEntity>>(flow, field, row, entityListValue);
                    break;
                default:
                    throw new ArgumentOutOfRangeException("fieldSourceValue");
            }

            return _out;
        }

        private static void SetValue<T>(Flow flow, BGField field, BGEntity row, ValueInput input)
        {
            if (field.ReadOnly) throw new Exception("Can not set value to " + field.FullName + " field, because this field is readonly ");
            if (!(field is BGField<T>)) throw new Exception("Can not cast " + field.FullName + " field to BGField<" + typeof(T).Name + ">, the field's value type is " + field.ValueType.Name);
            var value = flow.GetValue<T>(input);
            ((BGField<T>) field)[row.Index] = value;
        }
    }
}