"use strict";

App.module("GraphicsRenderingModule", function(GraphicsRenderingModule, App, Backbone, Marionette, $, _, Logger) {

    GraphicsRenderingModule.addInitializer(function(options){

        GraphicsRenderingModule.RendererPrototypes = {};
        GraphicsRenderingModule.renderers = {};

        /**
         * Registers a new renderer
         */
        GraphicsRenderingModule.registerRenderer = function(rendererDefinition) {
            var RendererPrototype;
            var inheritId = rendererDefinition.inherit ? rendererDefinition.inherit : "";
            var id = rendererDefinition.id;
            if (!id) {
                throw _.str.sprintf("Renderer definition does not contain an id");
            }
            var rendererWithThisId = null;
            try {
                rendererWithThisId = GraphicsRenderingModule.getRendererById(id);
            } catch (e) {
            }
            if (rendererWithThisId) {
                throw _.str.sprintf("Renderer with id \"%s\" already exists", id);
            }

            var prototypeOptions = {};
            var prototypeDefaultVegaConfig = {};
            if (!inheritId) {
                RendererPrototype = Marionette.Object;
            } else {
                try {
                    RendererPrototype = GraphicsRenderingModule.getRendererPrototypeById(inheritId);
                    var parentRenderer = GraphicsRenderingModule.getRendererById(inheritId);
                    prototypeOptions = parentRenderer.options;
                    prototypeDefaultVegaConfig = parentRenderer.defaultVegaConfig;
                } catch (e) {
                    throw _.str.sprintf("Renderer with id \"%s\" could not be inherited from renderer with id \"%s\" (it does not exist)", id, inheritId);
                }
            }

            var combinedOptions = rendererDefinition.options
                ? _.defaults({}, rendererDefinition.options, prototypeOptions)
                : _.clone(prototypeOptions);
            var combinedDefaultVegaConfig = rendererDefinition.defaultVegaConfig
                ? _.defaults({}, rendererDefinition.defaultVegaConfig, prototypeDefaultVegaConfig)
                        : _.clone(prototypeDefaultVegaConfig);

            for (var key in rendererDefinition.options) {
                if (rendererDefinition.options.hasOwnProperty(key) && rendererDefinition.options[key] === undefined) {
                    delete combinedOptions[key];
                }
            }
            rendererDefinition.options = combinedOptions;

            for (var key in rendererDefinition.defaultVegaConfig) {
                if (rendererDefinition.defaultVegaConfig.hasOwnProperty(key) && rendererDefinition.defaultVegaConfig[key] === undefined) {
                    delete combinedDefaultVegaConfig[key];
                }
            }
            rendererDefinition.defaultVegaConfig = combinedDefaultVegaConfig;

            var Renderer = RendererPrototype.extend(rendererDefinition);
            GraphicsRenderingModule.RendererPrototypes[id] = Renderer;
            GraphicsRenderingModule.renderers[id] = new Renderer();
        };

        GraphicsRenderingModule.getRendererPrototypeById = function(id) {
            var RendererPrototype = GraphicsRenderingModule.RendererPrototypes[id];
            if (!RendererPrototype) {
                throw _.str.sprintf("RendererPrototype with id \"%s\" not found.", id);
            }
            return RendererPrototype;
        };

        GraphicsRenderingModule.getRendererById = function(id) {
            var renderer = GraphicsRenderingModule.renderers[id];
            if (!renderer) {
                throw _.str.sprintf("Renderer with id \"%s\" not found.", id);
            }
            return renderer;
        };

        GraphicsRenderingModule.render = function(id, $element, data, options) {
            GraphicsRenderingModule.getRendererById(id).render($element, data, options);
        };
    });
}, Logger);
