require 'clearwater/component'
require 'clearwater/virtual_dom'

module Clearwater
  module SVGComponent
    def render
    end

    SVG_TAGS = {
      a: 'a',
      alt_glyph: 'altGlyph',
      alt_glyph_def: 'altGlyphDef',
      alt_glyph_item: 'altGlyphItem',
      animate: 'animate',
      animate_color: 'animateColor',
      animate_motion: 'animateMotion',
      animate_transform: 'animateTransform',
      circle: 'circle',
      clip_path: 'clipPath',
      color_profile: 'color-profile',
      cursor: 'cursor',
      defs: 'defs',
      desc: 'desc',
      ellipse: 'ellipse',
      fe_blend: 'feBlend',
      fe_color_matrix: 'feColorMatrix',
      fe_component_transfer: 'feComponentTransfer',
      fe_composite: 'feComposite',
      fe_convolve_matrix: 'feConvolveMatrix',
      fe_diffuse_lighting: 'feDiffuseLighting',
      fe_displacement_map: 'feDisplacementMap',
      fe_distant_light: 'feDistantLight',
      fe_flood: 'feFlood',
      fe_func_a: 'feFuncA',
      fe_func_b: 'feFuncB',
      fe_func_g: 'feFuncG',
      fe_func_r: 'feFuncR',
      fe_gaussian_blur: 'feGaussianBlur',
      fe_image: 'feImage',
      fe_merge: 'feMerge',
      fe_merge_node: 'feMergeNode',
      fe_morphology: 'feMorphology',
      fe_offset: 'feOffset',
      fe_point_light: 'fePointLight',
      fe_specular_lighting: 'feSpecularLighting',
      fe_spot_light: 'feSpotLight',
      fe_tile: 'feTile',
      fe_turbulence: 'feTurbulence',
      filter: 'filter',
      font: 'font',
      font_face: 'font-face',
      font_face_format: 'font-face-format',
      font_face_name: 'font-face-name',
      font_face_src: 'font-face-src',
      font_face_uri: 'font-face-uri',
      foreign_object: 'foreignObject',
      g: 'g',
      glyph: 'glyph',
      glyph_ref: 'glyphRef',
      hkern: 'hkern',
      image: 'image',
      line: 'line',
      linear_gradient: 'linearGradient',
      marker: 'marker',
      mask: 'mask',
      metadata: 'metadata',
      missing_glyph: 'missing-glyph',
      mpath: 'mpath',
      path: 'path',
      pattern: 'pattern',
      polygon: 'polygon',
      polyline: 'polyline',
      radial_gradient: 'radialGradient',
      rect: 'rect',
      script: 'script',
      set: 'set',
      stop: 'stop',
      style: 'style',
      svg: 'svg',
      switch: 'switch',
      symbol: 'symbol',
      text: 'text',
      text_path: 'textPath',
      title: 'title',
      tref: 'tref',
      tspan: 'tspan',
      use: 'use',
      view: 'view',
      vkern: 'vkern',
    }

    SVG_ATTRIBUTES = {
      accent_height: 'accent-height',
      accumulate: 'accumulate',
      additive: 'additive',
      alignment_baseline: 'alignment-baseline',
      alphabetic: 'alphabetic',
      amplitude: 'amplitude',
      arabic_form: 'arabic-form',
      ascent: 'ascent',
      attribute_name: 'attributeName',
      attribute_type: 'attributeType',
      azimuth: 'azimuth',
      base_frequency: 'baseFrequency',
      base_profile: 'baseProfile',
      baseline_shift: 'baseline-shift',
      bbox: 'bbox',
      begin: 'begin',
      bias: 'bias',
      by: 'by',
      calc_mode: 'calcMode',
      cap_height: 'cap-height',
      class: 'class',
      clip: 'clip',
      clip_path: 'clip-path',
      clip_rule: 'clip-rule',
      clip_path_units: 'clipPathUnits',
      color: 'color',
      color_interpolation: 'color-interpolation',
      color_interpolation_filters: 'color-interpolation-filters',
      color_profile: 'color-profile',
      color_rendering: 'color-rendering',
      content_script_type: 'contentScriptType',
      content_style_type: 'contentStyleType',
      cursor: 'cursor',
      cx: 'cx',
      cy: 'cy',
      d: 'd',
      descent: 'descent',
      diffuse_constant: 'diffuseConstant',
      direction: 'direction',
      display: 'display',
      divisor: 'divisor',
      dominant_baseline: 'dominant-baseline',
      dur: 'dur',
      dx: 'dx',
      dy: 'dy',
      edge_mode: 'edgeMode',
      elevation: 'elevation',
      enable_background: 'enable-background',
      end: 'end',
      exponent: 'exponent',
      external_resources_required: 'externalResourcesRequired',
      fill: 'fill',
      fill_opacity: 'fill-opacity',
      fill_rule: 'fill-rule',
      filter: 'filter',
      filter_res: 'filterRes',
      filter_units: 'filterUnits',
      flood_color: 'flood-color',
      flood_opacity: 'flood-opacity',
      font_family: 'font-family',
      font_size: 'font-size',
      font_size_adjust: 'font-size-adjust',
      font_stretch: 'font-stretch',
      font_style: 'font-style',
      font_variant: 'font-variant',
      font_weight: 'font-weight',
      format: 'format',
      from: 'from',
      fx: 'fx',
      fy: 'fy',
      g1: 'g1',
      g2: 'g2',
      glyph_name: 'glyph-name',
      glyph_orientation_horizontal: 'glyph-orientation-horizontal',
      glyph_orientation_vertical: 'glyph-orientation-vertical',
      glyph_ref: 'glyphRef',
      gradient_transform: 'gradientTransform',
      gradient_units: 'gradientUnits',
      hanging: 'hanging',
      height: 'height',
      horiz_adv_x: 'horiz-adv-x',
      horiz_origin_x: 'horiz-origin-x',
      horiz_origin_y: 'horiz-origin-y',
      id: 'id',
      ideographic: 'ideographic',
      image_rendering: 'image-rendering',
      in: 'in',
      in2: 'in2',
      intercept: 'intercept',
      k: 'k',
      k1: 'k1',
      k2: 'k2',
      k3: 'k3',
      k4: 'k4',
      kernel_matrix: 'kernelMatrix',
      kernel_unit_length: 'kernelUnitLength',
      kerning: 'kerning',
      key_points: 'keyPoints',
      key_splines: 'keySplines',
      key_times: 'keyTimes',
      lang: 'lang',
      length_adjust: 'lengthAdjust',
      letter_spacing: 'letter-spacing',
      lighting_color: 'lighting-color',
      limiting_cone_angle: 'limitingConeAngle',
      local: 'local',
      marker_end: 'marker-end',
      marker_mid: 'marker-mid',
      marker_start: 'marker-start',
      marker_height: 'markerHeight',
      marker_units: 'markerUnits',
      marker_width: 'markerWidth',
      mask: 'mask',
      mask_content_units: 'maskContentUnits',
      mask_units: 'maskUnits',
      mathematical: 'mathematical',
      max: 'max',
      media: 'media',
      method: 'method',
      min: 'min',
      mode: 'mode',
      name: 'name',
      num_octaves: 'numOctaves',
      offset: 'offset',
      onabort: 'onabort',
      onactivate: 'onactivate',
      onbegin: 'onbegin',
      onclick: 'onclick',
      onend: 'onend',
      onerror: 'onerror',
      onfocusin: 'onfocusin',
      onfocusout: 'onfocusout',
      onload: 'onload',
      onmousedown: 'onmousedown',
      onmousemove: 'onmousemove',
      onmouseout: 'onmouseout',
      onmouseover: 'onmouseover',
      onmouseup: 'onmouseup',
      onrepeat: 'onrepeat',
      onresize: 'onresize',
      onscroll: 'onscroll',
      onunload: 'onunload',
      onzoom: 'onzoom',
      opacity: 'opacity',
      operator: 'operator',
      order: 'order',
      orient: 'orient',
      orientation: 'orientation',
      origin: 'origin',
      overflow: 'overflow',
      overline_position: 'overline-position',
      overline_thickness: 'overline-thickness',
      panose_1: 'panose-1',
      path: 'path',
      path_length: 'pathLength',
      pattern_content_units: 'patternContentUnits',
      pattern_transform: 'patternTransform',
      pattern_units: 'patternUnits',
      pointer_events: 'pointer-events',
      points: 'points',
      points_at_x: 'pointsAtX',
      points_at_y: 'pointsAtY',
      points_at_z: 'pointsAtZ',
      preserve_alpha: 'preserveAlpha',
      preserve_aspect_ratio: 'preserveAspectRatio',
      primitive_units: 'primitiveUnits',
      r: 'r',
      radius: 'radius',
      ref_x: 'refX',
      ref_y: 'refY',
      rendering_intent: 'rendering-intent',
      repeat_count: 'repeatCount',
      repeat_dur: 'repeatDur',
      required_extensions: 'requiredExtensions',
      required_features: 'requiredFeatures',
      restart: 'restart',
      result: 'result',
      rotate: 'rotate',
      rx: 'rx',
      ry: 'ry',
      scale: 'scale',
      seed: 'seed',
      shape_rendering: 'shape-rendering',
      slope: 'slope',
      spacing: 'spacing',
      specular_constant: 'specularConstant',
      specular_exponent: 'specularExponent',
      spread_method: 'spreadMethod',
      start_offset: 'startOffset',
      std_deviation: 'stdDeviation',
      stemh: 'stemh',
      stemv: 'stemv',
      stitch_tiles: 'stitchTiles',
      stop_color: 'stop-color',
      stop_opacity: 'stop-opacity',
      strikethrough_position: 'strikethrough-position',
      strikethrough_thickness: 'strikethrough-thickness',
      string: 'string',
      stroke: 'stroke',
      stroke_dasharray: 'stroke-dasharray',
      stroke_dashoffset: 'stroke-dashoffset',
      stroke_linecap: 'stroke-linecap',
      stroke_linejoin: 'stroke-linejoin',
      stroke_miterlimit: 'stroke-miterlimit',
      stroke_opacity: 'stroke-opacity',
      stroke_width: 'stroke-width',
      style: 'style',
      surface_scale: 'surfaceScale',
      system_language: 'systemLanguage',
      table_values: 'tableValues',
      target: 'target',
      target_x: 'targetX',
      target_y: 'targetY',
      text_anchor: 'text-anchor',
      text_decoration: 'text-decoration',
      text_rendering: 'text-rendering',
      text_length: 'textLength',
      title: 'title',
      to: 'to',
      transform: 'transform',
      type: 'type',
      u1: 'u1',
      u2: 'u2',
      underline_position: 'underline-position',
      underline_thickness: 'underline-thickness',
      unicode: 'unicode',
      unicode_bidi: 'unicode-bidi',
      unicode_range: 'unicode-range',
      units_per_em: 'units-per-em',
      v_alphabetic: 'v-alphabetic',
      v_hanging: 'v-hanging',
      v_ideographic: 'v-ideographic',
      v_mathematical: 'v-mathematical',
      values: 'values',
      version: 'version',
      vert_adv_y: 'vert-adv-y',
      vert_origin_x: 'vert-origin-x',
      vert_origin_y: 'vert-origin-y',
      view_box: 'viewBox',
      view_target: 'viewTarget',
      visibility: 'visibility',
      width: 'width',
      widths: 'widths',
      word_spacing: 'word-spacing',
      writing_mode: 'writing-mode',
      x: 'x',
      x_height: 'x-height',
      x1: 'x1',
      x2: 'x2',
      x_channel_selector: 'xChannelSelector',
      xlinkactuate: 'xlinkactuate',
      xlinkarcrole: 'xlinkarcrole',
      xlinkhref: 'xlinkhref',
      xlinkrole: 'xlinkrole',
      xlinkshow: 'xlinkshow',
      xlinktitle: 'xlinktitle',
      xlinktype: 'xlinktype',
      xmlbase: 'xmlbase',
      xmllang: 'xmllang',
      xmlspace: 'xmlspace',
      y: 'y',
      y1: 'y1',
      y2: 'y2',
      y_channel_selector: 'yChannelSelector',
      z: 'z',
      zoom_and_pan: 'zoomAndPan',
    }

    def self.sanitize_attributes attributes
      return attributes unless `attributes.$$is_hash`

      sanitized = attributes.each_with_object({}) do |(key, value), hash|
        if svg_attr = SVG_ATTRIBUTES[key]
          hash[svg_attr] = value
        elsif key[0, 2] == 'on'
          hash[key] = proc do |event|
            value.call(Bowser::Event.new(event))
          end
        else
          hash[key] = value
        end
      end

      sanitized
    end

    module_function

    SVG_TAGS.each do |method_name, tag_name|
      define_method(method_name) do |attributes, content|
        tag(tag_name, attributes, content)
      end
    end

    def tag tag_name, attributes=nil, content=nil
      if !(`attributes.$$is_hash || attributes === #{nil}`)
        content = attributes
        attributes = nil
      end

      VirtualDOM.svg(
        tag_name,
        SVGComponent.sanitize_attributes(attributes),
        Component.sanitize_content(content)
      )
    end
  end
end
