module Rocx
  module Properties
    module AttributeBuilder

      VALID_THEME_COLORS = %i(accent1 accent2 accent3 accent4 accent5 accent6 background1 background2 dark1 dark2 followedHyperlink hyperlink light1 light2 none text1 text2)

      VALID_TYPES = %i(apples
                       archedScallops
                       babyPacifier
                       babyRattle
                       balloons3Colors
                       balloonsHotAir
                       basicBlackDashes
                       basicBlackDots
                       basicBlackSquares
                       basicThinLines
                       basicWhiteDashes
                       basicWhiteDots
                       basicWhiteSquares
                       basicWideInline
                       basicWideMidline
                       basicWideOutline
                       bats
                       birds
                       birdsFlight
                       cabins
                       cakeSlice
                       candyCorn
                       celticKnotwork
                       certificateBanner
                       chainLink
                       champagneBottle
                       checkedBarBlack
                       checkedBarColor
                       checkered
                       christmasTree
                       circlesLines
                       circlesRectangles
                       classicalWave
                       clocks
                       compass
                       confetti
                       confettiGrays
                       confettiOutlines
                       confettiStreamers
                       confettiWhite
                       cornerTriangles
                       couponCutoutDashes
                       couponCutoutDots
                       crazyMaze
                       creaturesButterfly
                       creaturesFish
                       creaturesInsects
                       creaturesLadyBug
                       crossStitch
                       cup
                       custom
                       dashDotStroked
                       dashed
                       dashSmallGap
                       decoArch
                       decoArchColor
                       decoBlocks
                       diamondsGray
                       dotDash
                       dotDotDash
                       dotted
                       double
                       doubleD
                       doubleDiamonds
                       doubleWave
                       earth1
                       earth2
                       earth3
                       eclipsingSquares1
                       eclipsingSquares2
                       eggsBlack
                       fans
                       film
                       firecrackers
                       flowersBlockPrint
                       flowersDaisies
                       flowersModern1
                       flowersModern2
                       flowersPansy
                       flowersRedRose
                       flowersRoses
                       flowersTeacup
                       flowersTiny
                       gems
                       gingerbreadMan
                       gradient
                       handmade1
                       handmade2
                       heartBalloon
                       heartGray
                       hearts
                       heebieJeebies
                       holly
                       houseFunky
                       hypnotic
                       iceCreamCones
                       inset
                       lightBulb
                       lightning1
                       lightning2
                       mapleLeaf
                       mapleMuffins
                       mapPins
                       marquee
                       marqueeToothed
                       moons
                       mosaic
                       musicNotes
                       nil
                       none
                       northwest
                       outset
                       ovals
                       packages
                       palmsBlack
                       palmsColor
                       paperClips
                       papyrus
                       partyFavor
                       partyGlass
                       pencils
                       people
                       peopleHats
                       peopleWaving
                       poinsettias
                       postageStamp
                       pumpkin1
                       pushPinNote1
                       pushPinNote2
                       pyramids
                       pyramidsAbove
                       quadrants
                       rings
                       safari
                       sawtooth
                       sawtoothGray
                       scaredCat
                       seattle
                       shadowedSquares
                       shapes1
                       shapes2
                       sharksTeeth
                       shorebirdTracks
                       single
                       skyrocket
                       snowflakeFancy
                       snowflaskes
                       sombrero
                       southwest
                       stars
                       stars3d
                       starsBlack
                       starsShadowed
                       starsTop
                       sun
                       swirligig
                       thick
                       thickThinLargeGap
                       thickThinMediumGap
                       thickThinSmallGap
                       thinThickLargeGap
                       thinThickMediumGap
                       thinThickSmallGap
                       thinThickThinLargeGap
                       thinThickThinMediumGap
                       thinThickThinSmallGap
                       threeDEmboss
                       threeDEngrave
                       tornPaper
                       tornPaperBlack
                       trees
                       triangle1
                       triangle2
                       triangleCircle1
                       triangleCircle2
                       triangleParty
                       triangle
                       triple
                       twistedLines1
                       twistedLines2
                       vine
                       wave
                       waveline
                       weavingAngles
                       weavingBraid
                       weavingRibbon
                       weavingStrips
                       whiteFlowers
                       woodwork
                       xIllusions
                       zanyTriangles
                       zigZag
                       zigZagStitch)

      def self.included(base)
        base.extend(ClassMethods)
      end

      module ClassMethods
        def attribute(name, expects: nil, displays_as: nil)
          attr_reader name

          define_method "#{name}=" do |value|
            send(expects, value)
            instance_variable_set "@#{name}", value
          end

          camelized_name = name.to_s.gsub(/_([a-z])/i) { $1.upcase }.to_sym
          attributes[name] = displays_as || camelized_name
        end

        def attributes
          @attributes ||= {}
        end
      end

      def render?
        attributes.keys.map(&method(:send)).any?
      end

      def attributes
        self.class.attributes
      end

    private

      def xml_attributes
        attributes.each_with_object({}) do |(name, display), attrs|
          value = send(name)
          attrs["w:#{display}"] = value if value
        end
      end

      def true_or_false(value)
        message = "Invalid #{name}: frame must be true or false"
        raise ArgumentError, message unless [true, false].member? value
      end

      def hex_color(value)
        message = "Invalid #{name}: must be :auto or a hex color, e.g. 4F1B8C"
        raise ArgumentError, message unless value == :auto || value =~ /[0-9A-F]{6}/
      end

      def hex_digit(value)
        message = "Invalid #{name}: must be a two-digit hex number, e.g. BF"
        raise ArgumentError, message unless value =~ /[0-9A-F]{2}/
      end

      def integer(value)
        message = "Invalid #{name}: must be an integer"
        raise ArgumentError, message unless value.is_a?(Integer)
      end

      def positive_integer(value)
        message = "Invalid #{name}: must be a positive integer"
        raise ArgumentError, message unless value.is_a?(Integer) && value >= 0
      end

      def string(value)
        message = "Invalid #{name}: must be a string"
        raise ArgumentError, message unless value.is_a?(String)
      end

      def on_or_off(value)
        valid_in? value, [:on, :off]
      end

      def valid_theme_color(value)
        valid_in? value, VALID_THEME_COLORS
      end

      def valid_type(value)
        valid_in? value, VALID_TYPES
      end

      def valid_in?(value, list)
        message = "Invalid #{name}: must be one of #{list.join(", ")} (was #{value.inspect})"
        raise ArgumentError, message unless list.member?(value)
      end

    end
  end
end