using System;
using System.Linq;
using RootMotion.FinalIK;
using UnityEngine;

[Serializable]
public class BipedIKCtrlData : IKCtrlData
{
	public BipedIKCtrlData(IKEffector effector, FBIKChain chain, IKMappingLimb ik_mapping, FullBodyIKCtrl ik_ctrl, Transform tgt_bone, IKEffector sub_effector, bool use_old = false) : base(ik_ctrl, tgt_bone, use_old, false)
	{
		this.Effector = effector;
		this.Effector.target = base.IKTarget;
		this.Chain = chain;
		this.IKMapping = ik_mapping;
		this.RootEffector = sub_effector;
		Transform transform = this.CreateSubTarget("BendBone");
		this.m_BoneBendGoal = new IKCtrlData.BoneTgtPair(this.Chain.bendConstraint.bone2, transform);
		this.Chain.bendConstraint.bendGoal = transform;
		this.Chain.bendConstraint.weight = 1f;
		this.RootEffector.target = this.CreateSubTarget("ChainRootBone");
		this.m_RootBoneTgtPair = new IKCtrlData.BoneTgtPair(this.RootEffector.bone, this.RootEffector.target);
		this.m_ForceIKEnable = true;
		this.ToCorrectBone = this.TargetBone;
		this.m_BendweitCtrl.Axis = Vector3.up;
	}

	public Transform BendBone
	{
		get
		{
			return this.m_BoneBendGoal.Bone;
		}
	}

	public Transform RootBone
	{
		get
		{
			return this.m_RootBoneTgtPair.Bone;
		}
	}

	public IKCtrlData.ChangeFlagData BendweightCtrl
	{
		get
		{
			return this.m_BendweitCtrl;
		}
	}

	public override Transform TargetBone
	{
		get
		{
			if (this.IsRootIK)
			{
				return this.RootBone;
			}
			if (this.IsBendIK)
			{
				return this.BendBone;
			}
			return base.TargetBone;
		}
	}

	public override Transform[] ChainBones
	{
		get
		{
			return (from node in this.Chain.nodes
			select node.transform).ToArray<Transform>();
		}
	}

	public override float PositionWeight
	{
		get
		{
			return this.Effector.positionWeight;
		}
		set
		{
			this.Effector.positionWeight = value;
		}
	}

	public override float RotationWeight
	{
		get
		{
			return this.Effector.rotationWeight;
		}
		set
		{
			this.Effector.rotationWeight = value;
		}
	}

	private Transform CreateSubTarget(string name)
	{
		Transform transform = base.IKTarget.parent.Find(name);
		if (!transform)
		{
			transform = new GameObject(name).transform;
			transform.SetParent(base.IKTarget.parent, false);
		}
		return transform;
	}

	private void CheckBorder(BipedIKCtrlData.BorderCorrectData correctData)
	{
		if (!correctData.Enable)
		{
			return;
		}
		float num = 0f;
		Vector3 check_pos = this.ToCorrectBone.position + this.MyIKCtrl.BodyCtrlData.BodyOffset;
		if (correctData.CheckBorder(check_pos, ref num))
		{
			switch (this.CorrectType)
			{
			case BipedIKCtrlData.BorderCorrectType.Bone:
				base.IKTarget.position += correctData.Axis * num;
				this.m_BoneBendGoal.Target.position += correctData.Axis * num;
				if (this.PositionWeight == 0f)
				{
					this.PositionWeight = 1f;
					base.PointIK.IsIKExec = true;
				}
				break;
			case BipedIKCtrlData.BorderCorrectType.HalfBody:
				base.IKTarget.position += correctData.Axis * num;
				this.m_BoneBendGoal.Target.position += correctData.Axis * num;
				this.m_RootBoneTgtPair.Target.position += correctData.Axis * num;
				if (this.PositionWeight == 0f)
				{
					this.PositionWeight = 1f;
					base.PointIK.IsIKExec = true;
				}
				break;
			case BipedIKCtrlData.BorderCorrectType.Chara:
				if (correctData.GetValue(this.MyIKCtrl.BodyCtrlData.AddOffset) < num)
				{
					this.MyIKCtrl.BodyCtrlData.SetAddOffset(correctData.Axis * num);
				}
				break;
			case BipedIKCtrlData.BorderCorrectType.All:
				if (correctData.GetValue(this.MyIKCtrl.BodyCtrlData.AllOffset) < num)
				{
					this.MyIKCtrl.BodyCtrlData.SetAllOffset(correctData.Axis * num);
				}
				break;
			}
		}
	}

