<commit_before>/**
 * @class Oskari.mapframework.ui.module.common.mapmodule.DrawPlugin
 */
Oskari.clazz.define('Oskari.mapframework.ui.module.common.mapmodule.DrawPlugin', function (config) {
    this.mapModule = null;
    this.pluginName = null;
    this._sandbox = null;
    this._map = null;
    this.drawControls = null;
    this.drawLayer = null;
    this.editMode = false;
    this.currentDrawMode = null;
    this.prefix = "DrawPlugin.";

    if (config && config.id) {
        // Note that the events and requests need to match the configured prefix based on the id!
        this.prefix = config.id + ".";
    }
    // graphicFill, instance
    if (config && config.graphicFill) {
        this.graphicFill = config.graphicFill;
    }
    this.multipart = (config && config.multipart === true);
}, {
    __name: 'DrawPlugin',

    getName: function () {
        return this.prefix + this.pluginName;
    },
    getMapModule: function () {
        return this.mapModule;
    },
    setMapModule: function (mapModule) {
        this.mapModule = mapModule;
        this._map = mapModule.getMap();
        this.pluginName = mapModule.getName() + this.__name;
    },
    /**
     * Enables the draw control for given params.drawMode.
     * Clears the layer of any previously drawn features.
     * TODO: draws the given params.geometry with params.style
     * @param params includes drawMode, geometry and style
     * @method
     */
    startDrawing: function (params) {
        if (params.isModify) {
            // preselect it for modification
            this.modifyControls.select.select(this.drawLayer.features[0]);
        } else {
            // remove possible old drawing
            this.drawLayer.destroyFeatures();
            if (params.geometry) {
                // sent existing geometry == edit mode
                this.editMode = true;
                // add feature to draw layer
                var features = [new OpenLayers.Feature.Vector(params.geometry)];
                this.drawLayer.addFeatures(features);
                // preselect it for modification
                this.modifyControls.select.select(this.drawLayer.features[0]);
            } else {
                // otherwise activate requested draw control for new geometry
                this.editMode = false;
                this.toggleControl(params.drawMode);
            }
        }

    },
    /**
     * Disables all draw controls and
     * clears the layer of any drawn features
     * @method
     */
    stopDrawing: function () {
        // disable all draw controls
        this.toggleControl();
        // clear drawing
        if (this.drawLayer) this.drawLayer.destroyFeatures();
    },

    forceFinishDraw: function () {
        try {
            //needed when preparing unfinished objects but causes unwanted features into the layer:
            //this.drawControls[this.currentDrawMode].finishSketch();
            this.finishedDrawing(true);
        } catch (error) {
            // happens when the sketch isn't even started -> reset state
            this.stopDrawing();
            var event = this._sandbox.getEventBuilder('DrawPlugin.SelectedDrawingEvent')();
            this._sandbox.notifyAll(event);
        }
    },

    /**
     * Called when drawing is finished.
     * Disables all draw controls and
     * sends a '[this.prefix] + FinishedDrawingEvent' with the drawn the geometry.
     * @method
     */
    finishedDrawing: function (isForced) {
        if (!this.multipart || isForced) {
            // not a multipart, stop editing
            var activeControls = this._getActiveDrawControls(),
                i,
                components;
            for (i = 0; i < activeControls.length; i++) {
                // only lines and polygons have the finishGeometry function
                if (typeof this.drawControls[activeControls[i]].handler.finishGeometry === typeof Function) {
                    // No need to finish geometry if already finished
                    switch (activeControls[i]) {
                    case "line":
                        if (this.drawControls.line.handler.line.geometry.components.length < 2) {
                            continue;
                        }
                        break;
                    case "area":
                        components = this.drawControls.area.handler.polygon.geometry.components;
                        if (components[components.length - 1].components.length < 3) {
                            continue;
                        }
                        break;
                    }
                    this.drawControls[activeControls[i]].handler.finishGeometry();
                }
            }
            this.toggleControl();
        }

        if (!this.editMode) {
            // programmatically select the drawn feature ("not really supported by openlayers")
            // http://lists.osgeo.org/pipermail/openlayers-users/2009-February/010601.html
            var lastIndex = this.drawLayer.features.length - 1;
            this.modifyControls.select.select(this.drawLayer.features[lastIndex]);
        }

        var event;
        if (!this.multipart || isForced) {
            event = this._sandbox.getEventBuilder('DrawPlugin.FinishedDrawingEvent')(this.getDrawing(), this.editMode);
            this._sandbox.notifyAll(event);
        } else {
            event = this._sandbox.getEventBuilder('DrawPlugin.AddedFeatureEvent')(this.getDrawing(), this.currentDrawMode);
            this._sandbox.notifyAll(event);
        }
    },
    /**
     * Enables the given draw control
     * Disables all the other draw controls
     * @param drawMode draw control to activate (if undefined, disables all
     * controls)
     * @method
     */
    toggleControl: function (drawMode) {
        this.currentDrawMode = drawMode;
        var key, control, activeDrawing, event;

        for (key in this.drawControls) {
            if (this.drawControls.hasOwnProperty(key)) {
                control = this.drawControls[key];
                if (drawMode === key) {
                    control.activate();
                } else {
                    control.deactivate();
                }
            }
        }
    },
    /**
     * Initializes the plugin:
     * - layer that is used for drawing
     * - drawControls
     * - registers for listening to requests
     * @param sandbox reference to Oskari sandbox
     * @method
     */
    init: function (sandbox) {
        var me = this;
        this.requestHandlers = {
            startDrawingHandler: Oskari.clazz.create('Oskari.mapframework.ui.module.common.mapmodule.DrawPlugin.request.StartDrawingRequestPluginHandler', sandbox, me),
            stopDrawingHandler: Oskari.clazz.create('Oskari.mapframework.ui.module.common.mapmodule.DrawPlugin.request.StopDrawingRequestPluginHandler', sandbox, me),
            getGeometryHandler: Oskari.clazz.create('Oskari.mapframework.ui.module.common.mapmodule.DrawPlugin.request.GetGeometryRequestPluginHandler', sandbox, me)
        };

        this.drawLayer = new OpenLayers.Layer.Vector(this.prefix + "DrawLayer", {
            /*style: {
             strokeColor: "#ff00ff",
             strokeWidth: 3,
             fillOpacity: 0,
             cursor: "pointer"
             },*/
            eventListeners: {
                "featuresadded": function (layer) {
                    // send an event that the drawing has been completed
                    me.finishedDrawing();
                },
                'vertexmodified': function (event) {
                    me._sendActiveGeometry(me.getDrawing());
                }
            }
        });

        this.drawControls = {
            point: new OpenLayers.Control.DrawFeature(me.drawLayer,
                OpenLayers.Handler.Point),
            line: new OpenLayers.Control.DrawFeature(me.drawLayer,
                OpenLayers.Handler.Path, {
                    callbacks: {
                        modify: function (geom, feature) {
                            me._sendActiveGeometry(me.getActiveDrawing(feature.geometry), 'line');
                        }
                    }
                }),
            area: new OpenLayers.Control.DrawFeature(me.drawLayer,
                OpenLayers.Handler.Polygon, {
                    handlerOptions: {
                        holeModifier: "altKey"
                    },
                    callbacks: {
                        modify: function (geom, feature) {
                            me._sendActiveGeometry(me.getActiveDrawing(feature.geometry), 'area');
                        }
                    }
                }),
            /*cut : new OpenLayers.Control.DrawFeature(me.drawLayer,
                                                      OpenLayers.Handler.Polygon,
                                                      {handlerOptions:{drawingHole: true}}),*/
            box: new OpenLayers.Control.DrawFeature(me.drawLayer,
                OpenLayers.Handler.RegularPolygon, {
                    handlerOptions: {
                        sides: 4,
                        irregular: true
                    }
                })
        };

        if (this.graphicFill !== null && this.graphicFill !== undefined) {
            var str = this.graphicFill;
            var format = new OpenLayers.Format.SLD();
            var obj = format.read(str),
                p;
            if (obj && obj.namedLayers) {
                for (p in obj.namedLayers) {
                    if (obj.namedLayers.hasOwnProperty(p)) {
                        this.drawLayer.styleMap.styles["default"] = obj.namedLayers[p].userStyles[0];
                        this.drawLayer.redraw();
                        break;
                    }
                }
            }
        }

        // doesn't really need to be in array, but lets keep it for future development
        this.modifyControls = {
            modify: new OpenLayers.Control.ModifyFeature(me.drawLayer, {
                standalone: true
            })
        };
        this.modifyControls.select = new OpenLayers.Control.SelectFeature(me.drawLayer, {
            onBeforeSelect: this.modifyControls.modify.beforeSelectFeature,
            onSelect: this.modifyControls.modify.selectFeature,
            onUnselect: this.modifyControls.modify.unselectFeature,
            scope: this.modifyControls.modify
        });

        this._map.addLayers([me.drawLayer]);
        var key;
        for (key in this.drawControls) {
            if (this.drawControls.hasOwnProperty(key)) {
                this._map.addControl(this.drawControls[key]);
            }
        }
        for (key in this.modifyControls) {
            if (this.modifyControls.hasOwnProperty(key)) {
                this._map.addControl(this.modifyControls[key]);
            }
        }
        // no harm in activating straight away
        this.modifyControls.modify.activate();
    },
    /**
     * Returns the drawn geometry from the draw layer
     * @method
     */
    getDrawing: function () {
        if (this.drawLayer.features.length === 0) {
            return null;
        }
        var featClass = this.drawLayer.features[0].geometry.CLASS_NAME;
        if ((featClass === "OpenLayers.Geometry.MultiPoint") ||
            (featClass === "OpenLayers.Geometry.MultiLineString") ||
            (featClass === "OpenLayers.Geometry.MultiPolygon")) {
            return this.drawLayer.features[0].geometry;
        }

        var drawing = null;
        var components = [],
            i;
        for (i = 0; i < this.drawLayer.features.length; i++) {
            components.push(this.drawLayer.features[i].geometry);
        }
        switch (featClass) {
        case "OpenLayers.Geometry.Point":
            drawing = new OpenLayers.Geometry.MultiPoint(components);
            break;
        case "OpenLayers.Geometry.LineString":
            drawing = new OpenLayers.Geometry.MultiLineString(components);
            break;
        case "OpenLayers.Geometry.Polygon":
            drawing = new OpenLayers.Geometry.MultiPolygon(components);
            break;
        }
        return drawing;
    },

    /**
     * Clones the drawing on the map and adds the geometry
     * currently being drawn to it.
     *
     * @method getActiveDrawing
     * @param  {OpenLayers.Geometry} geometry
     * @return {OpenLayers.Geometry}
     */
    getActiveDrawing: function (geometry) {
        var prevGeom = this.getDrawing(),
            composedGeom;

        if (prevGeom !== null && prevGeom !== undefined) {
            composedGeom = prevGeom.clone();
            composedGeom.addComponent(geometry);
            return composedGeom;
        }
        return geometry;
    },

    /**
     * Returns active draw control names
     * @method
     */
    _getActiveDrawControls: function () {
        var activeDrawControls = [],
            drawControl;
        for (drawControl in this.drawControls) {
            if (this.drawControls.hasOwnProperty(drawControl)) {
                if (this.drawControls[drawControl].active) {
                    activeDrawControls.push(drawControl);
                }
            }
        }
        return activeDrawControls;
    },

    _sendActiveGeometry: function (geometry, drawMode) {
        var eventBuilder = this._sandbox.getEventBuilder('DrawPlugin.ActiveDrawingEvent'),
            event, featClass;

        if (drawMode === null || drawMode === undefined) {
            featClass = geometry.CLASS_NAME;
            switch (featClass) {
            case "OpenLayers.Geometry.LineString":
            case "OpenLayers.Geometry.MultiLineString":
                drawMode = 'line';
                break;
            case "OpenLayers.Geometry.Polygon":
            case "OpenLayers.Geometry.MultiPolygon":
                drawMode = 'area';
                break;
            default:
                return;
            }
        }

        if (eventBuilder) {
            event = eventBuilder(geometry, drawMode);
            this._sandbox.notifyAll(event);
        }
    },

    register: function () {

    },
    unregister: function () {},
    startPlugin: function (sandbox) {
        this._sandbox = sandbox;

        sandbox.register(this);
        sandbox.addRequestHandler('DrawPlugin.StartDrawingRequest', this.requestHandlers.startDrawingHandler);
        sandbox.addRequestHandler('DrawPlugin.StopDrawingRequest', this.requestHandlers.stopDrawingHandler);
        sandbox.addRequestHandler('DrawPlugin.GetGeometryRequest', this.requestHandlers.getGeometryHandler);

    },
    stopPlugin: function (sandbox) {

        sandbox.removeRequestHandler('DrawPlugin.StartDrawingRequest', this.requestHandlers.startDrawingHandler);
        sandbox.removeRequestHandler('DrawPlugin.StopDrawingRequest', this.requestHandlers.stopDrawingHandler);
        sandbox.removeRequestHandler('DrawPlugin.GetGeometryRequest', this.requestHandlers.getGeometryHandler);
        sandbox.unregister(this);

        this._map = null;
        this._sandbox = null;
    },
    /* @method start
     * called from sandbox
     */
    start: function (sandbox) {},
    /**
     * @method stop
     * called from sandbox
     *
     */
    stop: function (sandbox) {}
}, {
    'protocol': ["Oskari.mapframework.module.Module", "Oskari.mapframework.ui.module.common.mapmodule.Plugin"]
});
<commit_msg>[AH-1230] Ignore icomplete polygons<commit_after>/**
 * @class Oskari.mapframework.ui.module.common.mapmodule.DrawPlugin
 */
