/*
 * Copyright (C) 2018 Square, Inc.
 *
 * 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.squareup.leakcanary.internal;

import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.text.SpannableStringBuilder;
import android.text.style.ReplacementSpan;
import android.text.style.UnderlineSpan;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.squareup.leakcanary.R;

/**
 * Inspired from https://github.com/flavienlaurent/spans and
 * https://github.com/andyxialm/WavyLineView
 */
class SquigglySpan extends ReplacementSpan {


  public static void replaceUnderlineSpans(SpannableStringBuilder builder, Resources resources) {
    UnderlineSpan[] underlineSpans = builder.getSpans(0, builder.length(), UnderlineSpan.class);
    for (UnderlineSpan span : underlineSpans) {
      int start = builder.getSpanStart(span);
      int end = builder.getSpanEnd(span);
      builder.removeSpan(span);
      builder.setSpan(new SquigglySpan(resources), start, end, 0);
    }
  }

  private final Paint squigglyPaint;
  private final Path path;
  private final int referenceColor;
  private final float halfStrokeWidth;
  private final float amplitude;
  private final float halfWaveHeight;
  private final float periodDegrees;

  private int width;

  SquigglySpan(Resources resources) {
    squigglyPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    squigglyPaint.setStyle(Paint.Style.STROKE);
    squigglyPaint.setColor(resources.getColor(R.color.leak_canary_leak));
    float strokeWidth =
        resources.getDimensionPixelSize(R.dimen.leak_canary_squiggly_span_stroke_width);
    squigglyPaint.setStrokeWidth(strokeWidth);

    halfStrokeWidth = strokeWidth / 2;
    amplitude = resources.getDimensionPixelSize(R.dimen.leak_canary_squiggly_span_amplitude);
    periodDegrees =
        resources.getDimensionPixelSize(R.dimen.leak_canary_squiggly_span_period_degrees);
    path = new Path();
    float waveHeight = 2 * amplitude + strokeWidth;
    halfWaveHeight = waveHeight / 2;
    referenceColor = resources.getColor(R.color.leak_canary_reference);
  }

  @Override
  public int getSize(@NonNull Paint paint, CharSequence text, int start, int end,
                     @Nullable Paint.FontMetricsInt fm) {
    width = (int) paint.measureText(text, start, end);
    return width;
  }

  @Override
  public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top,
                   int y, int bottom, @NonNull Paint paint) {
    squigglyHorizontalPath(path,
        x + halfStrokeWidth,
        x + width - halfStrokeWidth,
        bottom - halfWaveHeight,
        amplitude, periodDegrees);
    canvas.drawPath(path, squigglyPaint);

    paint.setColor(referenceColor);
    canvas.drawText(text, start, end, x, y, paint);
  }

  private static void squigglyHorizontalPath(Path path, float left, float right, float centerY,
                                             float amplitude,
                                             float periodDegrees) {
    path.reset();

    float y;
    path.moveTo(left, centerY);
    float period = (float) (2 * Math.PI / periodDegrees);

    for (float x = 0; x <= right - left; x += 1) {
      y = (float) (amplitude * Math.sin(40 + period * x) + centerY);
      path.lineTo(left + x, y);
    }
  }
}