	protected override void SetTargetTransform(IKCtrlData.IKParam data, Vector3 pos, Quaternion rot)
	{
		base.SetTargetTransform(data, pos, rot);
		Transform target = this.m_BoneBendGoal.Target;
		Transform target2 = this.m_RootBoneTgtPair.Target;
		if (this.IsRootIK || this.IsBendIK)
		{
			Vector3 position = target2.InverseTransformPoint(target.position);
			Vector3 position2 = this.m_BoneBendGoal.Bone.InverseTransformPoint(base.TargetBone.position);
			if (this.IsRootIK)
			{
				if (data.IsPointAttach)
				{
					this.RootEffector.positionWeight = this.PositionWeight;
					target2.position = base.IKTarget.position;
				}
				else
				{
					this.RootEffector.rotationWeight = this.RotationWeight;
					target2.rotation = base.IKTarget.rotation;
					target.rotation = target2.rotation * this.m_BoneBendGoal.Bone.localRotation;
					base.IKTarget.rotation = target.rotation * base.TargetBone.localRotation;
				}
				target.position = target2.TransformPoint(position);
				base.IKTarget.position = target.TransformPoint(position2);
			}
			else
			{
				if (data.IsPointAttach)
				{
					this.Chain.bendConstraint.weight = this.PositionWeight;
					this.RootEffector.positionWeight = (this.RootEffector.rotationWeight = this.PositionWeight);
					target2.rotation = Quaternion.FromToRotation(target.position - target2.position, base.IKTarget.position - target2.position) * target2.rotation;
					Vector3 b = base.IKTarget.position - target2.TransformPoint(position);
					target2.position += b;
					target.position = base.IKTarget.position;
				}
				else
				{
					target.rotation = base.IKTarget.rotation;
					base.IKTarget.rotation = target.rotation * base.TargetBone.localRotation;
				}
				base.IKTarget.position = this.m_BoneBendGoal.Target.TransformPoint(position2);
			}
		}
		else if (data.IsPointAttach)
		{
			Vector3 vector = this.m_BoneBendGoal.Bone.position - this.TargetBone.position;
			Vector3 vector2 = this.m_RootBoneTgtPair.Bone.position - this.m_BoneBendGoal.Bone.position;
			float f = Vector3.Dot(vector.normalized, vector2.normalized);
			float num = Mathf.Acos(f) * 57.29578f;
			float num2 = Mathf.Clamp01(num / this.m_BendFadeBorder);
			this.Chain.bendConstraint.weight = num2 * this.PositionWeight;
			Vector3 position3 = this.TargetBone.InverseTransformPoint(this.m_RootBoneTgtPair.Bone.position);
			target2.position = base.IKTarget.TransformPoint(position3);
			Vector3 position4 = this.TargetBone.InverseTransformPoint(this.m_BoneBendGoal.Bone.position);
			Vector3 position5 = base.IKTarget.TransformPoint(position4);
			target.position = position5;
		}
	}

	public void SetBendweightCtrl(string name)
	{
		if (this.MyIKCtrl.TgtMaid.boMAN)
		{
			this.BendweightCtrl.Target = this.MyIKCtrl.TgtBody.GetBone(name);
		}
		else
		{
			this.BendweightCtrl.Target = this.MyIKCtrl.GetSTFlagObj(name);
		}
	}

	public override void ApplyIKSetting()
	{
		this.m_BoneBendGoal.Cppy();
		this.m_RootBoneTgtPair.Cppy();
		this.Chain.bendConstraint.weight = 0f;
		this.RootEffector.positionWeight = 0f;
		this.RootEffector.rotationWeight = 0f;
		if (!base.PointIK.IsIKExec && !base.PointFlagData.IsEnable && (this.FloorCorrect.Enable || this.WallCorrect.Enable))
		{
			base.ForceIK = true;
		}
		base.ApplyIKSetting();
		this.CheckBorder(this.WallCorrect);
		this.CheckBorder(this.FloorCorrect);
		if (!this.IsBendIK && !this.IsRootIK && this.m_BendweitCtrl.IsEnable)
		{
			this.Chain.bendConstraint.weight = 1f - this.m_BendweitCtrl.Value01();
		}
	}

