/* For licensing terms, see /license.txt */

(function (window, $) {
    "use strict";

    function getPointOnImage(referenceElement, x, y) {
        var pointerPosition = {
                left: x + window.scrollX,
                top: y + window.scrollY
            },
            canvasOffset = {
                x: referenceElement.getBoundingClientRect().left + window.scrollX,
                y: referenceElement.getBoundingClientRect().top + window.scrollY
            };

        return {
            x: Math.round(pointerPosition.left - canvasOffset.x),
            y: Math.round(pointerPosition.top - canvasOffset.y)
        };
    }

    var SvgElementModel = function (attributes) {
        this.attributes = attributes;
        this.id = 0;
        this.name = "";

        this.changeEvent = null;
    };
    SvgElementModel.prototype.set = function (key, value) {
        this.attributes[key] = value;

        if (this.changeEvent) {
            this.changeEvent(this);
        }
    };
    SvgElementModel.prototype.get = function (key) {
        return this.attributes[key];
    };
    SvgElementModel.prototype.onChange = function (callback) {
        this.changeEvent = callback;
    };
    SvgElementModel.decode = function () {
        return new this();
    };
    SvgElementModel.prototype.encode = function () {
        return "";
    };

    var SvgPathModel = function (attributes) {
        SvgElementModel.call(this, attributes);
    };
    SvgPathModel.prototype = Object.create(SvgElementModel.prototype);
    SvgPathModel.prototype.addPoint = function (x, y) {
        x = parseInt(x);
        y = parseInt(y);

        var points = this.get("points");
        points.push([x, y]);

        this.set("points", points);
    };
    SvgPathModel.prototype.encode = function () {
        var pairedPoints = [];

        this.get("points").forEach(function (point) {
            pairedPoints.push(
                point.join(";")
            );
        });

        return "P)(" + pairedPoints.join(")(");
    };
    SvgPathModel.decode = function (pathInfo) {
        var points = [];

        $(pathInfo).each(function (i, point) {
            points.push([point.x, point.y]);
        });

        return new SvgPathModel({points: points});
    };

    var TextModel = function (userAttributes) {
        var attributes = $.extend({
            text: "",
            x: 0,
            y: 0,
            color: "red",
            fontSize: 20
        }, userAttributes);

        SvgElementModel.call(this, attributes);
    };
    TextModel.prototype = Object.create(SvgElementModel.prototype);
    TextModel.prototype.encode = function () {
        return "T)(" + this.get("text") + ")(" + this.get("x") + ";" + this.get("y");
    };
    TextModel.decode = function (textInfo) {
        return new TextModel({
            text: textInfo.text,
            x: textInfo.x,
            y: textInfo.y
        });
    };

    var SvgPathView = function (model) {
        var self = this;

        this.model = model;
        this.model.onChange(function () {
            self.render();
        });

        this.el = document.createElementNS("http://www.w3.org/2000/svg", "path");
        this.el.setAttribute("fill", "transparent");
        this.el.setAttribute("stroke", "red");
        this.el.setAttribute("stroke-width", "3");
    };
    SvgPathView.prototype.render = function () {
        var d = "";

        $.each(
            this.model.get("points"),
            function (i, point) {
                d += (i === 0) ? "M" : " L ";
                d += point[0] + " " + point[1];
            }
        );

        this.el.setAttribute("d", d);

        return this;
    };

    var TextView = function (model) {
        var self = this;

        this.model = model;
        this.model.onChange(function () {
            self.render();
        });

        this.el = document.createElementNS('http://www.w3.org/2000/svg', 'text');
        this.el.setAttribute('fill', this.model.get('color'));
        this.el.setAttribute('font-size', this.model.get('fontSize'));
        this.el.setAttribute('stroke', 'none');
    };
    TextView.prototype.render = function () {
        this.el.setAttribute('x', this.model.get('x'));
        this.el.setAttribute('y', this.model.get('y'));
        this.el.textContent = this.model.get('text');

        return this;
    };

    var ElementsCollection = function () {
        this.models = [];
        this.length = 0;
        this.addEvent = null;
    };
    ElementsCollection.prototype.add = function (pathModel) {
        pathModel.id = ++this.length;

        this.models.push(pathModel);

        if (this.addEvent) {
            this.addEvent(pathModel);
        }
    };
    ElementsCollection.prototype.get = function (index) {
        return this.models[index];
    };
    ElementsCollection.prototype.onAdd = function (callback) {
        this.addEvent = callback;
    };

    var AnnotationCanvasView = function (elementsCollection, image, questionId) {
        var self = this;

        this.questionId = parseInt(questionId);
        this.image = image;

        this.el = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
        this.el.setAttribute('version', '1.1');
        this.el.setAttribute('viewBox', '0 0 ' + this.image.width + ' ' + this.image.height);
        this.el.setAttribute('width', this.image.width);
        this.el.setAttribute('height', this.image.height);

        var svgImage = document.createElementNS('http://www.w3.org/2000/svg', 'image');
        svgImage.setAttributeNS('http://www.w3.org/1999/xlink', 'href', this.image.src);
        svgImage.setAttribute('width', this.image.width);
        svgImage.setAttribute('height', this.image.height);

        this.el.appendChild(svgImage);

        this.$el = $(this.el);

        this.elementsCollection = elementsCollection;
        this.elementsCollection.onAdd(function (pathModel) {
            self.renderElement(pathModel);
        });

        this.$rdbOptions = null;
    };
    AnnotationCanvasView.prototype.render = function () {
        this.setEvents();

        this.$rdbOptions = $('[name="' + this.questionId + '-options"]');

        return this;
    };
    AnnotationCanvasView.prototype.setEvents = function () {
        var self = this;

        var isMoving = false,
            elementModel = null;

        self.$el
            .on('dragstart', function (e) {
                e.preventDefault();
            })
            .on('click', function (e) {
                e.preventDefault();

                if ("1" !== self.$rdbOptions.filter(':checked').val()) {
                    return;
                }

                var point = getPointOnImage(self.el, e.clientX, e.clientY);
                elementModel = new TextModel({x: point.x, y: point.y, text: ''});
                self.elementsCollection.add(elementModel);
                elementModel = null;
                isMoving = false;
            })
            .on('mousedown', function (e) {
                e.preventDefault();

                var point = getPointOnImage(self.el, e.clientX, e.clientY);
                if (isMoving || "0" !== self.$rdbOptions.filter(':checked').val() || elementModel) {
                    return;
                }

                elementModel = new SvgPathModel({points: [[point.x, point.y]]});
                self.elementsCollection.add(elementModel);
                isMoving = true;
            })
            .on('mousemove', function (e) {
                e.preventDefault();

                if (!isMoving || "0" !== self.$rdbOptions.filter(':checked').val() || !elementModel) {
                    return;
                }

                var point = getPointOnImage(self.el, e.clientX, e.clientY);
                elementModel.addPoint(point.x, point.y);
            })
            .on('mouseup', function (e) {
                e.preventDefault();

                if (!isMoving || "0" !== self.$rdbOptions.filter(':checked').val() || !elementModel) {
                    return;
                }

                elementModel = null;
                isMoving = false;
            });
    };
    AnnotationCanvasView.prototype.renderElement = function (elementModel) {
        var elementView = null,
            self = this;

        if (elementModel instanceof SvgPathModel) {
            elementView = new SvgPathView(elementModel);
        } else if (elementModel instanceof TextModel) {
            elementView = new TextView(elementModel);
        }

        if (!elementView) {
            return;
        }

        $('<input>')
            .attr({
                type: 'hidden',
                name: 'choice[' + this.questionId + '][' + elementModel.id + ']'
            })
            .val(elementModel.encode())
            .appendTo(this.el.parentNode);

        $('<input>')
            .attr({
                type: 'hidden',
                name: 'hotspot[' + this.questionId + '][' + elementModel.id + ']'
            })
            .val(elementModel.encode())
            .appendTo(this.el.parentNode);

        this.el.appendChild(elementView.render().el);

        elementModel.onChange(function () {
            elementView.render();

            $('input[name="choice[' + self.questionId + '][' + elementModel.id + ']"]').val(elementModel.encode());
            $('input[name="hotspot[' + self.questionId + '][' + elementModel.id + ']"]').val(elementModel.encode());
        });

        if (elementModel instanceof TextModel) {
            $('<input>')
                .attr({
                    type: 'text',
                    name: 'text[' + this.questionId + '][' + elementModel.id + ']'
                })
                .addClass('form-control input-sm')
                .on('change', function (e) {
                    elementModel.set('text', this.value);

                    e.preventDefault();
                })
                .val(elementModel.get('text'))
                .appendTo('#annotation-toolbar-' + this.questionId + ' ul')
                .wrap('<li class="form-group"></li>')
                .focus();
        }
    };

    window.AnnotationQuestion = function (userSettings) {
        $(function () {
            var settings = $.extend(
                {
                    questionId: 0,
                    exerciseId: 0,
                    relPath: '/'
                },
                userSettings
            ),
            xhrUrl = 'exercise/annotation_user.php?' + _p.web_cid_query,
            $container = $('#annotation-canvas-' + settings.questionId);
            $.getJSON(settings.relPath + xhrUrl, {
                question_id: parseInt(settings.questionId),
                exe_id: parseInt(settings.exerciseId),
                course_id: parseInt(settings.courseId)
            })
            .done(function (questionInfo) {
                var image = new Image();
                image.onload = function () {
                    var elementsCollection = new ElementsCollection(),
                        canvas = new AnnotationCanvasView(elementsCollection, this, settings.questionId);

                    $container.html(canvas.render().el);

                    /** @namespace questionInfo.answers.paths */
                    $.each(questionInfo.answers.paths, function (i, pathInfo) {
                        var pathModel = SvgPathModel.decode(pathInfo);
                        elementsCollection.add(pathModel);
                    });

                    /** @namespace questionInfo.answers.texts */
                    $(questionInfo.answers.texts).each(function (i, textInfo) {
                        var textModel = TextModel.decode(textInfo);
                        elementsCollection.add(textModel);
                    });
                };
                image.src = questionInfo.image.path;
            });
        });
    };
})(window, window.jQuery);