Oskari.clazz.define('Oskari.mapframework.ui.module.common.mapmodule.DrawPlugin', function (config) {
    this.mapModule = null;
    this.pluginName = null;
    this._sandbox = null;
    this._map = null;
    this.drawControls = null;
    this.drawLayer = null;
    this.editMode = false;
    this.currentDrawMode = null;
    this.prefix = "DrawPlugin.";

    if (config && config.id) {
        // Note that the events and requests need to match the configured prefix based on the id!
        this.prefix = config.id + ".";
    }
    // graphicFill, instance
    if (config && config.graphicFill) {
        this.graphicFill = config.graphicFill;
    }
    this.multipart = (config && config.multipart === true);
}, {
    __name: 'DrawPlugin',

    getName: function () {
        return this.prefix + this.pluginName;
    },
    getMapModule: function () {
        return this.mapModule;
    },
    setMapModule: function (mapModule) {
        this.mapModule = mapModule;
        this._map = mapModule.getMap();
        this.pluginName = mapModule.getName() + this.__name;
    },
    /**
     * Enables the draw control for given params.drawMode.
     * Clears the layer of any previously drawn features.
     * TODO: draws the given params.geometry with params.style
     * @param params includes drawMode, geometry and style
     * @method
     */
    startDrawing: function (params) {
        if (params.isModify) {
            // preselect it for modification
            this.modifyControls.select.select(this.drawLayer.features[0]);
        } else {
            // remove possible old drawing
            this.drawLayer.destroyFeatures();
            if (params.geometry) {
                // sent existing geometry == edit mode
                this.editMode = true;
                // add feature to draw layer
                var features = [new OpenLayers.Feature.Vector(params.geometry)];
                this.drawLayer.addFeatures(features);
                // preselect it for modification
                this.modifyControls.select.select(this.drawLayer.features[0]);
            } else {
                // otherwise activate requested draw control for new geometry
                this.editMode = false;
                this.toggleControl(params.drawMode);
            }
        }

    },
    /**
     * Disables all draw controls and
     * clears the layer of any drawn features
     * @method
     */
    stopDrawing: function () {
        // disable all draw controls
        this.toggleControl();
        // clear drawing
        if (this.drawLayer) this.drawLayer.destroyFeatures();
    },

    forceFinishDraw: function () {
        try {
            //needed when preparing unfinished objects but causes unwanted features into the layer:
            //this.drawControls[this.currentDrawMode].finishSketch();
            this.finishedDrawing(true);
        } catch (error) {
            // happens when the sketch isn't even started -> reset state
            this.stopDrawing();
            var event = this._sandbox.getEventBuilder('DrawPlugin.SelectedDrawingEvent')();
            this._sandbox.notifyAll(event);
        }
    },

    /**
     * Called when drawing is finished.
     * Disables all draw controls and
     * sends a '[this.prefix] + FinishedDrawingEvent' with the drawn the geometry.
     * @method
     */
    finishedDrawing: function (isForced) {
        if (!this.multipart || isForced) {
            // not a multipart, stop editing
            var activeControls = this._getActiveDrawControls(),
                i,
                components;
            for (i = 0; i < activeControls.length; i++) {
                // only lines and polygons have the finishGeometry function
                if (typeof this.drawControls[activeControls[i]].handler.finishGeometry === typeof Function) {
                    // No need to finish geometry if already finished
                    switch (activeControls[i]) {
                    case "line":
                        if (this.drawControls.line.handler.line.geometry.components.length < 2) {
                            continue;
                        }
                        break;
                    case "area":
                        components = this.drawControls.area.handler.polygon.geometry.components;
                        if (components[components.length - 1].components.length < 3) {
                            continue;
                        }
                        break;
                    }
                    this.drawControls[activeControls[i]].handler.finishGeometry();
                }
            }
            this.toggleControl();
        }

        if (!this.editMode) {
            // programmatically select the drawn feature ("not really supported by openlayers")
            // http://lists.osgeo.org/pipermail/openlayers-users/2009-February/010601.html
            var lastIndex = this.drawLayer.features.length - 1;
            this.modifyControls.select.select(this.drawLayer.features[lastIndex]);
        }

        var event;
        if (!this.multipart || isForced) {
            event = this._sandbox.getEventBuilder('DrawPlugin.FinishedDrawingEvent')(this.getDrawing(), this.editMode);
            this._sandbox.notifyAll(event);
        } else {
            event = this._sandbox.getEventBuilder('DrawPlugin.AddedFeatureEvent')(this.getDrawing(), this.currentDrawMode);
            this._sandbox.notifyAll(event);
        }
    },
    /**
     * Enables the given draw control
     * Disables all the other draw controls
     * @param drawMode draw control to activate (if undefined, disables all
     * controls)
     * @method
     */
    toggleControl: function (drawMode) {
        this.currentDrawMode = drawMode;
        var key, control, activeDrawing, event;

        for (key in this.drawControls) {
            if (this.drawControls.hasOwnProperty(key)) {
                control = this.drawControls[key];
                if (drawMode === key) {
                    control.activate();
                } else {
                    control.deactivate();
                }
            }
        }
    },
    /**
     * Initializes the plugin:
     * - layer that is used for drawing
     * - drawControls
     * - registers for listening to requests
     * @param sandbox reference to Oskari sandbox
     * @method
     */
    init: function (sandbox) {
        var me = this;
        this.requestHandlers = {
            startDrawingHandler: Oskari.clazz.create('Oskari.mapframework.ui.module.common.mapmodule.DrawPlugin.request.StartDrawingRequestPluginHandler', sandbox, me),
            stopDrawingHandler: Oskari.clazz.create('Oskari.mapframework.ui.module.common.mapmodule.DrawPlugin.request.StopDrawingRequestPluginHandler', sandbox, me),
            getGeometryHandler: Oskari.clazz.create('Oskari.mapframework.ui.module.common.mapmodule.DrawPlugin.request.GetGeometryRequestPluginHandler', sandbox, me)
        };

        this.drawLayer = new OpenLayers.Layer.Vector(this.prefix + "DrawLayer", {
            /*style: {
             strokeColor: "#ff00ff",
             strokeWidth: 3,
             fillOpacity: 0,
             cursor: "pointer"
             },*/
            eventListeners: {
                "featuresadded": function (layer) {
                    // send an event that the drawing has been completed
                    me.finishedDrawing();
                },
                'vertexmodified': function (event) {
                    me._sendActiveGeometry(me.getDrawing());
                }
            }
        });

        this.drawControls = {
            point: new OpenLayers.Control.DrawFeature(me.drawLayer,
                OpenLayers.Handler.Point),
            line: new OpenLayers.Control.DrawFeature(me.drawLayer,
                OpenLayers.Handler.Path, {
                    callbacks: {
                        modify: function (geom, feature) {
                            me._sendActiveGeometry(me.getActiveDrawing(feature.geometry), 'line');
                        }
                    }
                }),
            area: new OpenLayers.Control.DrawFeature(me.drawLayer,
                OpenLayers.Handler.Polygon, {
                    handlerOptions: {
                        holeModifier: "altKey"
                    },
                    callbacks: {
                        modify: function (geom, feature) {
                            me._sendActiveGeometry(me.getActiveDrawing(feature.geometry), 'area');
                        }
                    }
                }),
            /*cut : new OpenLayers.Control.DrawFeature(me.drawLayer,
                                                      OpenLayers.Handler.Polygon,
                                                      {handlerOptions:{drawingHole: true}}),*/
            box: new OpenLayers.Control.DrawFeature(me.drawLayer,
                OpenLayers.Handler.RegularPolygon, {
                    handlerOptions: {
                        sides: 4,
                        irregular: true
                    }
                })
        };

        if (this.graphicFill !== null && this.graphicFill !== undefined) {
            var str = this.graphicFill,
                format = new OpenLayers.Format.SLD(),
                obj = format.read(str),
                p;
            if (obj && obj.namedLayers) {
                for (p in obj.namedLayers) {
                    if (obj.namedLayers.hasOwnProperty(p)) {
                        this.drawLayer.styleMap.styles["default"] = obj.namedLayers[p].userStyles[0];
                        this.drawLayer.redraw();
                        break;
                    }
                }
            }
        }

        // doesn't really need to be in array, but lets keep it for future development
        this.modifyControls = {
            modify: new OpenLayers.Control.ModifyFeature(me.drawLayer, {
                standalone: true
            })
        };
        this.modifyControls.select = new OpenLayers.Control.SelectFeature(me.drawLayer, {
            onBeforeSelect: this.modifyControls.modify.beforeSelectFeature,
            onSelect: this.modifyControls.modify.selectFeature,
            onUnselect: this.modifyControls.modify.unselectFeature,
            scope: this.modifyControls.modify
        });

        this._map.addLayers([me.drawLayer]);
        var key;
        for (key in this.drawControls) {
            if (this.drawControls.hasOwnProperty(key)) {
                this._map.addControl(this.drawControls[key]);
            }
        }
        for (key in this.modifyControls) {
            if (this.modifyControls.hasOwnProperty(key)) {
                this._map.addControl(this.modifyControls[key]);
            }
        }
        // no harm in activating straight away
        this.modifyControls.modify.activate();
    },
    /**
     * Returns the drawn geometry from the draw layer
     * @method
     */
    getDrawing: function () {
        if (this.drawLayer.features.length === 0) {
            return null;
        }
        var featClass = this.drawLayer.features[0].geometry.CLASS_NAME;
        if ((featClass === "OpenLayers.Geometry.MultiPoint") ||
            (featClass === "OpenLayers.Geometry.MultiLineString") ||
            (featClass === "OpenLayers.Geometry.MultiPolygon")) {
            return this.drawLayer.features[0].geometry;
        }
        var drawing = null,
            components = [],
            i,
            geom;
        for (i = 0; i < this.drawLayer.features.length; i++) {
            geom = this.drawLayer.features[i].geometry;
            // Remove unfinished polygons
            if (geom.CLASS_NAME === 'OpenLayers.Geometry.Polygon' && geom.components.length && geom.components[0].CLASS_NAME === 'OpenLayers.Geometry.LinearRing' && geom.components[0].components.length < 4) {
                // Unfinished poly, ignore.
            } else {
                components.push(geom);
            }
        }
        switch (featClass) {
        case "OpenLayers.Geometry.Point":
            drawing = new OpenLayers.Geometry.MultiPoint(components);
            break;
        case "OpenLayers.Geometry.LineString":
            drawing = new OpenLayers.Geometry.MultiLineString(components);
            break;
        case "OpenLayers.Geometry.Polygon":
            drawing = new OpenLayers.Geometry.MultiPolygon(components);
            break;
        }
        return drawing;
    },

    /**
     * Clones the drawing on the map and adds the geometry
     * currently being drawn to it.
     *
     * @method getActiveDrawing
     * @param  {OpenLayers.Geometry} geometry
     * @return {OpenLayers.Geometry}
     */
    getActiveDrawing: function (geometry) {
        var prevGeom = this.getDrawing(),
            composedGeom;

        if (prevGeom !== null && prevGeom !== undefined) {
            composedGeom = prevGeom.clone();
            composedGeom.addComponent(geometry);
            return composedGeom;
        }
        return geometry;
    },

    /**
     * Returns active draw control names
     * @method
     */
    _getActiveDrawControls: function () {
        var activeDrawControls = [],
            drawControl;
        for (drawControl in this.drawControls) {
            if (this.drawControls.hasOwnProperty(drawControl)) {
                if (this.drawControls[drawControl].active) {
                    activeDrawControls.push(drawControl);
                }
            }
        }
        return activeDrawControls;
    },

    _sendActiveGeometry: function (geometry, drawMode) {
        var eventBuilder = this._sandbox.getEventBuilder('DrawPlugin.ActiveDrawingEvent'),
            event,
            featClass;

        if (drawMode === null || drawMode === undefined) {
            featClass = geometry.CLASS_NAME;
            switch (featClass) {
            case "OpenLayers.Geometry.LineString":
            case "OpenLayers.Geometry.MultiLineString":
                drawMode = 'line';
                break;
            case "OpenLayers.Geometry.Polygon":
            case "OpenLayers.Geometry.MultiPolygon":
                drawMode = 'area';
                break;
            default:
                return;
            }
        }

        if (eventBuilder) {
            event = eventBuilder(geometry, drawMode);
            this._sandbox.notifyAll(event);
        }
    },

    register: function () {

    },
    unregister: function () {},
    startPlugin: function (sandbox) {
        this._sandbox = sandbox;

        sandbox.register(this);
        sandbox.addRequestHandler('DrawPlugin.StartDrawingRequest', this.requestHandlers.startDrawingHandler);
        sandbox.addRequestHandler('DrawPlugin.StopDrawingRequest', this.requestHandlers.stopDrawingHandler);
        sandbox.addRequestHandler('DrawPlugin.GetGeometryRequest', this.requestHandlers.getGeometryHandler);

    },
    stopPlugin: function (sandbox) {

        sandbox.removeRequestHandler('DrawPlugin.StartDrawingRequest', this.requestHandlers.startDrawingHandler);
        sandbox.removeRequestHandler('DrawPlugin.StopDrawingRequest', this.requestHandlers.stopDrawingHandler);
        sandbox.removeRequestHandler('DrawPlugin.GetGeometryRequest', this.requestHandlers.getGeometryHandler);
        sandbox.unregister(this);

        this._map = null;
        this._sandbox = null;
    },
    /* @method start
     * called from sandbox
     */
    start: function (sandbox) {},
    /**
     * @method stop
     * called from sandbox
     *
     */
    stop: function (sandbox) {}
}, {
    'protocol': ["Oskari.mapframework.module.Module", "Oskari.mapframework.ui.module.common.mapmodule.Plugin"]
});
<|endoftext|>


