<commit_before># encoding: utf-8

module Carto
  module NamedMaps
    class Template
      NAMED_MAPS_VERSION = '0.0.1'.freeze
      NAME_PREFIX = 'tpl_'.freeze
      AUTH_TYPE_OPEN = 'open'.freeze
      AUTH_TYPE_SIGNED = 'token'.freeze
      EMPTY_CSS = '#dummy{}'.freeze

      TILER_WIDGET_TYPES = {
        'category': 'aggregation',
        'formula': 'formula',
        'histogram': 'histogram',
        'list': 'list',
        'time-series': 'histogram'
      }.freeze

      DATAVIEW_TEMPLATE_OPTIONS = [:column, :aggregation, :aggregationColumn, :aggregation_column, :operation].freeze

      def initialize(visualization)
        # TODO: Remove when it's safe to assume thais confussion wont' happen.
        raise 'Carto::NamedMaps::Template needs a Carto::Visualization' unless visualization.is_a?(Carto::Visualization)

        @visualization = visualization
      end

      def to_hash
        @template ||= stats_aggregator.timing('named-map.template-data') do
          {
            name: name,
            auth: auth,
            version: NAMED_MAPS_VERSION,
            placeholders: placeholders,
            layergroup: {
              layers: layers,
              stat_tag: @visualization.id,
              dataviews: dataviews,
              analyses: analyses_definitions
            },
            view: view
          }
        end
      end

      def to_json
        to_hash.to_json
      end

      def name
        (NAME_PREFIX + @visualization.id).gsub(/[^a-zA-Z0-9\-\_.]/, '').tr('-', '_')
      end

      private

      def placeholders
        placeholders = {}

        layers = @visualization.layers

        last_index, carto_layers_visibility_placeholders = layer_visibility_placeholders(layers.select(&:carto_layer?))
        _, torque_layer_visibility_placeholders = layer_visibility_placeholders(layers.select(&:torque?),
                                                                                starting_index: last_index)

        placeholders = placeholders.merge(carto_layers_visibility_placeholders)
        placeholders = placeholders.merge(torque_layer_visibility_placeholders)

        placeholders
      end

      def layer_visibility_placeholders(layers, starting_index: 0)
        placeholders = {}

        index = starting_index
        layers.each do |layer|
          placeholders["layer#{index}".to_sym] = {
            type: 'number',
            default: layer.options[:visible] ? 1 : 0
          }
          index += 1
        end

        [index, placeholders]
      end

      def layers
        layers = []
        layer_index = -1 # forgive me for I have sinned

        @visualization.layers.select(&:named_map_layer?).each do |layer|
          if layer.data_layer?
            layer_index += 1

            layers.push(type: 'cartodb', options: options_for_cartodb_layers(layer, layer_index))
          elsif layer.base?
            layer_options = layer.options

            if layer_options[:type] == 'Plain'
              layers.push(type: 'plain', options: options_for_plain_basemap_layers(layer_options))
            else
              layers.push(type: 'http', options: options_for_http_basemap_layers(layer_options))
            end
          end
        end

        @visualization.layers.select(&:torque?).each do |layer|
          layer_index += 1
          layers.push(type: 'torque', options: common_options_for_carto_and_torque_layers(layer, layer_index))
        end

        layers
      end

      def options_for_plain_basemap_layers(layer_options)
        layer_options[:image].empty? ? { color: layer_options[:color] } : { imageUrl: layer_options[:image] }
      end

      def options_for_http_basemap_layers(layer_options)
        options = {}

        options[:urlTemplate] = layer_options[:urlTemplate] if layer_options[:urlTemplate].present?
        options[:subdomains] = layer_options[:subdomains] if layer_options[:subdomains]

        options
      end

      def options_for_cartodb_layers(layer, index)
        options = common_options_for_carto_and_torque_layers(layer, index)

        layer_options = layer.options
        layer_options_sql_wrap = layer_options[:sql_wrap]
        layer_options_query_wrapper = layer_options[:query_wrapper]

        options[:sql_wrap] = layer_options_sql_wrap || layer_options_query_wrapper

        options
      end

      def common_options_for_carto_and_torque_layers(layer, index)
        layer_options = layer.options

        options = {
          cartocss: layer_options.fetch(:tile_style).strip.empty? ? EMPTY_CSS : layer_options.fetch(:tile_style),
          cartocss_version: layer_options.fetch(:style_version)
        }

        layer_options_source = layer_options[:source]
        if layer_options_source
          options[:source] = { id: layer_options_source }
        else
          options[:sql] = visibility_wrapped_sql(layer.wrapped_sql(@visualization.user), index)
        end

        interactivity, attributes = infowindow_options(layer)

        options[:interactivity] = interactivity if interactivity
        options[:attributes] = attributes if attributes

        options
      end

      def visibility_wrapped_sql(sql, index)
        "SELECT * FROM (#{sql}) AS wrapped_query WHERE <%= layer#{index} %>=1"
      end

      def dataviews
        dataviews = {}

        @visualization.widgets.each do |widget|
          dataviews[widget.id.to_s] = dataview_data(widget)
        end

        dataviews
      end

      def analyses_definitions
        @visualization.analyses.map(&:analysis_definition)
      end

      def stats_aggregator
        @@stats_aggregator_instance ||= CartoDB::Stats::EditorAPIs.instance
      end

      def infowindow_options(layer)
        layer_options_interactivity = layer.options[:interactivity]
        interactivity = layer_options_interactivity if layer_options_interactivity

        layer_infowindow = layer.infowindow
        layer_infowindow_fields = layer_infowindow[:fields] if layer_infowindow
        attributes = if layer_infowindow_fields && !layer_infowindow_fields.empty?
                       {
                         id:       'cartodb_id',
                         columns:  layer_infowindow[:fields].map { |field| field.fetch(:name) }
                       }
                     end

        [interactivity, attributes]
      end

      def dataview_data(widget)
        options = widget.options.select { |k, _v| DATAVIEW_TEMPLATE_OPTIONS.include?(k) }
        options[:aggregationColumn] = options.delete(:aggregation_column)

        dataview_data = {
          type: TILER_WIDGET_TYPES[widget.type.to_sym],
          options: options
        }

        dataview_data[:source] = { id: widget.source_id } if widget.source_id.present?

        dataview_data
      end

      def auth
        method, valid_tokens = if @visualization.password_protected?
                                 [AUTH_TYPE_SIGNED, @visualization.user.get_auth_tokens]
                               elsif @visualization.organization?
                                 auth_tokens = @visualization.all_users_with_read_permission
                                                             .map(&:get_auth_tokens)
                                                             .flatten
                                                             .uniq

                                 [AUTH_TYPE_SIGNED, auth_tokens]
                               else
                                 [AUTH_TYPE_OPEN, nil]
                               end

        auth = { method: method }
        auth[:valid_tokens] = valid_tokens if valid_tokens

        auth
      end

      def view
        map = @visualization.map
        center_data = map.center_data

        data = {
          zoom: map.zoom,
          center: {
            lng: center_data[1].to_f,
            lat: center_data[0].to_f
          }
        }

        bounds_data = map.view_bounds_data

        # INFO: Don't return 'bounds' if all points are 0 to avoid static map trying to go too small zoom level
        if bounds_data[:west] != 0 || bounds_data[:south] != 0 || bounds_data[:east] != 0 || bounds_data[:north] != 0
          data[:bounds] = bounds_data
        end

        data
      end
    end
  end
