/* eslint env: {"jquery": 2} */

(function($) {
    $.signature = function(element, options) {

        // plugin's default options
        // this is private property and is  accessible only from inside the plugin
        var defaults = {
            lineWidth: 1,
            onData: function() {}
        };

        // to avoid confusions, use "plugin" to reference the
        // current instance of the object
        var plugin = this;

        // this will hold the merged default, and user-provided options
        // plugin's properties will be available through this object like:
        // plugin.settings.propertyName from inside the plugin or
        // element.data('signature').settings.propertyName from outside the plugin,
        // where "element" is the element the plugin is attached to;
        plugin.settings = {};

        var $element = $(element), // reference to the jQuery version of DOM element
            canvas = $element.get(0),
            context = canvas.getContext("2d"),
            result = [],
            startTime = 0,
            x_min, y_min,
            x_max, y_max;

        // the "constructor" method that gets called when the object is created
        plugin.init = function() {
            // the plugin's final properties are the merged default and
            // user-provided options (if any)
            plugin.settings = $.extend({}, defaults, options);

            clearBorders();

            context.lineWidth = plugin.settings.lineWidth;
            context.lineJoin = context.lineCap = "round";

            $element.on("mouseup mouseleave", function() {
                $(this).off("mousemove");
            });

            $element.on("touchend", function() {
                $(this).off("touchmove");
            });

            processDrawingEvents("mousedown", "mousemove", getMousePos);
            processDrawingEvents("touchstart", "touchmove", getTouchPos);
        };

        // public methods
        plugin.clear = function() {
            result = [];
            context.clearRect(0, 0, canvas.width, canvas.height);
            context.beginPath();
            clearBorders();

        };

        plugin.save = function(format) {
            if(!x_max || !y_max) return;
            var tempCanvas = document.createElement("canvas"),
                tCtx = tempCanvas.getContext("2d");
            var width = x_max - x_min;
            var height = y_max - y_min;

            // Failsafe in case there is an error in min/max values
            if (width < 1) {
                width = 160;
            }

            if (height < 1) {
                height = 100;
            }

            // Normalize image size
            if (width / height < 1.6) {
                width = height * 1.6;
            }

            tempCanvas.width = width;
            tempCanvas.height = height;
            tCtx.drawImage(canvas, x_min, y_min, width, height, 0, 0, width, height);
            var img = tempCanvas.toDataURL(format || "image/png");
            tempCanvas.remove();
            return img;
        };

        plugin.getResult = function() {
            return result;
        };

        plugin.getClearedResult = function() {
            var cleared_result = result;
            for(var i = 0; i < cleared_result.length; i++) {
                cleared_result[i].x -= (x_min - 1);
                cleared_result[i].y -= y_min;
            }
            return cleared_result;
        };

        // private methods
        var drawLine = function(x, y) {
            context.lineTo(x, y);
            context.stroke();
        };

        var getMousePos = function(e) {
            return {
                x: e.offsetX,
                y: e.offsetY,
            };
        };

        var getTouchPos = function(e) {
          var rect = canvas.getBoundingClientRect();
          var x = Math.round(e.originalEvent.touches[0].clientX - rect.left);
          var y = Math.round(e.originalEvent.touches[0].clientY - rect.top);
          return { x: x, y: y };
        }

        var saveResults = function(x, y, type) {
            startTime = startTime || $.now();
            var counter = $.now() - startTime;
            var resultObject = {x: x, y: y, t: counter, type: type};
            plugin.settings.onData(x, y, counter, type);
            result.push(resultObject);
        };

        var clearBorders = function() {
            x_max = y_max = 0;
            x_min = canvas.width;
            y_min = canvas.height;
        };

        var setBorders = function(x, y) {
            x_max = Math.max(x_max, x);
            y_max = Math.max(y_max, y);
            x_min = Math.min(x_min, x);
            y_min = Math.min(y_min, y);
        };

        var processDrawingEvents = function(startevent, moveevent, getCoords) {
            $element.on(startevent, function(e) {
              e.preventDefault();
              var pos = getCoords(e);
              context.moveTo(pos.x - 1, pos.y - 1);
              $(this).on(moveevent, function(e) {
                var pos = getCoords(e);
                drawLine(pos.x, pos.y);
                saveResults(pos.x, pos.y, 1);
                setBorders(pos.x, pos.y);
              });
              saveResults(pos.x, pos.y, 0);
            });
        };

        plugin.init();
    };

    // add the plugin to the jQuery.fn object
    $.fn.signature = function(options) {

        // iterate through the DOM elements we are attaching the plugin to
        return this.each(function() {

            // if plugin has not already been attached to the element
            if (undefined == $(this).data("signature")) {

                // create a new instance of the plugin
                // pass the DOM element and the user-provided options as arguments
                var plugin = new $.signature(this, options);

                // in the jQuery version of the element
                // store a reference to the plugin object
                // you can later access the plugin and its methods and properties like
                // element.data('signature').publicMethod(arg1, arg2, ... argn) or
                // element.data('signature').settings.propertyName
                $(this).data("signature", plugin);
            }
        });
    };
})(jQuery);