<commit_before>'use strict';

angular.module('myApp.view1', ['ngRoute'])

    .config(['$routeProvider', function ($routeProvider) {
        $routeProvider.when('/', {
            templateUrl: 'view1/view1.html',
            controller:  'View1Ctrl'
        });
    }])

    .controller('View1Ctrl', ['$scope', '$timeout', '$interval', function ($scope, $timeout, $interval) {
        function stackTrace(msg) {
            var err = new Error(msg);
            throw err.stack;
        }

        var simon = {
            states:          {
                on:        function () {
                    /* state: on */
                    this.view.gameOn    = true;
                    this.view.counterOn = true;
                    // next state
                    this._addEvent(0, this, this._setState, this.states.ready);
                    console.log('state on ran');
                },
                off:       function () {
                    /* state: off */
                    this.view.gameOn    = false;
                    this.view.strict    = false;
                    this.view.counter   = '- -';
                    this.view.counterOn = false;

                    // clean up
                    this._cleanup();

                    // set state to undefined - this is our initial state
                    this._addEvent(0, this, this._setState, undefined);
                    // stop heartbeat 100ms latter - this gives update time to process any clean up events
                    this._addEvent(100, this, this._stopHeartBeat, undefined);
                },
                ready:     function () {
                    /* state: ready */
                },
                run:       function () {
                    /* state: run */
                    this._setCounter(this.seqCount + 1);
                },
                waiting:   function () {
                    /* state: waiting */
                },
                animating: function () {
                    /* state: animating */
                    // empty marker state
                },
                playing:   function () {
                    /* state: playing */
                },
                start:     function () {
                    /* state: start */

                    // clean up
                    this._cleanup();

                    // generate a sequence
                    this._generateSequence();

                    // set start to restart - this was done to avoid code duplication as
                    // restart already dose what needed to be done to start
                    var parent = this;
                    this.failTimerID = this._addEvent(0, this, this._setState, parent.states.restart);
                },
                restart:   function () {
                    /* state: restart */
                    this.seqNum = 0;

                    // play sequence
                    var delay = this._playSequence();

                    // set state to run
                    var parent = this;
                    this._addEvent(delay, this, this._setState, parent.states.run);

                    // add event to time out if they take too long to input buttons
                    // keep event id so we can cancel it
                    this.failTimerID = this._addEvent(delay + this.inputTimeOut, this, this._setState, parent.states.failed);
                },
                failed:    function () {
                    /* state: failed */

                    // cancel any fail timer - this way it doesnt get called twice
                    if (this.failTimerID !== undefined) {
                        this._removeEvent(this.failTimerID);
                        this.failTimerID = undefined;
                    }

                    console.log('failed');
                    // player failed for some reason, we don't care why

                    var nextState = this.states.restart;
                    // if strict that's it game over / restart
                    if (this.view.strictOn) {
                        nextState = this.states.start;
                    }

                    // play animation.error
                    this.animation.play(this, this.animation.error, nextState);
                }
            }, /* end of states */
            animation:       {
                play:  function (scope, animation, nextState, prams) {
                    scope._addEvent(0, scope, scope._setState, scope.states.animating);
                    var animationTime = animation(scope, prams);
                    scope._addEvent(animationTime, scope, scope._setState, nextState);
                },
                error: function (scope) {
                    var flashTime = 300;
                    var time = 0;

                    scope.view.counter    = '! !';
                    var flashFunc = function () {
                        scope.view.counterOn = !scope.view.counterOn;
                    };

                    // tell view to flash ! !
                    for (var i = 1; i < 7; i++) {
                        scope._addEvent(time, scope, flashFunc);
                        time += flashTime;
                    }
                    return time;
                },
                win: function (scope) {
                    var spinTime = 50;
                    var time = 0;

                    var spin = ['| |', '/ /', '- -', '\\ \\'];

                    var flashFunc = function (num) {
                        scope.view.counterOn = !scope.view.counterOn;
                        scope.view.counter    = spin[num % 4];
                    };

                    // tell view to flash ! !
                    for (var i = 1; i < 101; i++) {
                        scope._addEvent(time, scope, flashFunc, i);
                        time += spinTime;
                    }
                    return time;
                },
                buttonFlash: function (scope, prams) {
                    var btn = prams;
                    var btnOn = function (btn) {
                        scope.view[btn]      = true;
                        scope.view.sndToPlay = scope.sounds[btn + 'Snd'];
                    };
                    var btnOff = function (btn) {
                        scope.view[btn]      = false;
                        scope.view.sndToPlay = undefined;
                    };

                    scope._addEvent(0, scope, btnOn, btn);
                    scope._addEvent(scope.flashTime, scope, btnOff, btn);
                    return scope.flashTime;
                }
            }, /* end of animation */
            _startHeartBeat: function () {
                // heart beat
                var parent     = this;
                var lastTick   = Date.now();
                var updateTick = function () {
                    var tick = Date.now();
                    parent._onUpdate(tick - lastTick);
                    lastTick = tick;
                };
                this.heartBeat = $interval(updateTick, 33, 0, true);
            },
            _stopHeartBeat:  function () {
                $interval.cancel(this.heartBeat);
                this.heartBeat = undefined;
            },
            _setCallback:    function (callback) {
                if (callback === undefined) {
                    stackTrace('callback undefined!');
                }
                this.callback = callback;
            },
            on:              function (callback) {
                if (callback === undefined) {
                    stackTrace('callback cannot be undefined!');
                }
                this._setCallback(callback);
                this._startHeartBeat();
                var parent = this;
                this._addEvent(0, this, this._setState, parent.states.on);
            },
            off:             function () {
                var parent = this;
                this._addEvent(0, this, this._setState, parent.states.off);
            },
            toggleStrict:    function () {
                this.view.strictOn = !this.view.strictOn;

                /* test code */
                /*
                this.seqCount = 19;
                this.seqNum = 18;
                console.log(this.sequence);
                */
            },
            _onUpdate:       function (dt) {
                this._processEvents(dt);

                // execute state
                if (this.state !== undefined) {
                    this.state();
                }
                // tell view to update
                this.callback();
            },
            _addEvent:       function (delay, scope, func, prams) {
                var id = this.events.length;
                this.events.push({id: id, scope: scope, delay: delay, func: func, prams: prams});
                return id;
            },
            _removeEvent:    function (id) {
                this.events.some(function (element, index) {
                    if (element.id === id) {
                        this.events[index] = undefined;
                        return true;
                    }
                }, this);
            },
            _removeAllEvents: function () {
                this.events = [];
            },
            _processEvents:  function (dt) {
                var marker = 'marker';
                this.events.push(marker);

                var shifted;
                do {
                    shifted = this.events.shift();
                    if (shifted !== marker && shifted !== undefined) {
                        shifted.delay -= dt;
                        if (shifted.delay <= 0) {
                            shifted.func.bind(shifted.scope)(shifted.prams);
                        } else {
                            this.events.push(shifted);
                        }
                    }
                } while (shifted !== marker);
            },
            _cleanup:        function () {
                // clear all events
                this._removeAllEvents();

                // reset view and other data
                this.view.counter   = '- -';
                this.seqCount       = 0;
                this.seqNum         = 0;
                this.difficulty     = 0;
                this.view.btnGreen  = false;
                this.view.btnRed    = false;
                this.view.btnBlue   = false;
                this.view.btnYellow = false;
                this.view.sndToPlay = undefined;
            },

            start:             function () {
                if (!this.view.gameOn) {
                    return;
                }
                console.log('starting');

                // set state to start
                var parent = this;
                this._addEvent(0, this, this._setState, parent.states.start);
            },
            _setState:         function (newState) {
                this.state = newState;
            },
            btnInput:          function (color) {
                if (this.state !== this.states.run) {
                    return;
                }
                var btn;
                var btnNum;
                if (color === 'green') {
                    btn    = 'btnGreen';
                    btnNum = 1;
                } else if (color === 'red') {
                    btn    = 'btnRed';
                    btnNum = 2;
                } else if (color === 'blue') {
                    btn    = 'btnBlue';
                    btnNum = 3;
                } else if (color === 'yellow') {
                    btn    = 'btnYellow';
                    btnNum = 4;
                }

                // play sound and light button
                this._addEvent(0, this, this._btnOn, btn);
                this._addEvent(this.btnFlashTime, this, this._btnOff, btn);

                // process input
                // good input
                var parent = this;
                if (this.sequence[this.seqNum] === btnNum) {
                    this.seqNum++;

                    /* difficulty increase */
                    if (this.seqNum === this.level_1 || this.seqNum === this.level_2 || this.seqNum === this.level_3) {
                        this.difficulty += this.diffInc;
                    }

                    /* win */
                    if (this.seqNum > 19) {
                        // cancel fail timer
                        this._removeEvent(this.failTimerID);

                        // play win animation
                        this.animation.play(this, this.animation.win, this.states.ready);
                        return;
                    }

                    //
                    if (this.seqNum > this.seqCount) {
                        console.log('this.seqNum > this.seqCount');
                        this.seqNum = 0;
                        this.seqCount++;

                        // cancel fail timer
                        this._removeEvent(this.failTimerID);

                        // play sequence
                        var delay = this._playSequence();

                        // set state to run
                        this._addEvent(delay, this, this._setState, parent.states.run);

                        // add event to time out if they take too long to input buttons
                        // keep event id so we can cancel it
                        this.failTimerID = this._addEvent(delay + this.inputTimeOut, this, this._setState, parent.states.failed);
                    }
                } else {
                    // bad input - set state to failed
                    this._addEvent(0, this, this._setState, parent.states.failed);
                }
            },
            _generateSequence: function () {
                this.sequence = [];
                for (var i = 0; i < 20; i++) {
                    var num = Math.floor(Math.random() * (5 - 1)) + 1;
                    this.sequence.push(num);
                }
            },
            // todo turn playSequence into an animation
            _playSequence:     function () {
                console.log('_playSequence');

                var delay = this.timeDelay;
                // set state to playing to prevent user actions other than on/off
                var parent = this;
                this._addEvent(0, this, this._setState, parent.states.animating);

                for (var i = 0; i < this.seqCount + 1; i++) {
                    // button on
                    this._addEvent(delay , this, this._btnOn, this._getBtn(this.sequence[i]));
                    // button off
                    this._addEvent(delay + this.btnFlashTime, this, this._btnOff, this._getBtn(this.sequence[i]));
                    delay += this.timeDelay - this.difficulty;
                }
                return delay;
            },
            _btnOn:            function (btn) {
                this.view[btn]      = true;
                this.view.sndToPlay = this.sounds[btn + 'Snd'];
            },
            _btnOff:           function (btn) {
                this.view[btn]      = false;
                this.view.sndToPlay = undefined;
            },
            _getBtn:           function (nbr) {
                switch (nbr) {
                    case 1:
                        return 'btnGreen';
                    case 2:
                        return 'btnRed';
                    case 3:
                        return 'btnBlue';
                    case 4:
                        return 'btnYellow';
                }
            },
            getSoundToPlay:  function () {
                var result          = this.view.sndToPlay;
                this.view.sndToPlay = undefined;
                return result;
            },
            _setCounter: function (value){
                value = value.toString().split('');
                if (value.length === 1){
                    value.unshift('0');
                }
                this.view.counter = value.join(' ');
            },
            view:            {
                btnGreen:  false,
                btnRed:    false,
                btnBlue:   false,
                btnYellow: false,
                sndToPlay: undefined,
                counter:   '- -',
                counterOn: false,
                strictOn:  false,
                gameOn:    false
            },
            sounds:          {
                btnGreenSnd:  'assets/sounds/simonSound1.mp3',
                btnRedSnd:    'assets/sounds/simonSound2.mp3',
                btnBlueSnd:   'assets/sounds/simonSound3.mp3',
                btnYellowSnd: 'assets/sounds/simonSound4.mp3',
            },
            events:          [],
            state:           undefined,
            sequence:        [],
            seqCount:        0,                 // end of the current rnd
            seqNum:          0,                 // how many correct buttons player has pushed
            timeDelay:       900,              // millisecond time delay between buttons
            btnFlashTime:    400,               // millisecond how long to leave a button on.
            inputTimeOut:    8000,              // time player has to input the correct sequence
            autoRestartTime: 2000,              // millisecond how long to wait before restart
            flashTime:       300,
            level_1:         5,
            level_2:         9,
            level_3:         13,
            difficulty:      0,
            diffInc:         200,
            failTimerID:     undefined,
            heartBeat:       undefined
        };
        /* end of simon */

        var onOffSwitch    = false;
        var updateView     = function () {
            $scope.onOff       = simon.view.gameOn;
            $scope.counterOn   = simon.view.counterOn;
            $scope.strictLed   = simon.view.strictOn;
            $scope.count       = simon.view.counter;
            $scope.greenBtnOn  = simon.view.btnGreen;
            $scope.redBtnOn    = simon.view.btnRed;
            $scope.blueBtnOn   = simon.view.btnBlue;
            $scope.yellowBtnOn = simon.view.btnYellow;

            var sndToPlay = simon.getSoundToPlay();
            if (sndToPlay !== undefined) {
                var audio = new Audio(sndToPlay);
                audio.play();
            }
            //$scope.$apply();
        };
        $scope.switchClick = function () {
            onOffSwitch = !onOffSwitch;
            if (onOffSwitch) {
                simon.on(updateView);
            } else {
                simon.off();
            }
        };
        $scope.strictClick = function () {
            simon.toggleStrict();
        };
        $scope.btnPress    = function (color) {
            simon.btnInput(color);
        };
        $scope.startBtn    = function () {
            simon.start();
        };
        updateView();

    }]);<commit_msg>updated btnInput to use buttonFlash animation<commit_after>'use strict';

