using System.Collections.Generic;
using SharpDX;
using Framefield.Core.OperatorPartTraits;
using System;

namespace Framefield.Core.IDb15c950b_832f_4079_be7c_305aa579f9ff
{
    public class Class_LookAt : OperatorPart.Function, ISceneTransform
    {
        // ISceneTransform
        public Matrix Transform
        {
            get
            {
                UpdateTransform(new OperatorPartContext(), OperatorPart.Connections);
                return _transform;
            }
        }

        public override OperatorPartContext Eval(OperatorPartContext context, List<OperatorPart> inputs, int outputIdx) {
            var SceneInput = inputs[0];
            
            UpdateTransform(context, inputs);
            var prevTransform = context.ObjectTWorld;

            context.ObjectTWorld = _transform * prevTransform;
            SceneInput.Eval(context);
            context.ObjectTWorld = prevTransform;

            return context;
        }
        
        // >>> _inputids
        private enum InputId
        {
            SceneInput = 0,
            TargetX = 1,
            TargetY = 2,
            TargetZ = 3,
            UpVectorX = 4,
            UpVectorY = 5,
            UpVectorZ = 6
        }
        // <<< _inputids

        private void UpdateTransform(OperatorPartContext context, List<OperatorPart> inputs)
        {
            if (!Changed)
                return;
                
            // >>> _params
            var SceneInput = inputs[(int)InputId.SceneInput];
            var TargetX = inputs[(int)InputId.TargetX].Eval(context).Value;
            var TargetY = inputs[(int)InputId.TargetY].Eval(context).Value;
            var TargetZ = inputs[(int)InputId.TargetZ].Eval(context).Value;
            var Target = new Vector3(TargetX, TargetY, TargetZ);
            var UpVectorX = inputs[(int)InputId.UpVectorX].Eval(context).Value;
            var UpVectorY = inputs[(int)InputId.UpVectorY].Eval(context).Value;
            var UpVectorZ = inputs[(int)InputId.UpVectorZ].Eval(context).Value;
            var UpVector = new Vector3(UpVectorX, UpVectorY, UpVectorZ);
            // <<< _params

            //var translation = new Vector3(TranslateX, TranslateY, TranslateZ);
            //var rotation = Quaternion.RotationYawPitchRoll(MathUtil.DegreesToRadians(RotateY),
            //                                               MathUtil.DegreesToRadians(RotateX),
            //                                               MathUtil.DegreesToRadians(RotateZ));
            //var scale = new Vector3(ScaleX, ScaleY, ScaleZ);
            Vector3 scale, position;
            Quaternion rotation;
            context.ObjectTWorld.Decompose(out scale, out rotation, out position);

            var transform = Matrix.Identity;
            var t = position - Target;
            if (t.Length() > 0)
            {
                var dir = -t;
                dir.Normalize();
                var helperDir = new Vector3(1, 0, 0);
                if (Math.Abs(dir.Y) < 0.1 && Math.Abs(dir.Z) < 0.1)
                    helperDir = new Vector3(0, 1, 0);
                var yAxis = Vector3.Cross(dir, helperDir);
                yAxis.Normalize();
                var xAxis = Vector3.Cross(yAxis, dir);
                xAxis.Normalize();
                var m = Matrix.Identity;
                m.Row1 = new Vector4(xAxis, 0);
                m.Row2 = new Vector4(yAxis, 0);
                m.Row3 = new Vector4(dir, 0);
                transform *= m;
            }
            
            _transform = transform;


            //_transform = Matrix.Transformation(Pivot, Quaternion.Zero, scale, Pivot, rotation, translation);
        }

        private Matrix _transform;
    }
}
