module Savio
  class Slider
    include IORenderable

    attr_reader :length, :min, :max, :size, :value

    @@sliders = []
    def self.sliders
      @@sliders
    end

    def initialize(args = {})
      @@sliders.push(self)
      super(args)

      @length = args[:length]   || 100
      @min = args[:min]         || 0
      @max = args[:max]         || 100

      @style = args[:style] || 'knob'
      if @style != 'knob' && @style != 'fill'
        @style = 'knob'
      end

      @value = args[:value]     || rand(@min..@max)
      @showValue = args[:showValue] || true

      @labelColor  = args[:labelColor]  || Savio::Colors::White
      @sliderColor = args[:sliderColor] || Savio::Colors::Gray
      @knobColor   = args[:knobColor]   || Savio::Colors::Green

      @onChange = Proc.new {}

      build()
    end

    def onChange(&proc)
      @onChange = proc
    end

    def style=(style)
      if style == 'knob' || style == 'fill'
        @style = style
        rebuild()
      end
    end
    def length=(length)
      @length = length.clamp(1, Window.width-@x)
      rebuild()
    end
    def showValue=(state)
      @showValue = state
      rebuild()
    end
    def labelColor=(c)
      @labelColor = c
      rebuild()
    end
    def sliderColor=(c)
      @sliderColor = c
      rebuild()
    end
    def knobColor=(c)
      @knobColor = c
      rebuild()
    end
    def min=(x)
      @min = x
      setValue(@value)
    end
    def max=(x)
      @max = x
      setValue(@value)
    end

    def renderKnobTo(x)
      if x.between?(@x, @x+@length)
        case @style
        when 'knob'
          @knob.x = x
        when 'fill'
          @knob.width = x - @x
        end
      end
    end

    def moveKnob(x)
      if x.between?(@x, @x+@length)
        renderKnobTo(x)

        to_max = @max
        to_min = @min
        from_max = @x + @length
        from_min = @x
        pos = x
        @value = (((to_max - to_min) * (pos - from_min)) / (from_max - from_min) + to_min)
        if @showValue == true
          @label.text = @value.round(2).to_s
        end
        @onChange.call
      end
    end

    def value=(value)
      setValue(value)
    end

    def setValue(value)
      if value.between?(@min, @max)
        to_max = @x + @length
        to_min = @x
        from_max = @max.to_f
        from_min = @min.to_f
        pos = value
        knobX = (((to_max - to_min) * (pos - from_min)) / (from_max - from_min) + to_min)
        @value = value
        if @showValue == true
          @label.text = @value.round(2).to_s
        end
        renderKnobTo(knobX)
      else
        setValue(@min)
      end
    end

    def remove()
      super()
      @sliderLine.remove
      @knob.remove
      @label.remove
      @nameLabel.remove
    end

    def add()
      super()
      @sliderLine.add
      @knob.add
      @label.add
      @nameLabel.add
    end

    def build()
      @shown = true

      @sliderLine = Line.new(
        x1: @x, y1: @y,
        x2: @x+@length, y2: @y,
        width: @size,
        color: @sliderColor,
        z: @z
      )

      case @style
      when 'knob'
        @knob = Circle.new(
          x: @x, y: @y,
          radius: @size * 1.2,
          color: @knobColor,
          z: @z+1
        )
      when 'fill'
        @knob = Rectangle.new(
          x: @x, y: @y,
          width: 0 , height: @size,
          color: @knobColor,
          z: @z+1
        )
      end

      @label = Text.new(
        @value.to_s,
        x: @x + @length + @size, y: @y - @size * 1.75,
        size: @size * 2.5,
        color: @labelColor,
        z: @z+1
      )

      @label.y = @y + @sliderLine.width / 2 - @label.height / 2

      @nameLabel = Text.new(
        @displayName.to_s,
        x: @x, y: @y - @size * 3 - @size,
        size: @size * 2.5,
        color: @labelColor,
        z: @z+2
      )

      setValue(@value)

      if @showValue == false
        @label.remove
      end
    end
  end
end