angular.module('myApp.view1', ['ngRoute'])

    .config(['$routeProvider', function ($routeProvider) {
        $routeProvider.when('/', {
            templateUrl: 'view1/view1.html',
            controller:  'View1Ctrl'
        });
    }])

    .controller('View1Ctrl', ['$scope', '$timeout', '$interval', function ($scope, $timeout, $interval) {
        function stackTrace(msg) {
            var err = new Error(msg);
            throw err.stack;
        }

        var simon = {
            states:          {
                on:        function () {
                    /* state: on */
                    this.view.gameOn    = true;
                    this.view.counterOn = true;
                    // next state
                    this._addEvent(0, this, this._setState, this.states.ready);
                    console.log('state on ran');
                },
                off:       function () {
                    /* state: off */
                    this.view.gameOn    = false;
                    this.view.strict    = false;
                    this.view.counter   = '- -';
                    this.view.counterOn = false;

                    // clean up
                    this._cleanup();

                    // set state to undefined - this is our initial state
                    this._addEvent(0, this, this._setState, undefined);
                    // stop heartbeat 100ms latter - this gives update time to process any clean up events
                    this._addEvent(100, this, this._stopHeartBeat, undefined);
                },
                ready:     function () {
                    /* state: ready */
                },
                run:       function () {
                    /* state: run */
                    this._setCounter(this.seqCount + 1);
                },
                waiting:   function () {
                    /* state: waiting */
                },
                animating: function () {
                    /* state: animating */
                    // empty marker state
                },
                updating:   function () {
                    /* state: updating */
                },
                start:     function () {
                    /* state: start */

                    // clean up
                    this._cleanup();

                    // generate a sequence
                    this._generateSequence();

                    // set start to restart - this was done to avoid code duplication as
                    // restart already dose what needed to be done to start
                    var parent = this;
                    this.failTimerID = this._addEvent(0, this, this._setState, parent.states.restart);
                },
                restart:   function () {
                    /* state: restart */
                    this.seqNum = 0;

                    // play sequence
                    var delay = this._playSequence();

                    // set state to run
                    var parent = this;
                    this._addEvent(delay, this, this._setState, parent.states.run);

                    // add event to time out if they take too long to input buttons
                    // keep event id so we can cancel it
                    this.failTimerID = this._addEvent(delay + this.inputTimeOut, this, this._setState, parent.states.failed);
                },
                failed:    function () {
                    /* state: failed */

                    // cancel any fail timer - this way it doesnt get called twice
                    if (this.failTimerID !== undefined) {
                        this._removeEvent(this.failTimerID);
                        this.failTimerID = undefined;
                    }

                    console.log('failed');
                    // player failed for some reason, we don't care why

                    var nextState = this.states.restart;
                    // if strict that's it game over / restart
                    if (this.view.strictOn) {
                        nextState = this.states.start;
                    }

                    // play animation.error
                    this.animation.play(this, this.animation.error, nextState);
                }
            }, /* end of states */
            animation:       {
                play:  function (scope, animation, nextState, prams) {
                    scope._addEvent(0, scope, scope._setState, scope.states.animating);
                    var animationTime = animation(scope, prams);
                    scope._addEvent(animationTime, scope, scope._setState, nextState);
                },
                error: function (scope) {
                    var flashTime = 300;
                    var time = 0;

                    scope.view.counter    = '! !';
                    var flashFunc = function () {
                        scope.view.counterOn = !scope.view.counterOn;
                    };

                    // tell view to flash ! !
                    for (var i = 1; i < 7; i++) {
                        scope._addEvent(time, scope, flashFunc);
                        time += flashTime;
                    }
                    return time;
                },
                win: function (scope) {
                    var spinTime = 50;
                    var time = 0;

                    var spin = ['| |', '/ /', '- -', '\\ \\'];

                    var flashFunc = function (num) {
                        scope.view.counterOn = !scope.view.counterOn;
                        scope.view.counter    = spin[num % 4];
                    };

                    // tell view to flash ! !
                    for (var i = 1; i < 101; i++) {
                        scope._addEvent(time, scope, flashFunc, i);
                        time += spinTime;
                    }
                    return time;
                },
                buttonFlash: function (scope, prams) {
                    var btn = prams;
                    var btnOn = function (btn) {
                        scope.view[btn]      = true;
                        scope.view.sndToPlay = scope.sounds[btn + 'Snd'];
                    };
                    var btnOff = function (btn) {
                        scope.view[btn]      = false;
                        scope.view.sndToPlay = undefined;
                    };

                    scope._addEvent(0, scope, btnOn, btn);
                    scope._addEvent(scope.flashTime, scope, btnOff, btn);
                    return scope.flashTime;
                }
            }, /* end of animation */
            _startHeartBeat: function () {
                // heart beat
                var parent     = this;
                var lastTick   = Date.now();
                var updateTick = function () {
                    var tick = Date.now();
                    parent._onUpdate(tick - lastTick);
                    lastTick = tick;
                };
                this.heartBeat = $interval(updateTick, 33, 0, true);
            },
            _stopHeartBeat:  function () {
                $interval.cancel(this.heartBeat);
                this.heartBeat = undefined;
            },
            _setCallback:    function (callback) {
                if (callback === undefined) {
                    stackTrace('callback undefined!');
                }
                this.callback = callback;
            },
            on:              function (callback) {
                if (callback === undefined) {
                    stackTrace('callback cannot be undefined!');
                }
                this._setCallback(callback);
                this._startHeartBeat();
                var parent = this;
                this._addEvent(0, this, this._setState, parent.states.on);
            },
            off:             function () {
                var parent = this;
                this._addEvent(0, this, this._setState, parent.states.off);
            },
            toggleStrict:    function () {
                this.view.strictOn = !this.view.strictOn;

                /* test code */
                /*
                this.seqCount = 19;
                this.seqNum = 18;
                console.log(this.sequence);
                */
            },
            _onUpdate:       function (dt) {
                this._processEvents(dt);

                // execute state
                if (this.state !== undefined) {
                    this.state();
                }
                // tell view to update
                this.callback();
            },
            _addEvent:       function (delay, scope, func, prams) {
                var id = this.events.length;
                this.events.push({id: id, scope: scope, delay: delay, func: func, prams: prams});
                return id;
            },
            _removeEvent:    function (id) {
                this.events.some(function (element, index) {
                    if (element.id === id) {
                        this.events[index] = undefined;
                        return true;
                    }
                }, this);
            },
            _removeAllEvents: function () {
                this.events = [];
            },
            _processEvents:  function (dt) {
                var marker = 'marker';
                this.events.push(marker);

                var shifted;
                do {
                    shifted = this.events.shift();
                    if (shifted !== marker && shifted !== undefined) {
                        shifted.delay -= dt;
                        if (shifted.delay <= 0) {
                            shifted.func.bind(shifted.scope)(shifted.prams);
                        } else {
                            this.events.push(shifted);
                        }
                    }
                } while (shifted !== marker);
            },
            _cleanup:        function () {
                // clear all events
                this._removeAllEvents();

                // reset view and other data
                this.view.counter   = '- -';
                this.seqCount       = 0;
                this.seqNum         = 0;
                this.difficulty     = 0;
                this.view.btnGreen  = false;
                this.view.btnRed    = false;
                this.view.btnBlue   = false;
                this.view.btnYellow = false;
                this.view.sndToPlay = undefined;
            },

            start:             function () {
                if (!this.view.gameOn) {
                    return;
                }
                console.log('starting');

                // set state to start
                var parent = this;
                this._addEvent(0, this, this._setState, parent.states.start);
            },
            _setState:         function (newState) {
                this.state = newState;
            },
            btnInput:          function (color) {
                if (this.state !== this.states.run) {
                    return;
                }
                var btn;
                var btnNum;
                if (color === 'green') {
                    btn    = 'btnGreen';
                    btnNum = 1;
                } else if (color === 'red') {
                    btn    = 'btnRed';
                    btnNum = 2;
                } else if (color === 'blue') {
                    btn    = 'btnBlue';
                    btnNum = 3;
                } else if (color === 'yellow') {
                    btn    = 'btnYellow';
                    btnNum = 4;
                }

                // play sound and light button
                this.animation.play(this, this.animation.buttonFlash, this.states.updating, btn);

                // process input
                // good input
                var parent = this;
                if (this.sequence[this.seqNum] === btnNum) {
                    this.seqNum++;

                    /* difficulty increase */
                    if (this.seqNum === this.level_1 || this.seqNum === this.level_2 || this.seqNum === this.level_3) {
                        this.difficulty += this.diffInc;
                    }

                    /* win */
                    if (this.seqNum > 19) {
                        // cancel fail timer
                        this._removeEvent(this.failTimerID);

                        // play win animation
                        this.animation.play(this, this.animation.win, this.states.ready);
                        return;
                    }

                    //
                    if (this.seqNum > this.seqCount) {
                        console.log('this.seqNum > this.seqCount');
                        this.seqNum = 0;
                        this.seqCount++;

                        // cancel fail timer
                        this._removeEvent(this.failTimerID);

                        // play sequence
                        var delay = this._playSequence();

                        // set state to run
                        this._addEvent(delay, this, this._setState, parent.states.run);

                        // add event to time out if they take too long to input buttons
                        // keep event id so we can cancel it
                        this.failTimerID = this._addEvent(delay + this.inputTimeOut, this, this._setState, parent.states.failed);
                    }
                } else {
                    // bad input - set state to failed
                    this._addEvent(0, this, this._setState, parent.states.failed);
                }
            },
            _generateSequence: function () {
                this.sequence = [];
                for (var i = 0; i < 20; i++) {
                    var num = Math.floor(Math.random() * (5 - 1)) + 1;
                    this.sequence.push(num);
                }
            },
            // todo turn playSequence into an animation
            _playSequence:     function () {
                console.log('_playSequence');

                var delay = this.timeDelay;
                // set state to playing to prevent user actions other than on/off
                var parent = this;
                this._addEvent(0, this, this._setState, parent.states.animating);

                for (var i = 0; i < this.seqCount + 1; i++) {
                    // button on
                    this._addEvent(delay , this, this._btnOn, this._getBtn(this.sequence[i]));
                    // button off
                    this._addEvent(delay + this.btnFlashTime, this, this._btnOff, this._getBtn(this.sequence[i]));
                    delay += this.timeDelay - this.difficulty;
                }
                return delay;
            },
            _btnOn:            function (btn) {
                this.view[btn]      = true;
                this.view.sndToPlay = this.sounds[btn + 'Snd'];
            },
            _btnOff:           function (btn) {
                this.view[btn]      = false;
                this.view.sndToPlay = undefined;
            },
            _getBtn:           function (nbr) {
                switch (nbr) {
                    case 1:
                        return 'btnGreen';
                    case 2:
                        return 'btnRed';
                    case 3:
                        return 'btnBlue';
                    case 4:
                        return 'btnYellow';
                }
            },
            getSoundToPlay:  function () {
                var result          = this.view.sndToPlay;
                this.view.sndToPlay = undefined;
                return result;
            },
            _setCounter: function (value){
                value = value.toString().split('');
                if (value.length === 1){
                    value.unshift('0');
                }
                this.view.counter = value.join(' ');
            },
            view:            {
                btnGreen:  false,
                btnRed:    false,
                btnBlue:   false,
                btnYellow: false,
                sndToPlay: undefined,
                counter:   '- -',
                counterOn: false,
                strictOn:  false,
                gameOn:    false
            },
            sounds:          {
                btnGreenSnd:  'assets/sounds/simonSound1.mp3',
                btnRedSnd:    'assets/sounds/simonSound2.mp3',
                btnBlueSnd:   'assets/sounds/simonSound3.mp3',
                btnYellowSnd: 'assets/sounds/simonSound4.mp3',
            },
            events:          [],
            state:           undefined,
            sequence:        [],
            seqCount:        0,                 // end of the current rnd
            seqNum:          0,                 // how many correct buttons player has pushed
            timeDelay:       900,              // millisecond time delay between buttons
            btnFlashTime:    400,               // millisecond how long to leave a button on.
            inputTimeOut:    8000,              // time player has to input the correct sequence
            autoRestartTime: 2000,              // millisecond how long to wait before restart
            flashTime:       300,
            level_1:         5,
            level_2:         9,
            level_3:         13,
            difficulty:      0,
            diffInc:         200,
            failTimerID:     undefined,
            heartBeat:       undefined
        };
        /* end of simon */

        var onOffSwitch    = false;
        var updateView     = function () {
            $scope.onOff       = simon.view.gameOn;
            $scope.counterOn   = simon.view.counterOn;
            $scope.strictLed   = simon.view.strictOn;
            $scope.count       = simon.view.counter;
            $scope.greenBtnOn  = simon.view.btnGreen;
            $scope.redBtnOn    = simon.view.btnRed;
            $scope.blueBtnOn   = simon.view.btnBlue;
            $scope.yellowBtnOn = simon.view.btnYellow;

            var sndToPlay = simon.getSoundToPlay();
            if (sndToPlay !== undefined) {
                var audio = new Audio(sndToPlay);
                audio.play();
            }
            //$scope.$apply();
        };
        $scope.switchClick = function () {
            onOffSwitch = !onOffSwitch;
            if (onOffSwitch) {
                simon.on(updateView);
            } else {
                simon.off();
            }
        };
        $scope.strictClick = function () {
            simon.toggleStrict();
        };
        $scope.btnPress    = function (color) {
            simon.btnInput(color);
        };
        $scope.startBtn    = function () {
            simon.start();
        };
        updateView();

    }]);<|endoftext|>


