//
//  markerTipEntityScript.js
//  examples/homeContent/markerTipEntityScript
//
//  Created by Eric Levin on 2/17/15.
//  Copyright 2016 High Fidelity, Inc.
//
//  This script provides the logic for an object to draw marker strokes on its associated whiteboard

//  Distributed under the Apache License, Version 2.0.
//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html



(function() {
    Script.include("../../libraries/utils.js");
    var TRIGGER_CONTROLS = [
        Controller.Standard.LT,
        Controller.Standard.RT,
    ];
    var MAX_POINTS_PER_STROKE = 40;
    var _this;
    MarkerTip = function() {
        _this = this;
        _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png";
        _this.strokeForwardOffset = 0.0001;
        _this.STROKE_WIDTH_RANGE = {
            min: 0.002,
            max: 0.01
        };
        _this.MAX_MARKER_TO_BOARD_DISTANCE = 1.4;
        _this.MIN_DISTANCE_BETWEEN_POINTS = 0.002;
        _this.MAX_DISTANCE_BETWEEN_POINTS = 0.1;
        _this.strokes = [];
        _this.PAINTING_TRIGGER_THRESHOLD = 0.2;
        _this.STROKE_NAME = "hifi-marker-stroke";
        _this.WHITEBOARD_SURFACE_NAME = "hifi-whiteboardDrawingSurface";
        _this.MARKER_RESET_WAIT_TIME = 3000;
    };

    MarkerTip.prototype = {

        startEquip: function(id, params) {
            _this.whiteboards = [];
            _this.equipped = true;
            _this.hand = params[0] == "left" ? 0 : 1;
            _this.markerColor = getEntityUserData(_this.entityID).markerColor;
            // search for whiteboards
            var markerPosition = Entities.getEntityProperties(_this.entityID, "position").position;
            var entities = Entities.findEntities(markerPosition, 10);
            entities.forEach(function(entity) {
                var entityName = Entities.getEntityProperties(entity, "name").name;
                if (entityName === _this.WHITEBOARD_SURFACE_NAME) {

                    _this.whiteboards.push(entity);
                }
            });

            print("intersectable entities " + JSON.stringify(_this.whiteboards))
        },

        releaseEquip: function() {
            _this.resetStroke();
            Overlays.editOverlay(_this.laserPointer, {
                visible: false
            });

            // Once user releases marker, wait a bit then put marker back to its original position and rotation
            Script.setTimeout(function() {
                var userData = getEntityUserData(_this.entityID);
                Entities.editEntity(_this.entityID, {
                    position: userData.originalPosition,
                    rotation: userData.originalRotation,
                    velocity: {
                        x: 0,
                        y: -0.01,
                        z: 0
                    }
                });
            }, _this.MARKER_RESET_WAIT_TIME);
        },


        continueEquip: function() {
            // cast a ray from marker and see if it hits anything
            var markerProps = Entities.getEntityProperties(_this.entityID, ["position", "rotation"]);

            var pickRay = {
                origin: markerProps.position,
                direction: Quat.getFront(markerProps.rotation)
            }
            var intersection = Entities.findRayIntersectionBlocking(pickRay, true, _this.whiteboards);

            if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) {
                _this.currentWhiteboard = intersection.entityID;
                var whiteboardRotation = Entities.getEntityProperties(_this.currentWhiteboard, "rotation").rotation;
                _this.whiteboardNormal = Quat.getFront(whiteboardRotation);
                Overlays.editOverlay(_this.laserPointer, {
                    visible: true,
                    position: intersection.intersection,
                    rotation: whiteboardRotation
                })
                _this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]);
                if (_this.triggerValue > _this.PAINTING_TRIGGER_THRESHOLD) {
                    _this.paint(intersection.intersection)
                } else {
                    _this.resetStroke();
                }
            } else {
                if (_this.currentStroke) {
                    _this.resetStroke();
                }

                Overlays.editOverlay(_this.laserPointer, {
                    visible: false
                });
            }

        },

        newStroke: function(position) {
            _this.strokeBasePosition = position;
            _this.currentStroke = Entities.addEntity({
                type: "PolyLine",
                name: _this.STROKE_NAME,
                dimensions: {
                    x: 10,
                    y: 10,
                    z: 10
                },
                position: position,
                textures: _this.MARKER_TEXTURE_URL,
                color: _this.markerColor,
                lifetime: 5000,
            });

            _this.linePoints = [];
            _this.normals = [];
            _this.strokes.push(_this.currentStroke);
        },

        paint: function(position) {
            var basePosition = position;
            if (!_this.currentStroke) {
                if (_this.oldPosition) {
                    basePosition = _this.oldPosition;
                }
                _this.newStroke(basePosition);
            }

            var localPoint = Vec3.subtract(basePosition, _this.strokeBasePosition);
            localPoint = Vec3.sum(localPoint, Vec3.multiply(_this.whiteboardNormal, _this.strokeForwardOffset));

            if (_this.linePoints.length > 0) {
                var distance = Vec3.distance(localPoint, _this.linePoints[_this.linePoints.length - 1]);
                if (distance < _this.MIN_DISTANCE_BETWEEN_POINTS) {
                    return;
                }
            }
            _this.linePoints.push(localPoint);
            _this.normals.push(_this.whiteboardNormal);

            var strokeWidths = [];
            for (var i = 0; i < _this.linePoints.length; i++) {
                // Create a temp array of stroke widths for calligraphy effect - start and end should be less wide
                var pointsFromCenter = Math.abs(_this.linePoints.length / 2 - i);
                var pointWidth = map(pointsFromCenter, 0, this.linePoints.length / 2, _this.STROKE_WIDTH_RANGE.max, this.STROKE_WIDTH_RANGE.min);
                strokeWidths.push(pointWidth);
            }

            Entities.editEntity(_this.currentStroke, {
                linePoints: _this.linePoints,
                normals: _this.normals,
                strokeWidths: strokeWidths
            });

            if (_this.linePoints.length > MAX_POINTS_PER_STROKE) {
                Entities.editEntity(_this.currentStroke, {
                    parentID: _this.currentWhiteboard
                });
                _this.currentStroke = null;
                _this.oldPosition = position;
            }
        },
        resetStroke: function() {

            Entities.editEntity(_this.currentStroke, {
                parentID: _this.currentWhiteboard
            });
            _this.currentStroke = null;

            _this.oldPosition = null;
        },

        preload: function(entityID) {
            this.entityID = entityID;
            _this.laserPointer = Overlays.addOverlay("circle3d", {
                color: {
                    red: 220,
                    green: 35,
                    blue: 53
                },
                solid: true,
                size: 0.01,
            });

        },

        unload: function() {
            Overlays.deleteOverlay(_this.laserPointer);
            _this.strokes.forEach(function(stroke) {
                Entities.deleteEntity(stroke);
            });
        }
    };

    // entity scripts always need to return a newly constructed object of our type
    return new MarkerTip();
});