/*
 * Copyright 2000-2015 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.util.ui;

import java.awt.*;
import java.awt.geom.GeneralPath;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;

/**
 * Draws a 'wavy' line of 1-pixel amplitude. Instances are cached for performance reasons.
 * <p>
 * This class is not thread-safe, it's supposed to be used in EDT only.
 */
public class WavePainter {
  private static final float STROKE_WIDTH = 0.7f;
  private static final float THICKNESS = 0.7f;

  private static final Map<Color, WavePainter> myPainters = new HashMap<Color, WavePainter>();
  private static final int PATTERN_WIDTH = 4000;

  private final BufferedImage myImage;

  private WavePainter(Color color) {
    myImage = UIUtil.createImage(PATTERN_WIDTH, 3, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = myImage.createGraphics();
    try {
      GraphicsUtil.setupAAPainting(g);
      g.setStroke(new BasicStroke(STROKE_WIDTH));
      g.setColor(color);
      g.setStroke(new BasicStroke(THICKNESS));
      double height = 1;
      double cycle = 4 * height;
      final double wavedAt = 3 - THICKNESS - height;
      GeneralPath wavePath = new GeneralPath();
      wavePath.moveTo(0, wavedAt - Math.cos(0 * 2 * Math.PI / cycle) * height);
      for (int x = 0; x < PATTERN_WIDTH; x++) {
        wavePath.lineTo(x, wavedAt - Math.cos(x * 2 * Math.PI / cycle) * height);
      }
      g.draw(wavePath);
    }
    finally {
      g.dispose();
    }
  }

  /**
   * Paints a wave in given coordinate range. <code>y</code> defines the lower boundary of painted wave.
   */
  public void paint(Graphics2D g, int xStart, int xEnd, int y) {
    Composite oldComposite = g.getComposite();
    g.setComposite(AlphaComposite.SrcOver);
    Shape clip = g.getClip();
    g.setClip(xStart, y-3, xEnd-xStart, 3);
    UIUtil.drawImage(g, myImage, xStart, y-3, null);
    g.setComposite(oldComposite);
    g.setClip(clip);
  }

  public static WavePainter forColor(Color color) {
    WavePainter painter = myPainters.get(color);
    if (painter == null) {
      painter = new WavePainter(color);
      // creating a new Color instance, as the one passed as parameter can be mutable (JBColor) and shouldn't be used as a map key
      //noinspection UseJBColor
      myPainters.put(new Color(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()), painter);
    }
    return painter;
  }
}

@@ -868,10 +868,11 @@
 * %3Cp
+/
 %3E%0A
-
  * T
@@ -1023,55 +1023,8 @@
 .7f;
-%0A  private static final float THICKNESS = 0.7f;
 %0A%0A  
@@ -1497,55 +1497,8 @@
 r);%0A
-      g.setStroke(new BasicStroke(THICKNESS));%0A
     
@@ -1588,17 +1588,20 @@
 3 - 
-THICKNESS
+STROKE_WIDTH
  - h
@@ -2277,17 +2277,21 @@
 t, y
--
+ - 
 3, xEnd
--
+ - 
 xSta
@@ -2340,17 +2340,19 @@
 Start, y
--
+ - 
 3, null)

optimize wave (underscore) painting