<commit_before>'use strict';

angular.module('myApp.view2', ['ngRoute'])

    .config(['$routeProvider', function ($routeProvider) {
        $routeProvider.when('/view2', {
            templateUrl: 'view2/view2.html',
            controller: 'View2Ctrl'
        });
    }])

    .controller('View2Ctrl', ['usage', function (usage) {
        var canvas = $('#testCanvas')[0];//document.getElementById('testCanvas');
        canvas.width = window.innerWidth - 100;

        //style variables
        var margin = {top: 10, left: 10, right: 10, bottom: 10};

        var maxCanvasHeight = canvas.height - (Number(margin.top) + Number(margin.bottom)) - 15,//Offset by 15
            maxCanvasWidth = canvas.width - (margin.left + margin.right) - 15;//Offset by 15

        //Set up all variable.
        var ctx = canvas.getContext('2d'),
            curUsage = usage.coffeeShop[0].data,

            barWidth = (maxCanvasWidth / curUsage.length),//Width of each bar needs to scale with canvas barWidth
            currX = margin.left,// start at margin boarder
            spacing = 2,
            lineHeight = 10,
            i;// this should only be used for loops...

        var maxBarHeight = getMaxChartValue(curUsage);
        var barHeightOffset = (maxCanvasHeight / maxBarHeight);// Offset for scaling bar height to canvas

        console.log(curUsage);

        /**
         * This renders vertical lines at the (currx, Y) coordinates
         */
        function renderLines() {
            ctx.strokeStyle = "#d8838e";
            ctx.lineWidth = spacing;
            ctx.beginPath();
            ctx.moveTo(currX, canvas.height - margin.bottom);
            ctx.lineTo(currX, canvas.height - lineHeight - margin.bottom);
            ctx.stroke();
        }

        /**
         * This renders one horizontal line to connect all vertical lines.
         */
        function renderLineConnectors() {
            ctx.beginPath();
            ctx.strokeStyle = "#d8838e";
            ctx.lineWidth = spacing;
            ctx.moveTo(margin.left, canvas.height - margin.bottom - lineHeight);
            ctx.lineTo(currX, canvas.height - margin.bottom - lineHeight);
            ctx.stroke();
            ctx.closePath();
        }

        /**
         * This renders the graph bars scaled to fit the canvas window
         */
        function renderBars() {
            ctx.fillStyle = '#d8838e';
            var l = curUsage.length, barHight = 0, barY = 0;
            for (i = 0; i < l; i++) {
                barHight = curUsage[i].usage * barHeightOffset;//tried to make this easier to read
                barY = (canvas.height - barHight) - margin.bottom - lineHeight;//tried to make this easier to read
                ctx.fillRect(currX, barY, barWidth, barHight);
                renderLines();
                currX += barWidth + spacing;
            }
            renderLines();
        }

        /**
         * This draws the individual pieces of the graph in the right order
         */
        !function renderAll() {
            renderBars();
            renderLineConnectors();
        }();

        /**
         *
         * @param chartArray - the array for the current chart
         * @returns {number} the max usage number
         */
        function getMaxChartValue(chartArray) {
            var max = 0, cur = 0, l = chartArray.length;
            for (i = 0; i < l; i++) {
                cur = chartArray[i].usage;
                if (cur > max) max = cur;
            }
            return max;
        }

    }]);<commit_msg>Added timeFormat() for formatting the time into the preferred display. Added the start of render text.<commit_after>'use strict';

