require "spec_helper"

describe ChunkyPNG::Canvas::Drawing do
  describe "#compose_pixel" do
    subject { ChunkyPNG::Canvas.new(1, 1, ChunkyPNG::Color.rgb(200, 150, 100)) }

    it "should compose colors correctly" do
      subject.compose_pixel(0, 0, ChunkyPNG::Color(100, 150, 200, 128))
      expect(subject[0, 0]).to eql ChunkyPNG::Color(150, 150, 150)
    end

    it "should return the composed color" do
      expect(subject.compose_pixel(0, 0, ChunkyPNG::Color.rgba(100, 150, 200, 128))).to eql ChunkyPNG::Color.rgb(150, 150, 150)
    end

    it "should do nothing when the coordinates are out of bounds" do
      expect(subject.compose_pixel(1, -1, :black)).to be_nil
      expect { subject.compose_pixel(1, -1, :black) }.to_not change { subject[0, 0] }
    end
  end

  describe "#line" do
    it "should draw lines correctly with anti-aliasing" do
      canvas = ChunkyPNG::Canvas.new(31, 31, ChunkyPNG::Color::WHITE)

      # rubocop:disable Layout/SpaceInsideParens # for improved readability
      canvas.line( 0,  0, 30, 30, ChunkyPNG::Color::BLACK)
      canvas.line( 0, 30, 30,  0, ChunkyPNG::Color::BLACK)
      canvas.line(15, 30, 15,  0, ChunkyPNG::Color.rgba(200,   0,   0, 128))
      canvas.line( 0, 15, 30, 15, ChunkyPNG::Color.rgba(200,   0,   0, 128))
      canvas.line(30, 30,  0, 15, ChunkyPNG::Color.rgba(  0, 200,   0, 128), false)
      canvas.line( 0, 15, 30,  0, ChunkyPNG::Color.rgba(  0, 200,   0, 128))
      canvas.line( 0, 30, 15,  0, ChunkyPNG::Color.rgba(  0,   0, 200, 128), false)
      canvas.line(15,  0, 30, 30, ChunkyPNG::Color.rgba(  0,   0, 200, 128))
      # rubocop:enable Layout/SpaceInsideParens

      expect(canvas).to eql reference_canvas("lines")
    end

    it "should draw partial lines if the coordinates are partially out of bounds" do
      canvas = ChunkyPNG::Canvas.new(1, 2, ChunkyPNG::Color::WHITE)
      canvas.line(-5, -5, 0, 0, "#000000")
      expect(canvas.pixels).to eql [ChunkyPNG::Color::BLACK, ChunkyPNG::Color::WHITE]
    end

    it "should return itself to allow chaining" do
      canvas = ChunkyPNG::Canvas.new(16, 16, ChunkyPNG::Color::WHITE)
      expect(canvas.line(1, 1, 10, 10, :black)).to equal(canvas)
    end

    it "should draw a single pixel when the start and end point are the same" do
      canvas = ChunkyPNG::Canvas.new(5, 5, ChunkyPNG::Color::WHITE)
      canvas.line(2, 2, 2, 2, ChunkyPNG::Color::BLACK)

      non_white_pixels = canvas.pixels.count { |pixel| pixel != ChunkyPNG::Color::WHITE }
      expect(non_white_pixels).to eql 1
    end
  end

  describe "#rect" do
    subject { ChunkyPNG::Canvas.new(16, 16, "#ffffff") }

    it "should draw a rectangle with the correct colors" do
      subject.rect(1, 1, 10, 10, ChunkyPNG::Color.rgba(0, 255, 0, 80), ChunkyPNG::Color.rgba(255, 0, 0, 100))
      subject.rect(5, 5, 14, 14, ChunkyPNG::Color.rgba(0, 0, 255, 160), ChunkyPNG::Color.rgba(255, 255, 0, 100))
      expect(subject).to eql reference_canvas("rect")
    end

    it "should return itself to allow chaining" do
      expect(subject.rect(1, 1, 10, 10)).to equal(subject)
    end

    it "should draw partial rectangles if the coordinates are partially out of bounds" do
      subject.rect(0, 0, 20, 20, :black, :white)
      expect(subject[0, 0]).to eql ChunkyPNG::Color::BLACK
    end

    it "should draw the rectangle fill only if the coordinates are fully out of bounds" do
      subject.rect(-1, -1, 20, 20, :black, :white)
      expect(subject[0, 0]).to eql ChunkyPNG::Color::WHITE
    end
  end

  describe "#circle" do
    subject { ChunkyPNG::Canvas.new(32, 32, ChunkyPNG::Color.rgba(0, 0, 255, 128)) }

    it "should draw circles" do
      subject.circle(11, 11, 10, ChunkyPNG::Color("red @ 0.5"), ChunkyPNG::Color("white @ 0.2"))
      subject.circle(21, 21, 10, ChunkyPNG::Color("green @ 0.5"))
      expect(subject).to eql reference_canvas("circles")
    end

    it "should draw partial circles when going of the canvas bounds" do
      subject.circle(0, 0, 10, ChunkyPNG::Color(:red))
      subject.circle(31, 16, 10, ChunkyPNG::Color(:black), ChunkyPNG::Color(:white, 0xaa))
      expect(subject).to eql reference_canvas("partial_circles")
    end

    it "should return itself to allow chaining" do
      expect(subject.circle(10, 10, 5, :red)).to equal(subject)
    end
  end

  describe "#polygon" do
    subject { ChunkyPNG::Canvas.new(22, 22) }

    it "should draw an filled triangle when using 3 control points" do
      subject.polygon("(2,2) (20,5) (5,20)", ChunkyPNG::Color(:black, 0xaa), ChunkyPNG::Color(:red, 0x44))
      expect(subject).to eql reference_canvas("polygon_triangle_filled")
    end

    it "should draw a unfilled polygon with 6 control points" do
      subject.polygon("(2,2) (12, 1) (20,5) (18,18) (5,20) (1,12)", ChunkyPNG::Color(:black))
      expect(subject).to eql reference_canvas("polygon_unfilled")
    end

    it "should draw a vertically crossed filled polygon with 4 control points" do
      subject.polygon("(2,2) (21,2) (2,21) (21,21)", ChunkyPNG::Color(:black), ChunkyPNG::Color(:red))
      expect(subject).to eql reference_canvas("polygon_filled_vertical")
    end

    it "should draw a vertically crossed filled polygon with 4 control points" do
      subject.polygon("(2,2) (2,21) (21,2) (21,21)", ChunkyPNG::Color(:black), ChunkyPNG::Color(:red))
      expect(subject).to eql reference_canvas("polygon_filled_horizontal")
    end

    it "should return itself to allow chaining" do
      expect(subject.polygon("(2,2) (20,5) (5,20)")).to equal(subject)
    end
  end

  describe "#bezier_curve" do
    subject { ChunkyPNG::Canvas.new(24, 24, ChunkyPNG::Color::WHITE) }

    it "should draw a bezier curve starting at the first point" do
      subject.bezier_curve("3,20 10,10, 20,20")
      expect(subject[3, 20]).to eql ChunkyPNG::Color::BLACK
    end

    it "should draw a bezier curve ending at the last point" do
      subject.bezier_curve("3,20 10,10, 20,20")
      expect(subject[20, 20]).to eql ChunkyPNG::Color::BLACK
    end

    it "should draw a bezier curve with a color of green" do
      subject.bezier_curve("3,20 10,10, 20,20", :green)
      expect(subject[3, 20]).to eql ChunkyPNG::Color(:green)
    end

    it "should draw a three point bezier curve" do
      expect(subject.bezier_curve("1,23 12,10 23,23")).to eql reference_canvas("bezier_three_point")
    end

    it "should draw a three point bezier curve flipped" do
      expect(subject.bezier_curve("1,1 12,15 23,1")).to eql reference_canvas("bezier_three_point_flipped")
    end

    it "should draw a four point bezier curve" do
      expect(subject.bezier_curve("1,23 1,5 22,5 22,23")).to eql reference_canvas("bezier_four_point")
    end

    it "should draw a four point bezier curve flipped" do
      expect(subject.bezier_curve("1,1 1,19 22,19 22,1")).to eql reference_canvas("bezier_four_point_flipped")
    end

    it "should draw a four point bezier curve with a shape of an s" do
      expect(subject.bezier_curve("1,23 1,5 22,23 22,5")).to eql reference_canvas("bezier_four_point_s")
    end

    it "should draw a five point bezier curve" do
      expect(subject.bezier_curve("10,23 1,10 12,5 23,10 14,23")).to eql reference_canvas("bezier_five_point")
    end

    it "should draw a six point bezier curve" do
      expect(subject.bezier_curve("1,23 4,15 8,20 2,2 23,15 23,1")).to eql reference_canvas("bezier_six_point")
    end
  end
end