end
<commit_msg>go back to using shortcuts now<commit_after># encoding: utf-8

module Carto
  module NamedMaps
    class Template
      NAMED_MAPS_VERSION = '0.0.1'.freeze
      NAME_PREFIX = 'tpl_'.freeze
      AUTH_TYPE_OPEN = 'open'.freeze
      AUTH_TYPE_SIGNED = 'token'.freeze
      EMPTY_CSS = '#dummy{}'.freeze

      TILER_WIDGET_TYPES = {
        'category': 'aggregation',
        'formula': 'formula',
        'histogram': 'histogram',
        'list': 'list',
        'time-series': 'histogram'
      }.freeze

      DATAVIEW_TEMPLATE_OPTIONS = [:column, :aggregation, :aggregationColumn, :aggregation_column, :operation].freeze

      def initialize(visualization)
        # TODO: Remove when it's safe to assume thais confussion wont' happen.
        raise 'Carto::NamedMaps::Template needs a Carto::Visualization' unless visualization.is_a?(Carto::Visualization)

        @visualization = visualization
      end

      def to_hash
        @template ||= stats_aggregator.timing('named-map.template-data') do
          {
            name: name,
            auth: auth,
            version: NAMED_MAPS_VERSION,
            placeholders: placeholders,
            layergroup: {
              layers: layers,
              stat_tag: @visualization.id,
              dataviews: dataviews,
              analyses: analyses_definitions
            },
            view: view
          }
        end
      end

      def to_json
        to_hash.to_json
      end

      def name
        (NAME_PREFIX + @visualization.id).gsub(/[^a-zA-Z0-9\-\_.]/, '').tr('-', '_')
      end

      private

      def placeholders
        placeholders = {}

        layers = @visualization.layers

        last_index, carto_layers_visibility_placeholders = layer_visibility_placeholders(layers.select(&:carto_layer?))
        _, torque_layer_visibility_placeholders = layer_visibility_placeholders(layers.select(&:torque?),
                                                                                starting_index: last_index)

        placeholders = placeholders.merge(carto_layers_visibility_placeholders)
        placeholders = placeholders.merge(torque_layer_visibility_placeholders)

        placeholders
      end

      def layer_visibility_placeholders(layers, starting_index: 0)
        placeholders = {}

        index = starting_index
        layers.each do |layer|
          placeholders["layer#{index}".to_sym] = {
            type: 'number',
            default: layer.options[:visible] ? 1 : 0
          }
          index += 1
        end

        [index, placeholders]
      end

      def layers
        layers = []
        layer_index = -1 # forgive me for I have sinned

        @visualization.named_maps_layers.each do |layer|
          if layer.data_layer?
            layer_index += 1

            layers.push(type: 'cartodb', options: options_for_cartodb_layers(layer, layer_index))
          elsif layer.base?
            layer_options = layer.options

            if layer_options[:type] == 'Plain'
              layers.push(type: 'plain', options: options_for_plain_basemap_layers(layer_options))
            else
              layers.push(type: 'http', options: options_for_http_basemap_layers(layer_options))
            end
          end
        end

        @visualization.torque_layers.each do |layer|
          layer_index += 1
          layers.push(type: 'torque', options: common_options_for_carto_and_torque_layers(layer, layer_index))
        end

        layers
      end

      def options_for_plain_basemap_layers(layer_options)
        layer_options[:image].empty? ? { color: layer_options[:color] } : { imageUrl: layer_options[:image] }
      end

      def options_for_http_basemap_layers(layer_options)
        options = {}

        options[:urlTemplate] = layer_options[:urlTemplate] if layer_options[:urlTemplate].present?
        options[:subdomains] = layer_options[:subdomains] if layer_options[:subdomains]

        options
      end

      def options_for_cartodb_layers(layer, index)
        options = common_options_for_carto_and_torque_layers(layer, index)

        layer_options = layer.options
        layer_options_sql_wrap = layer_options[:sql_wrap]
        layer_options_query_wrapper = layer_options[:query_wrapper]

        options[:sql_wrap] = layer_options_sql_wrap || layer_options_query_wrapper

        options
      end

      def common_options_for_carto_and_torque_layers(layer, index)
        layer_options = layer.options

        options = {
          cartocss: layer_options.fetch(:tile_style).strip.empty? ? EMPTY_CSS : layer_options.fetch(:tile_style),
          cartocss_version: layer_options.fetch(:style_version)
        }

        layer_options_source = layer_options[:source]
        if layer_options_source
          options[:source] = { id: layer_options_source }
        else
          options[:sql] = visibility_wrapped_sql(layer.wrapped_sql(@visualization.user), index)
        end

        interactivity, attributes = infowindow_options(layer)

        options[:interactivity] = interactivity if interactivity
        options[:attributes] = attributes if attributes

        options
      end

      def visibility_wrapped_sql(sql, index)
        "SELECT * FROM (#{sql}) AS wrapped_query WHERE <%= layer#{index} %>=1"
      end

      def dataviews
        dataviews = {}

        @visualization.widgets.each do |widget|
          dataviews[widget.id.to_s] = dataview_data(widget)
        end

        dataviews
      end

      def analyses_definitions
        @visualization.analyses.map(&:analysis_definition)
      end

      def stats_aggregator
        @@stats_aggregator_instance ||= CartoDB::Stats::EditorAPIs.instance
      end

      def infowindow_options(layer)
        layer_options_interactivity = layer.options[:interactivity]
        interactivity = layer_options_interactivity if layer_options_interactivity

        layer_infowindow = layer.infowindow
        layer_infowindow_fields = layer_infowindow[:fields] if layer_infowindow
        attributes = if layer_infowindow_fields && !layer_infowindow_fields.empty?
                       {
                         id:       'cartodb_id',
                         columns:  layer_infowindow[:fields].map { |field| field.fetch(:name) }
                       }
                     end

        [interactivity, attributes]
      end

      def dataview_data(widget)
        options = widget.options.select { |k, _v| DATAVIEW_TEMPLATE_OPTIONS.include?(k) }
        options[:aggregationColumn] = options.delete(:aggregation_column)

        dataview_data = {
          type: TILER_WIDGET_TYPES[widget.type.to_sym],
          options: options
        }

        dataview_data[:source] = { id: widget.source_id } if widget.source_id.present?

        dataview_data
      end

      def auth
        method, valid_tokens = if @visualization.password_protected?
                                 [AUTH_TYPE_SIGNED, @visualization.user.get_auth_tokens]
                               elsif @visualization.organization?
                                 auth_tokens = @visualization.all_users_with_read_permission
                                                             .map(&:get_auth_tokens)
                                                             .flatten
                                                             .uniq

                                 [AUTH_TYPE_SIGNED, auth_tokens]
                               else
                                 [AUTH_TYPE_OPEN, nil]
                               end

        auth = { method: method }
        auth[:valid_tokens] = valid_tokens if valid_tokens

        auth
      end

      def view
        map = @visualization.map
        center_data = map.center_data

        data = {
          zoom: map.zoom,
          center: {
            lng: center_data[1].to_f,
            lat: center_data[0].to_f
          }
        }

        bounds_data = map.view_bounds_data

        # INFO: Don't return 'bounds' if all points are 0 to avoid static map trying to go too small zoom level
        if bounds_data[:west] != 0 || bounds_data[:south] != 0 || bounds_data[:east] != 0 || bounds_data[:north] != 0
          data[:bounds] = bounds_data
        end

        data
      end
    end
  end
end

{'fraction_non_alphanumeric': 0.08375573256094618, 'fraction_numerical': 0.0025343953656770456, 'mean_word_length': 1.961579699785561, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 28, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5979685', 'n_tokens_mistral': 4724, 'n_tokens_neox': 4476, 'n_words': 869}