angular.module('myApp.view2', ['ngRoute'])

    .config(['$routeProvider', function ($routeProvider) {
        $routeProvider.when('/view2', {
            templateUrl: 'view2/view2.html',
            controller: 'View2Ctrl'
        });
    }])

    .controller('View2Ctrl', ['usage', function (usage) {
        var canvas = $('#testCanvas')[0];//document.getElementById('testCanvas');
        canvas.width = window.innerWidth - 100;

        //style variables
        var margin = {top: 10, left: 10, right: 10, bottom: 10};

        var maxCanvasHeight = canvas.height - (Number(margin.top) + Number(margin.bottom)) - 15,//Offset by 15
            maxCanvasWidth = canvas.width - (margin.left + margin.right) - 15;//Offset by 15

        //Set up all variable.
        var ctx = canvas.getContext('2d'),
            curUsage = usage.coffeeShop[0].data,

            barWidth = (maxCanvasWidth / curUsage.length),//Width of each bar needs to scale with canvas barWidth
            currX = margin.left,// start at margin boarder
            spacing = 2,
            lineHeight = 10,
            i;// this should only be used for loops...

        var maxBarHeight = getMaxChartValue(curUsage);
        var barHeightOffset = (maxCanvasHeight / maxBarHeight);// Offset for scaling bar height to canvas

        console.log(curUsage);

        /**
         * This renders vertical lines at the (currx, Y) coordinates
         */
        function renderLines() {
            ctx.strokeStyle = "#d8838e";
            ctx.lineWidth = spacing;
            ctx.beginPath();
            ctx.moveTo(currX, canvas.height - margin.bottom);
            ctx.lineTo(currX, canvas.height - lineHeight - margin.bottom);
            ctx.stroke();
        }

        /**
         * This renders one horizontal line to connect all vertical lines.
         */
        function renderLineConnectors() {
            ctx.beginPath();
            ctx.strokeStyle = "#d8838e";
            ctx.lineWidth = spacing;
            ctx.moveTo(margin.left, canvas.height - margin.bottom - lineHeight);
            ctx.lineTo(currX, canvas.height - margin.bottom - lineHeight);
            ctx.stroke();
            ctx.closePath();
        }

        /**
         * This renders the graph bars scaled to fit the canvas window
         */
        function renderBars() {
            ctx.fillStyle = '#d8838e';
            var l = curUsage.length, barHight = 0, barY = 0;
            for (i = 0; i < l; i++) {
                barHight = curUsage[i].usage * barHeightOffset;//tried to make this easier to read
                barY = (canvas.height - barHight) - margin.bottom - lineHeight;//tried to make this easier to read
                ctx.fillRect(currX, barY, barWidth, barHight);
                renderLines();
                currX += barWidth + spacing;
            }
            renderLines();
        }

        function renderTimes(text) {
            ctx.font = "30px Arial";
            ctx.fillText("Hello World", 10, 50);
        }

        /**
         * This draws the individual pieces of the graph in the right order
         */
        !function renderAll() {
            renderBars();
            renderLineConnectors();
        }();

        /**
         *
         * @param chartArray - the array for the current chart
         * @returns {number} the max usage number
         */
        function getMaxChartValue(chartArray) {
            var max = 0, cur = 0, l = chartArray.length;
            for (i = 0; i < l; i++) {
                cur = chartArray[i].usage;
                if (cur > max) max = cur;
            }
            return max;
        }

        /**
         * This will format the time according to the graph specification.
         * @param time
         * @returns {*}
         */
        function timeFormat(time) {
            if (time > 1259) {
                return (time - 1200).toString().substring(0, 2) + " PM"
            }

            if (time <= 1259 && time > 1159) {
                return time.toString().substring(0, 2) + " PM"
            }

            if (time <= 1159 && time > 959) {
                return time.toString().substring(0, 2) + " AM"
            }

            if (time <= 59) {
                return "12 AM"
            }

            return time.toString().substring(0, 1) + " AM"
        }

    }]);<|endoftext|>