	public override void SetIKSetting(IKCtrlData.IKAttachType attachType, bool is_next, Maid tgt_maid, int slot_no, string attach_name, Transform axis_bone, Transform target, Vector3 f_vecOffset, bool do_animation = false)
	{
		base.SetIKSetting(attachType, is_next, tgt_maid, slot_no, attach_name, axis_bone, target, f_vecOffset, do_animation);
		if (this.IsRootIK)
		{
			base.BlendPosRot.Copy(this.m_lastRootPosRot);
		}
		else if (this.IsBendIK)
		{
			base.BlendPosRot.Copy(this.m_lastBendPosRot);
		}
	}

	public override void Detach(IKCtrlData.IKAttachType attachType)
	{
		base.Detach(attachType);
		this.IsRootIK = (this.IsBendIK = false);
		this.RootEffector.positionWeight = 0f;
		this.RootEffector.rotationWeight = 0f;
		this.m_BoneBendGoal.PosOffset = Vector3.zero;
		this.m_RootBoneTgtPair.PosOffset = Vector3.zero;
		this.WallCorrect.Reset();
		this.FloorCorrect.Reset();
		this.ToCorrectBone = this.TargetBone;
		this.CorrectType = BipedIKCtrlData.BorderCorrectType.Bone;
		this.m_BendweitCtrl.Reset();
	}

	public override void SetTargetOffset(Vector3 offset, bool inverse = false)
	{
		if (base.IsIKExec)
		{
			return;
		}
		base.SetTargetOffset(offset, inverse);
		this.m_BoneBendGoal.PosOffset = this.m_OffsetEnable.GetEnable(offset, inverse);
		this.m_RootBoneTgtPair.PosOffset = this.m_OffsetEnable.GetEnable(offset, inverse);
	}

	public override void LateUpdate()
	{
		base.LateUpdate();
		this.m_lastBendPosRot.Copy(this.m_BoneBendGoal.Bone);
		this.m_lastRootPosRot.Copy(this.m_RootBoneTgtPair.Bone);
	}

	private IKCtrlData.BoneTgtPair m_BoneBendGoal;

	private IKCtrlData.PosRotPair m_lastBendPosRot = new IKCtrlData.PosRotPair();

	private IKCtrlData.ChangeFlagData m_BendweitCtrl = new IKCtrlData.ChangeFlagData();

	private IKCtrlData.BoneTgtPair m_RootBoneTgtPair;

	private IKCtrlData.PosRotPair m_lastRootPosRot = new IKCtrlData.PosRotPair();

	[Header("壁・床補正情報")]
	public BipedIKCtrlData.BorderCorrectData WallCorrect = new BipedIKCtrlData.BorderCorrectData(Vector3.forward);

	public BipedIKCtrlData.BorderCorrectData FloorCorrect = new BipedIKCtrlData.BorderCorrectData(Vector3.up);

	public BipedIKCtrlData.BorderCorrectType CorrectType;

	public Transform ToCorrectBone;

	[Header("肘・膝をターゲットに合わせるフラグ")]
	public bool IsBendIK;

	[Header("肩・太ももをターゲットに合わせるフラグ")]
	public bool IsRootIK;

	[SerializeField]
	[Space]
	[Range(1f, 90f)]
	private float m_BendFadeBorder = 30f;

	public readonly IKEffector Effector;

	public readonly FBIKChain Chain;

	public readonly IKMappingLimb IKMapping;

	public readonly IKEffector RootEffector;

	public enum BorderCorrectType
	{
		Bone,
		HalfBody,
		Chara,
		All
	}

	[Serializable]
	public class BorderCorrectData
	{
		public BorderCorrectData(Vector3 axis)
		{
			this.Axis = axis;
		}

		public void Reset()
		{
			this.Border = 0f;
			this.Enable = false;
		}

		public float GetValue(Vector3 pos)
		{
			pos = KasaiUtility.Vec3Multiply(pos, this.Axis);
			return pos.magnitude * Vector3.Dot(this.Axis, pos.normalized);
		}

		public bool CheckBorder(Vector3 check_pos, ref float diff)
		{
			float value = this.GetValue(check_pos);
			diff = this.Border - value;
			return value < this.Border;
		}

		public float Border;

		public bool Enable;

		public Vector3 Axis;
	}
}
