/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * 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 android.text;

import static android.text.Layout.Alignment.ALIGN_NORMAL;

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.perftests.utils.PerfTestActivity;
import android.text.style.ReplacementSpan;
import android.util.ArraySet;

import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

import java.util.Arrays;
import java.util.Collection;
import java.util.Random;

@LargeTest
@RunWith(Parameterized.class)
public class DynamicLayoutPerfTest {

    @Parameters(name = "{0}")
    public static Collection cases() {
        return Arrays.asList(new Object[][] {
            { "0%", 0.0f},
            { "1%", 0.01f},
            { "5%", 0.05f},
            { "30%", 0.3f},
            { "100%", 1.0f},
        });
    }

    private final String mMetricKey;
    private final float mProbability;
    public DynamicLayoutPerfTest(String metricKey, float probability) {
        mMetricKey = metricKey;
        mProbability = probability;
    }

    private static class MockReplacementSpan extends ReplacementSpan {
        @Override
        public int getSize(Paint paint, CharSequence text, int start, int end, FontMetricsInt fm) {
            return 10;
        }

        @Override
        public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top,
                int y, int bottom, Paint paint) {
        }
    }

    @Rule
    public ActivityTestRule<PerfTestActivity> mActivityRule =
            new ActivityTestRule<>(PerfTestActivity.class);

    @Rule
    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();


    private final static String ALPHABETS = "abcdefghijklmnopqrstuvwxyz";

    private SpannableStringBuilder getText() {
        final long seed = 1234567890;
        final Random r = new Random(seed);
        final SpannableStringBuilder builder = new SpannableStringBuilder();

        final int paragraphCount = 100;
        for (int i = 0; i < paragraphCount; i++) {
            final int wordCount = 5 + r.nextInt(20);
            final boolean containsReplacementSpan = r.nextFloat() < mProbability;
            final int replacedWordIndex = containsReplacementSpan ? r.nextInt(wordCount) : -1;
            for (int j = 0; j < wordCount; j++) {
                final int startIndex = builder.length();
                final int wordLength = 1 + r.nextInt(10);
                for (int k = 0; k < wordLength; k++) {
                    char c = ALPHABETS.charAt(r.nextInt(ALPHABETS.length()));
                    builder.append(c);
                }
                if (replacedWordIndex == j) {
                    builder.setSpan(new MockReplacementSpan(), startIndex,
                            builder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                }
                builder.append(' ');
            }
            builder.append('\n');
        }
        return builder;
    }

    @Test
    public void testGetBlocksAlwaysNeedToBeRedrawn() {
        final SpannableStringBuilder text = getText();
        final DynamicLayout layout = new DynamicLayout(text, new TextPaint(), 1000,
                ALIGN_NORMAL, 0, 0, false);

        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        final int steps = 10;
        while (state.keepRunning()) {
            for (int i = 0; i < steps; i++) {
                int offset = (text.length() * i) / steps;
                text.insert(offset, "\n");
                text.delete(offset, offset + 1);
                final ArraySet<Integer> set = layout.getBlocksAlwaysNeedToBeRedrawn();
                if (set != null) {
                    for (int j = 0; j < set.size(); j++) {
                        layout.getBlockIndex(set.valueAt(j));
                    }
                }
            }
        }
    }
}