<commit_before>var AtlasTemplate = require("../views/templates/atlas");
var AtlasMapTemplate = require("../views/templates/atlasmap");
var LineItemTemplate = require("../views/templates/line_item");

module.exports = Backbone.View.extend({
    "last-z-index": 10,
    "currentZoomLevel": 1.0,
    "lastPosition": {
        "top": 0, "left": 0
    },

    events: {
        "click a.refresh-loaded": function() {
            _.each(this.$el.find(".atlas-map"), this.loadMapData);
        },
        "click a.zoom-in": function() {
            this.currentZoomLevel = this.currentZoomLevel * 1.15;
            this.zoom(this.currentZoomLevel);
        },
        "click a.zoom-out": function() {
            this.currentZoomLevel = this.currentZoomLevel * 0.85;
            this.zoom(this.currentZoomLevel);
        },
        "click a.zoom-home": function() {
            this.currentZoomLevel = 1.0;
            this.zoom(this.currentZoomLevel);
        },
        "click a.resize-item": function(e) {
            var li = $(e.target).parents("li");
            if (li.hasClass("active")) {
                this.$el.find(".atlas-map").resizable("destroy");
            } else {
                this.$el.find(".atlas-map").resizable({ "ghost":true});
            }
            li.toggleClass("active");
        },
        "click a.scale-item": function(e) {
            var li = $(e.target).parents("li");
            if (li.hasClass("active")) {
                this.$el.find(".atlas-map").resizable("destroy");
            } else {
                this.$el.find(".atlas-map").resizable({
                    "handles":"n, e, s, w, ne, se, sw, nw",
                    "aspectRatio":true,
                    "animateEasing":"linear",
                    "stop":function (stopE, ui) {
                        var scaleLevel = (ui.size.width / ui.originalSize.width) * 90;
                        $(stopE.target).children().effect("scale", {"scale":"both", "percent":scaleLevel}, 1000);
                    }
                });
            }
            li.toggleClass("active");
        },
        "click a.minimize-me": function(e) {
            this.closeMap($(e.target).parents(".atlas-map"));
        },
        "click a.refresh-me": function(e) {
            this.loadMapData($(e.target).parents(".atlas-map"));
        },
        "click a.open-map": function(e) {
            var mapId = $(e.target).data("id");
            _.each(this.model.get("maps"), function(map) {
                if (_.isEqual(map.id, mapId)) {
                    map.isOpen = true;
                    this.appendAtlasMap(map);
                }
            }, this);
        },
        "click div.atlas-map": function(e) {
            var $target = $(e.target);
            if (!$target.hasClass("atlas-map")) {
                $target = $(e.target).parents(".atlas-map");
            }

            $target.css("z-index", this.nextZindex());
        }
    },

    initialize: function(options) {
        _.extend(this, options);
        _.bindAll(this, "initMaps", "appendAtlasMap", "loadMapData", "loadMapContents", "viewsByUri", "closeMap", "zoom");
        _.bindAll(this, "loadCancerList", "initGeneTypeahead", "nextZindex", "nextPosition");

        this.$el.html(AtlasTemplate());
        this.$el.find(".atlas-zoom").draggable({ "scroll":true });

        $.ajax({ url:"svc/data/lookups/cancers", type:"GET", dataType:"text", success:this.loadCancerList });
        $.ajax({ url:"svc/data/lookups/genes", type:"GET", dataType:"text", success:this.initGeneTypeahead });

        this.model.on("load", this.initMaps);
    },

    initMaps: function() {
        _.each(_.sortBy(this.model.get("maps"), "label"), function(map) {
            if (map.isOpen) {
                this.appendAtlasMap(map);
            }

            var lit = { "a_class": "open-map", "id": map.id, "label": map.label };
            if (map.disabled) {
                lit = { "li_class": "disabled", "id": map.id, "label": map.label };
            }
            this.$el.find(".maps-selector").append(LineItemTemplate(lit));
        }, this);
    },

    appendAtlasMap: function(map) {
        var uid = Math.round(Math.random() * 10000);
        _.each(map.views, function(view, idx) {
            if (idx == 0) view["li_class"] = "active";
            view["uid"] = uid++;
        });

        if (!_.has(map, "position")) {
            map.assignedPosition = this.nextPosition();
        }

        this.$el.find(".atlas-zoom").append(AtlasMapTemplate(map));
        var $atlasMap = this.$el.find(".atlas-zoom").children().last();
        $atlasMap.css("z-index", this.nextZindex());

        var _this = this;
        this.$el.find(".maps-btn").effect("transfer", {
            "to": $atlasMap,
            complete: function() {
                _this.loadMapData($atlasMap);
                $atlasMap.draggable({ "scroll":true });
            }
        }, 750);
    },

    loadMapData: function(atlasMap) {
        _.each($(atlasMap).find(".map-contents"), function(mc) {
            _.defer(this.loadMapContents, mc);
        }, this);
    },

    loadMapContents: function(contentContainer, view_options, query_options) {
        var $target = $(contentContainer);
        var source = $target.data("source");
        var view_name = $target.data("view");
        var linked_to = $target.data("linked");
        if (source && view_name) {
            var afn = function(link) {
                return $(link).data("id")
            };

            var cancerList = _.map(this.$el.find(".cancer-selector .active a"), afn);
            var geneList = _.map(this.$el.find(".gene-selector .item-remover"), afn);

            var v_options = _.extend({ "genes": geneList, "cancers": cancerList, "hideSelector": true }, view_options || {});
            var q_options = _.extend({ "gene": geneList, "cancer": cancerList }, query_options || {});

            this.viewsByUri($target, source, view_name, v_options, q_options);
        }
    },

    viewsByUri: function(targetEl, uri, view_name, options, query) {
//        console.log("viewsByUri(" + uri + "," + view_name + "," + JSON.stringify(options) + "," + JSON.stringify(query) + ")");
        var ViewClass = qed.Views[view_name];
        if (ViewClass) {
            var parts = uri.split("/");
            var data_root = parts[0];
            var analysis_id = parts[1];
            var dataset_id = parts[2];
            var model_unit = qed.Datamodel.get(data_root)[analysis_id];
            var catalog = model_unit.catalog;
            var catalog_unit = catalog[dataset_id];
            var modelName = model_unit.model || catalog_unit.model;
            var serviceUri = catalog_unit.service || model_unit.service || "data/" + uri;
            var Model = qed.Models[modelName || "Default"];

            var model_optns = _.extend(options, {
                "data_uri": "svc/" + serviceUri,
                "analysis_id": analysis_id,
                "dataset_id": dataset_id,
                "model_unit": model_unit,
                "catalog_unit": catalog_unit
            });
            // TODO: Determine which views need annotations
            // qed.FetchAnnotations(dataset_id);

            var model = new Model(model_optns);
            _.defer(function() {
                model.fetch({
                    "data": query,
                    "traditional": true,
                    success:function () {
                        model.trigger("load");
                    }
                });
            });

            var view_options = _.extend({"model":model}, (model_unit.view_options || {}), (options || {}));

            console.log("viewsByUri(" + uri + "," + view_name + "):loading view");
            var view = new ViewClass(view_options);
            $(targetEl).html(view.render().el);
        }
    },

    closeMap: function(atlasMap) {
        $(atlasMap).effect("transfer", {
            "to": this.$el.find(".maps-btn"),
            complete: function() {
                $(atlasMap).remove();
            }
        }, 750);
    },

    zoom: function(zoomLevel) {
        this.$el.find(".atlas-zoom").zoomTo({
            "duration":1000,
            "scalemode": "both",
            "easing": "ease",
            "nativeanimation": true,
            "root": this.$el.find(".atlas-canvas"),
            "closeclick": false,
            "targetsize":zoomLevel
        });
    },

    loadCancerList: function(txt) {
        var cancerList = txt.trim().split("\n");
        var UL = this.$el.find(".cancer-selector");
        _.each(cancerList, function(cancer) {
            UL.append(LineItemTemplate({"li_class":"active","a_class":"toggle-active","id":cancer,"label":cancer}));
        });

        UL.find(".toggle-active").click(function(e) {
            $(e.target).parent().toggleClass("active");
        });

        UL.sortable();
    },

    initGeneTypeahead: function(txt) {
        var genelist = txt.trim().split("\n");

        var UL = this.$el.find(".gene-selector");
        this.$el.find(".genes-typeahead").typeahead({
            source:function (q, p) {
                p(_.compact(_.flatten(_.map(q.toLowerCase().split(" "), function (qi) {
                    return _.map(genelist, function (geneitem) {
                        if (geneitem.toLowerCase().indexOf(qi) >= 0) return geneitem;
                    });
                }))));
            },

            updater:function (gene) {
                UL.append(LineItemTemplate({ "label":gene, "id":gene, "a_class":"item-remover", "i_class":"icon-trash" }));
                UL.find(".item-remover").click(function(e) {
                    $(e.target).parent().remove();
                });
                return "";
            }
        });

        UL.find(".item-remover").click(function(e) {
            $(e.target).parent().remove();
        });

        UL.sortable();
    },

    nextZindex: function() {
        var nextZindex = 1 + this["last-z-index"];
        this["last-z-index"] = nextZindex;
        return nextZindex;
    },

    nextPosition: function() {
        var lastPos = {
            "left": this.lastPosition.left + 50,
            "top": this.lastPosition.top + 50
        };
        this.lastPosition = lastPos;
        return lastPos;
    }
});<commit_msg>show description from map atlas<commit_after>var AtlasTemplate = require("../views/templates/atlas");
var AtlasMapTemplate = require("../views/templates/atlasmap");
var LineItemTemplate = require("../views/templates/line_item");

