using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Leap;
using Leap.Unity;
/// <summary>
/// This script invokes the virbration motors upon collisions with fingertips. The vibration strenght depends on
/// how deep your fingertips are inside the object. The implementation here does not directly respond to collisions
/// to keep the computational costs as low as possible. Only once per update it is checked whether the hand is colliding
/// with the object. If so, the finger tip positions are retained and the motors are activated if the tips are within the cube,
/// </summary>
[RequireComponent (typeof(Rigidbody))]
public class InteractionCube : MonoBehaviour {
    // reference to the controller, necessary to send the data
    public ArduinoConnector controller;
    // true as long as the hand is colliding with the cube
    private bool colliding;
    // reference to the actual hand, necessary to obtain fingertip positions
    private RigidHand hand;
    // this is merely a failsafe to deactivate the motors if the hand was lost
    void Update()
    {
        if (this.colliding)
        {
            if (!this.hand.IsTracked)
            {
                this.hand = null;
                this.colliding = false;
                this.controller.sendData(0, 0, 0, 0, 0);
            }
        }
    }
    // here, the actual vibrations are controlled, but only if a hand is currently colliding with the cube,
    // a setup like this scales quite well, since the communication with the controller is reduced to the max.
    // you can equip multiple objects with this script without dropping the framerate to much
    void LateUpdate()
    {
        if (this.colliding && this.hand != null)
        {
            this.processCollision();
        }
    }
    // is a hand colliding with the cube, if so is it a right hand?
    void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.GetComponentInParent<RigidHand>() != null)
        {
            if (collision.gameObject.GetComponentInParent<RigidHand>().Handedness == Chirality.Right)
            {
                this.colliding = true;
                this.hand = collision.gameObject.GetComponentInParent<RigidHand>();
            }
        }
    }
    // did the collision with our target hand end?
    void OnCollisionExit(Collision collision)
    {
        if (collision.gameObject.GetComponentInParent<RigidHand>() != null && this.hand != null)
        {
            if (collision.gameObject.GetComponentInParent<RigidHand>() == this.hand)
            {
                this.hand = null;
                this.colliding = false;
                this.controller.sendData(0, 0, 0, 0, 0);
            }
        }
    }
    // here, the fingertips of the colliding hand are retained, the distance to the
    // object center is obtained and used to scale the vibration strength
    private void processCollision()
    {
        // we put in the vibration strengths here
        int[] values = new int[] {0, 0, 0, 0, 0};
        // these are the render bounds of the object, that is the visible volume
        Bounds bounds = this.gameObject.GetComponent<Renderer>().bounds;
        // we go through the fingers...
        foreach (FingerModel finger in this.hand.fingers)
        {
            // check if it is a defined one...
            if (finger.fingerType != Finger.FingerType.TYPE_UNKNOWN)
            {
                int index = (int) finger.fingerType;
                // we get the tip...
                Vector3 tip = finger.GetTipPosition();
                if (bounds.Contains(tip))
                {
                    // calculate the distance...
                    float distance = Vector3.Distance(this.transform.position, tip) / bounds.extents.magnitude;
                    // and scale the vibration strength accordingly
                    values[index] = 255 - (int) (distance * 255);
                    if (values[index] < 0)
                    {
                        values[index] = 0;
                    }
                }
            }
        }
        // here we send the current vibration strengths
        this.controller.sendData(values[0], values[1], values[2], values[3], values[4]);
    }
}
