/// <summary>
    /// Sets the spiral properties yo the curves
    /// </summary>
    private void SetSpiralProperties(SplineParticles _target)
    {
        AnimationCurve 	tempCurveFirstAxis = new AnimationCurve();
        AnimationCurve 	tempCurveSecondAxis = new AnimationCurve();
        AnimationCurve	targetAnimationCurveFirstAxis 	= new AnimationCurve();
        AnimationCurve	targetAnimationCurveSecondAxis	= new AnimationCurve();

        switch (_target.spiralAxis)
        {
            case SplineParticles.SPIRAL_AXIS.X:
                targetAnimationCurveFirstAxis 	= 	_target.velocityCurveZ;
                targetAnimationCurveSecondAxis 	=	_target.velocityCurveY;
            break;
            case SplineParticles.SPIRAL_AXIS.Y:
                targetAnimationCurveFirstAxis 	= 	_target.velocityCurveX;
                targetAnimationCurveSecondAxis 	=	_target.velocityCurveZ;
            break;
            case SplineParticles.SPIRAL_AXIS.Z:
                targetAnimationCurveFirstAxis 	= 	_target.velocityCurveX;
                targetAnimationCurveSecondAxis 	=	_target.velocityCurveY;
            break;

        }

        for (int i = 0; i<targetAnimationCurveFirstAxis.keys.Length; i++)
        {
            Keyframe newKey = targetAnimationCurveFirstAxis.keys[i];
            newKey.value += Mathf.Sin(newKey.time*6*_target.spiralLoops)*10*_target.spiralAmplitude;
            tempCurveFirstAxis.AddKey(newKey);
        }

        for (int i = 0; i<targetAnimationCurveSecondAxis.keys.Length; i++)
        {
            Keyframe newKey = targetAnimationCurveSecondAxis.keys[i];
            newKey.value += Mathf.Cos(newKey.time*6*_target.spiralLoops)*10*_target.spiralAmplitude;
            tempCurveSecondAxis.AddKey(newKey);

        }

        //Assign curves
        switch (_target.spiralAxis)
        {
            case SplineParticles.SPIRAL_AXIS.X:
                _target.velocityCurveZ = tempCurveFirstAxis;
                _target.velocityCurveY = tempCurveSecondAxis;
            break;
            case SplineParticles.SPIRAL_AXIS.Y:
                _target.velocityCurveX = tempCurveFirstAxis;
                _target.velocityCurveZ = tempCurveSecondAxis;
            break;
            case SplineParticles.SPIRAL_AXIS.Z:
                _target.velocityCurveX = tempCurveFirstAxis;
                _target.velocityCurveY = tempCurveSecondAxis;
            break;
        }
    }
    /// <summary>
    /// Simplifies the curve, to reduce noise or to make it eaiser to tweak on the editor
    /// </summary>
    private AnimationCurve SimplifyCurve(AnimationCurve _curveToSimplify, SplineParticles _target)
    {
        AnimationCurve	simplifiedAnimationCurve =  new AnimationCurve();

        for (int i = 0; i<_curveToSimplify.keys.Length; i++)
        {
            if (i == 0 || i == _curveToSimplify.keys.Length-1)
                simplifiedAnimationCurve.AddKey(_curveToSimplify.keys[i]);
            else
            {
                Keyframe prevKey = _curveToSimplify.keys[i-1];
                Keyframe currentKey = _curveToSimplify.keys[i];
                float inLineTangent = (currentKey.value - prevKey.value)/(currentKey.time-prevKey.time);

                // We have to test not only the coordinates but also the tangents
                if (Mathf.Sign(Mathf.Round(inLineTangent*100)/100) != Mathf.Sign(Mathf.Round(currentKey.inTangent*100)/100) ||
                    Mathf.Sign(Mathf.Round(inLineTangent*100)/100) != Mathf.Sign(Mathf.Round(prevKey.outTangent*100)/100) ||
                    (
                    (Mathf.Sign(inLineTangent) == Mathf.Sign(currentKey.inTangent) && Mathf.Abs(Mathf.Abs(inLineTangent)-Mathf.Abs(currentKey.inTangent)) > _target.pathSimplifyError) ||
                    (Mathf.Sign(inLineTangent) == Mathf.Sign(currentKey.outTangent) && Mathf.Abs(Mathf.Abs(inLineTangent)-Mathf.Abs(currentKey.outTangent)) > _target.pathSimplifyError)
                    ))
                    simplifiedAnimationCurve.AddKey(_curveToSimplify.keys[i]);
            }
        }

        return simplifiedAnimationCurve;
    }
    private void NormelizeAndSimplify(SplineParticles _target)
    {
        //Curve values normalization. To show correctly on the particle velocity curve editor

        xVelocityCurveScale = NormalizeCurve(ref _target.velocityCurveX);
        yVelocityCurveScale = NormalizeCurve(ref _target.velocityCurveY);
        zVelocityCurveScale = NormalizeCurve(ref _target.velocityCurveZ);

        //Simplify the number of key. This will help to reduce noise or to be easier to tweek the curves on the editor
        _target.velocityCurveX = SimplifyCurve(_target.velocityCurveX, _target);
        _target.velocityCurveY = SimplifyCurve(_target.velocityCurveY, _target);
        _target.velocityCurveZ = SimplifyCurve(_target.velocityCurveZ, _target);
    }
    /// <summary>
    /// Sets the curve points.
    /// </summary>
    private void SetCurvePoints(int _loopNumber, Spline.BaseSpline.SplineIterator _iterator, SplineParticles _target, float _offset)
    {
        previousPoint = Vector3.zero;

        for (float i = 0; i<=1; i += _target.pathQuality)
        {
            CalculatePoint(i, _loopNumber, _iterator, _target, _offset);
        }
    }
    /// <summary>
    /// Creates the velocity curve.
    /// </summary>
    /// <param name='_target'>
    /// _target.
    /// </param>
    private void CreateVelocityCurve(SplineParticles _target)
    {
        if (_target.pathQuality <= 0)
        {
            Debug.LogWarning("Too much quality on particle follow path");
            return;
        }

        Spline.BaseSpline.SplineIterator splineIterator;

        if (_target.splinePath == null)
            splineIterator = _target.GetComponent<SplineParticles>().Spline.GetIterator();

        else
            splineIterator = _target.splinePath.Spline.GetIterator();

        //Clear curve values
        _target.velocityCurveX = new AnimationCurve();
        _target.velocityCurveY = new AnimationCurve();
        _target.velocityCurveZ = new AnimationCurve();

        if (_target.loopNumber <= 1) //Set the curve points for each loop
        {
            SetCurvePoints(1, splineIterator, _target, 0);
        }
        else
        {
            for (int i = 0; i < _target.loopNumber; i++)
                SetCurvePoints(_target.loopNumber, splineIterator, _target, (float)i/(float)_target.loopNumber);
        }

        //Check if there is any key on the last keyframe, for precision problems
        if (1 - _target.velocityCurveX.keys[_target.velocityCurveX.keys.Length-1].time >= 0.0001f)
        {
                CalculatePoint(1, 1, splineIterator, _target, 0);
        }
    }
    /// <summary>
    /// Creates the veocity curves and Assign them to the particle system
    /// </summary>
    /// <param name='_target'>
    /// _target.
    /// </param>
    private void CreateAndSetVelocityCurves(SplineParticles _target)
    {
        ClearCurves(_target);
        CreateVelocityCurve(_target);

        if (_target.useSpiral)
            SetSpiralProperties(_target);

        NormelizeAndSimplify(_target);

        ChangeVelocityCurve(_target);
    }
    private void ClearCurves(SplineParticles _target)
    {
        _target.velocityCurveX = AnimationCurve.Linear(0,0,1,0);
        _target.velocityCurveY = AnimationCurve.Linear(0,0,1,0);
        _target.velocityCurveZ = AnimationCurve.Linear(0,0,1,0);

        xVelocityCurveScale = 1;
        yVelocityCurveScale = 1;
        zVelocityCurveScale = 1;

        this.Repaint();
    }
    /// <summary>
    /// Apply the changes to the particle system
    /// </summary>
    private void ChangeVelocityCurve(SplineParticles _target)
    {
        ParticleSystem myParticleSystem = _target.gameObject.GetComponent<ParticleSystem>();

        SerializedObject newSerializedObject = new SerializedObject(myParticleSystem);

        SerializedProperty enableVelocityModule = newSerializedObject.FindProperty("VelocityModule.enabled");

        SerializedProperty velocityModuleTypeX = newSerializedObject.FindProperty("VelocityModule.x.minMaxState");
        SerializedProperty velocityModuleTypeY = newSerializedObject.FindProperty("VelocityModule.y.minMaxState");
        SerializedProperty velocityModuleTypeZ = newSerializedObject.FindProperty("VelocityModule.z.minMaxState");

        SerializedProperty velocityModuleInWorldSpace = newSerializedObject.FindProperty("VelocityModule.inWorldSpace");

        SerializedProperty speedCurveX = newSerializedObject.FindProperty("VelocityModule.x.maxCurve");

        SerializedProperty scalarCurveX = newSerializedObject.FindProperty("VelocityModule.x.scalar");

        SerializedProperty speedCurveY = newSerializedObject.FindProperty("VelocityModule.y.maxCurve");

        SerializedProperty scalarCurveY = newSerializedObject.FindProperty("VelocityModule.y.scalar");

        SerializedProperty speedCurveZ = newSerializedObject.FindProperty("VelocityModule.z.maxCurve");

        SerializedProperty scalarCurveZ = newSerializedObject.FindProperty("VelocityModule.z.scalar");

        if (_target.autoEnableParticleVelocityCurves == true)
        {
            if (!_target.hasCreatedTheCurveOnce)
            {
                _target.particleSystem.startSpeed = 0;
                _target.hasCreatedTheCurveOnce = true;
            }
            velocityModuleInWorldSpace.boolValue = false;
            enableVelocityModule.boolValue 	= _target.autoEnableParticleVelocityCurves;
            velocityModuleTypeX.intValue  	= 1;
            velocityModuleTypeY.intValue  	= 1;
            velocityModuleTypeZ.intValue  	= 1;
            _target.particleSystem.startSpeed = 0;
        }

        scalarCurveX.floatValue = xVelocityCurveScale;
        scalarCurveY.floatValue = yVelocityCurveScale;
        scalarCurveZ.floatValue = zVelocityCurveScale;

        speedCurveX.animationCurveValue = _target.velocityCurveX;
        speedCurveY.animationCurveValue = _target.velocityCurveY;
        speedCurveZ.animationCurveValue = _target.velocityCurveZ;

        newSerializedObject.ApplyModifiedProperties();
    }
    /// <summary>
    /// Calculates the point each animation curve point. 
    /// </summary>
    private void CalculatePoint(float _point, int _loopNumber, Spline.BaseSpline.SplineIterator _iterator, SplineParticles _target, float _offset)
    {
        _iterator.SetOffsetPercent(_point);

            //Calc modifiers

            float lifeTimeModifier = _target.particleSystem.startLifetime;
            float loopsModifier = _target.loopNumber;

            //Vector3 tangentAtPoint = _target.transform.TransformDirection(_iterator.GetTangent().normalized);
            Vector3 currentPosition = _target.transform.TransformPoint(_iterator.GetPosition());
            Vector3 tangentAtPoint = (_iterator.GetTangent().normalized);
            //Vector3 currentPosition =(_iterator.GetPosition());
            Vector3 velocityAtPoint = Vector3.zero;

            if (_point == 0 && _target.Spline.WrapMode == Spline.BaseSpline.SplineWrapMode.Loop)
            {
                _iterator.SetOffsetPercent(1-_target.pathQuality);
                previousPoint = _target.transform.TransformPoint(_iterator.GetPosition());
                //previousPoint = (_iterator.GetPosition());
            }
            else if (_point == 0 && _target.Spline.WrapMode != Spline.BaseSpline.SplineWrapMode.Loop)
            {
                _iterator.SetOffsetPercent(_point+_target.pathQuality);
                previousPoint = _target.transform.TransformPoint(_iterator.GetPosition());
                //previousPoint = (_iterator.GetPosition());
            }

            velocityAtPoint = (currentPosition - previousPoint).magnitude * tangentAtPoint;
            //velocityAtPoint = tangentAtPoint;

            previousPoint = currentPosition;

            velocityAtPoint *= loopsModifier*(1/_target.pathQuality)/lifeTimeModifier;

        //		Debug.Log("Point:  " + _point + "   " + velocityAtPoint.x + "  " +velocityAtPoint.y + "   "+velocityAtPoint.z );

            _target.velocityCurveX.AddKey(_point/_loopNumber + _offset,velocityAtPoint.x);
            _target.velocityCurveY.AddKey(_point/_loopNumber + _offset,velocityAtPoint.y);
            _target.velocityCurveZ.AddKey(_point/_loopNumber + _offset,velocityAtPoint.z);
    }