module.exports = Backbone.View.extend({
    "last-z-index": 10,
    "currentZoomLevel": 1.0,
    "lastPosition": {
        "top": 0, "left": 0
    },

    events: {
        "click a.refresh-loaded": function() {
            _.each(this.$el.find(".atlas-map"), this.loadMapData);
        },
        "click a.zoom-in": function() {
            this.currentZoomLevel = this.currentZoomLevel * 1.15;
            this.zoom(this.currentZoomLevel);
        },
        "click a.zoom-out": function() {
            this.currentZoomLevel = this.currentZoomLevel * 0.85;
            this.zoom(this.currentZoomLevel);
        },
        "click a.zoom-home": function() {
            this.currentZoomLevel = 1.0;
            this.zoom(this.currentZoomLevel);
        },
        "click a.resize-item": function(e) {
            var li = $(e.target).parents("li");
            if (li.hasClass("active")) {
                this.$el.find(".atlas-map").resizable("destroy");
            } else {
                this.$el.find(".atlas-map").resizable({ "ghost":true});
            }
            li.toggleClass("active");
        },
        "click a.scale-item": function(e) {
            var li = $(e.target).parents("li");
            if (li.hasClass("active")) {
                this.$el.find(".atlas-map").resizable("destroy");
            } else {
                this.$el.find(".atlas-map").resizable({
                    "handles":"n, e, s, w, ne, se, sw, nw",
                    "aspectRatio":true,
                    "animateEasing":"linear",
                    "stop":function (stopE, ui) {
                        var scaleLevel = (ui.size.width / ui.originalSize.width) * 90;
                        $(stopE.target).children().effect("scale", {"scale":"both", "percent":scaleLevel}, 1000);
                    }
                });
            }
            li.toggleClass("active");
        },
        "click a.minimize-me": function(e) {
            this.closeMap($(e.target).parents(".atlas-map"));
        },
        "click a.refresh-me": function(e) {
            this.loadMapData($(e.target).parents(".atlas-map"));
        },
        "click a.open-map": function(e) {
            var mapId = $(e.target).data("id");
            _.each(this.model.get("maps"), function(map) {
                if (_.isEqual(map.id, mapId)) {
                    map.isOpen = true;
                    this.appendAtlasMap(map);
                }
            }, this);
        },
        "click div.atlas-map": function(e) {
            var $target = $(e.target);
            if (!$target.hasClass("atlas-map")) {
                $target = $(e.target).parents(".atlas-map");
            }

            $target.css("z-index", this.nextZindex());
        }
    },

    initialize: function(options) {
        _.extend(this, options);
        _.bindAll(this, "initMaps", "appendAtlasMap", "loadMapData", "loadMapContents", "viewsByUri", "closeMap", "zoom");
        _.bindAll(this, "loadCancerList", "initGeneTypeahead", "nextZindex", "nextPosition");

        this.$el.html(AtlasTemplate());
        this.$el.find(".atlas-zoom").draggable({ "scroll":true });

        $.ajax({ url:"svc/data/lookups/cancers", type:"GET", dataType:"text", success:this.loadCancerList });
        $.ajax({ url:"svc/data/lookups/genes", type:"GET", dataType:"text", success:this.initGeneTypeahead });

        this.model.on("load", this.initMaps);
    },

    initMaps: function() {
        _.each(_.sortBy(this.model.get("maps"), "label"), function(map) {
            if (map.isOpen) {
                this.appendAtlasMap(map);
            }

            var lit = { "a_class": "open-map", "id": map.id, "label": map.label };
            if (map.disabled) {
                lit = { "li_class": "disabled", "id": map.id, "label": map.label };
            }
            this.$el.find(".maps-selector").append(LineItemTemplate(lit));
        }, this);
    },

    appendAtlasMap: function(map) {
        var uid = Math.round(Math.random() * 10000);
        _.each(map.views, function(view, idx) {
            if (idx == 0) view["li_class"] = "active";
            view["uid"] = uid++;
        });

        if (!_.has(map, "position")) {
            map.assignedPosition = this.nextPosition();
        }

        this.$el.find(".atlas-zoom").append(AtlasMapTemplate(map));
        var $atlasMap = this.$el.find(".atlas-zoom").children().last();
        $atlasMap.css("z-index", this.nextZindex());

        $atlasMap.find(".info-me").popover({
            "title": "Description",
            "trigger": "hover",
            "content": map.description
        });

        var _this = this;
        this.$el.find(".maps-btn").effect("transfer", {
            "to": $atlasMap,
            complete: function() {
                _this.loadMapData($atlasMap);
                $atlasMap.draggable({ "scroll":true });
            }
        }, 750);
    },

    loadMapData: function(atlasMap) {
        _.each($(atlasMap).find(".map-contents"), function(mc) {
            _.defer(this.loadMapContents, mc);
        }, this);
    },

    loadMapContents: function(contentContainer, view_options, query_options) {
        var $target = $(contentContainer);
        var source = $target.data("source");
        var view_name = $target.data("view");
        var linked_to = $target.data("linked");
        if (source && view_name) {
            var afn = function(link) {
                return $(link).data("id")
            };

            var cancerList = _.map(this.$el.find(".cancer-selector .active a"), afn);
            var geneList = _.map(this.$el.find(".gene-selector .item-remover"), afn);

            var v_options = _.extend({ "genes": geneList, "cancers": cancerList, "hideSelector": true }, view_options || {});
            var q_options = _.extend({ "gene": geneList, "cancer": cancerList }, query_options || {});

            this.viewsByUri($target, source, view_name, v_options, q_options);
        }
    },

    viewsByUri: function(targetEl, uri, view_name, options, query) {
//        console.log("viewsByUri(" + uri + "," + view_name + "," + JSON.stringify(options) + "," + JSON.stringify(query) + ")");
        var ViewClass = qed.Views[view_name];
        if (ViewClass) {
            var parts = uri.split("/");
            var data_root = parts[0];
            var analysis_id = parts[1];
            var dataset_id = parts[2];
            var model_unit = qed.Datamodel.get(data_root)[analysis_id];
            var catalog = model_unit.catalog;
            var catalog_unit = catalog[dataset_id];
            var modelName = model_unit.model || catalog_unit.model;
            var serviceUri = catalog_unit.service || model_unit.service || "data/" + uri;
            var Model = qed.Models[modelName || "Default"];

            var model_optns = _.extend(options, {
                "data_uri": "svc/" + serviceUri,
                "analysis_id": analysis_id,
                "dataset_id": dataset_id,
                "model_unit": model_unit,
                "catalog_unit": catalog_unit
            });
            // TODO: Determine which views need annotations
            // qed.FetchAnnotations(dataset_id);

            var model = new Model(model_optns);
            _.defer(function() {
                model.fetch({
                    "data": query,
                    "traditional": true,
                    success:function () {
                        model.trigger("load");
                    }
                });
            });

            var view_options = _.extend({"model":model}, (model_unit.view_options || {}), (options || {}));

            console.log("viewsByUri(" + uri + "," + view_name + "):loading view");
            var view = new ViewClass(view_options);
            $(targetEl).html(view.render().el);
        }
    },

    closeMap: function(atlasMap) {
        $(atlasMap).effect("transfer", {
            "to": this.$el.find(".maps-btn"),
            complete: function() {
                $(atlasMap).remove();
            }
        }, 750);
    },

    zoom: function(zoomLevel) {
        this.$el.find(".atlas-zoom").zoomTo({
            "duration":1000,
            "scalemode": "both",
            "easing": "ease",
            "nativeanimation": true,
            "root": this.$el.find(".atlas-canvas"),
            "closeclick": false,
            "targetsize":zoomLevel
        });
    },

    loadCancerList: function(txt) {
        var cancerList = txt.trim().split("\n");
        var UL = this.$el.find(".cancer-selector");
        _.each(cancerList, function(cancer) {
            UL.append(LineItemTemplate({"li_class":"active","a_class":"toggle-active","id":cancer,"label":cancer}));
        });

        UL.find(".toggle-active").click(function(e) {
            $(e.target).parent().toggleClass("active");
        });

        UL.sortable();
    },

    initGeneTypeahead: function(txt) {
        var genelist = txt.trim().split("\n");

        var UL = this.$el.find(".gene-selector");
        this.$el.find(".genes-typeahead").typeahead({
            source:function (q, p) {
                p(_.compact(_.flatten(_.map(q.toLowerCase().split(" "), function (qi) {
                    return _.map(genelist, function (geneitem) {
                        if (geneitem.toLowerCase().indexOf(qi) >= 0) return geneitem;
                    });
                }))));
            },

            updater:function (gene) {
                UL.append(LineItemTemplate({ "label":gene, "id":gene, "a_class":"item-remover", "i_class":"icon-trash" }));
                UL.find(".item-remover").click(function(e) {
                    $(e.target).parent().remove();
                });
                return "";
            }
        });

        UL.find(".item-remover").click(function(e) {
            $(e.target).parent().remove();
        });

        UL.sortable();
    },

    nextZindex: function() {
        var nextZindex = 1 + this["last-z-index"];
        this["last-z-index"] = nextZindex;
        return nextZindex;
    },

    nextPosition: function() {
        var lastPos = {
            "left": this.lastPosition.left + 50,
            "top": this.lastPosition.top + 50
        };
        this.lastPosition = lastPos;
        return lastPos;
    }
});<|endoftext|>