/*
 * Copyright (C) 2017 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.media.cts.bitstreams.app;

import android.app.Instrumentation;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.media.MediaCodec;
import android.media.MediaCodecInfo.CodecProfileLevel;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.media.cts.bitstreams.MediaBitstreams;
import android.os.Bundle;
import android.os.Debug;
import android.util.Xml;

import androidx.test.InstrumentationRegistry;

import com.android.compatibility.common.util.DynamicConfigDeviceSide;
import com.android.compatibility.common.util.MediaUtils;

import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.xmlpull.v1.XmlSerializer;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * Test class that uses device-side media APIs to determine up to which resolution MediaPreparer
 * should copy media files for CtsMediaStressTestCases.
 */
@RunWith(JUnit4.class)
public class MediaBitstreamsDeviceSideTest {

    private static final String KEY_SIZE = "size";
    private static final String UTF_8 = "utf-8";
    /** Instrumentation status code used to write resolution to metrics */
    private static final int INST_STATUS_IN_PROGRESS = 2;

    private static File mAppCache = InstrumentationRegistry.getContext().getExternalCacheDir();
    private static String mDeviceBitstreamsPath = InstrumentationRegistry.getArguments().getString(
            MediaBitstreams.OPT_DEVICE_BITSTREAMS_PATH,
            MediaBitstreams.DEFAULT_DEVICE_BITSTEAMS_PATH);

    @BeforeClass
    public static void setUp() {
        Bundle args = InstrumentationRegistry.getArguments();
        String debugStr = args.getString(MediaBitstreams.OPT_DEBUG_TARGET_DEVICE, "false");
        boolean debug = Boolean.parseBoolean(debugStr);
        if (debug && !Debug.isDebuggerConnected()) {
            Debug.waitForDebugger();
        }
    }

    private static void fixFormat(MediaFormat format, String path) {
        // TODO(b/137684344): Revisit so that we can get this information from
        //                    the bitstream or the extractor.
        if (path.indexOf("/10bit/") < 0) {
            return;
        }
        String mime = format.getString(MediaFormat.KEY_MIME);
        int profile = -1, level = -1;
        if (mime.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) {
            profile = CodecProfileLevel.VP9Profile2;
            level = CodecProfileLevel.VP9Level1;
        } else if (mime.equals(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
            profile = CodecProfileLevel.HEVCProfileMain10;
            level = CodecProfileLevel.HEVCMainTierLevel1;
        } else if (mime.equals(MediaFormat.MIMETYPE_VIDEO_AV1)) {
            profile = CodecProfileLevel.AV1ProfileMain10;
            level = CodecProfileLevel.AV1Level2;
        } else {
            return;
        }

        if (!format.containsKey(MediaFormat.KEY_PROFILE)) {
            format.setInteger(MediaFormat.KEY_PROFILE, profile);
        }
        if (!format.containsKey(MediaFormat.KEY_LEVEL)) {
            format.setInteger(MediaFormat.KEY_LEVEL, level);
        }
    }

    static interface ReportCallback {
        void run(OutputStream out) throws Exception;
    }

    static class GenerateBitstreamsFormatsXml implements ReportCallback {
        @Override
        public void run(OutputStream out) throws Exception {

            String[] keys = new String[] {
                    MediaFormat.KEY_WIDTH,
                    MediaFormat.KEY_HEIGHT,
                    MediaFormat.KEY_FRAME_RATE,
                    MediaFormat.KEY_PROFILE,
                    MediaFormat.KEY_LEVEL,
                    MediaFormat.KEY_BIT_RATE};

            XmlSerializer formats = Xml.newSerializer();
            formats.setOutput(out, UTF_8);
            formats.startDocument(UTF_8, true);
            formats.startTag(null, MediaBitstreams.DYNAMIC_CONFIG);

            DynamicConfigDeviceSide config = new DynamicConfigDeviceSide(MediaBitstreams.K_MODULE);
            for (String path : config.keySet()) {

                formats.startTag(null, MediaBitstreams.DYNAMIC_CONFIG_ENTRY);
                formats.attribute(null, MediaBitstreams.DYNAMIC_CONFIG_KEY, path);
                formats.startTag(null, MediaBitstreams.DYNAMIC_CONFIG_VALUE);

                String formatStr = config.getValue(path);
                if (formatStr != null && !formatStr.isEmpty()) {
                    formats.text(formatStr);
                } else {
                    File media = new File(mDeviceBitstreamsPath, path);
                    String fullPath = media.getPath();
                    MediaFormat format = MediaUtils.getTrackFormatForPath(null, fullPath, "video");
                    StringBuilder formatStringBuilder = new StringBuilder(MediaFormat.KEY_MIME);
                    formatStringBuilder.append('=').append(format.getString(MediaFormat.KEY_MIME));
                    formatStringBuilder.append(',').append(KEY_SIZE)
                            .append('=').append(media.length());
                    for (String key : keys) {
                        formatStringBuilder.append(',').append(key).append('=');
                        if (format.containsKey(key)) {
                            formatStringBuilder.append(format.getInteger(key));
                        }
                    }
                    formats.text(formatStringBuilder.toString());
                }

                formats.endTag(null, MediaBitstreams.DYNAMIC_CONFIG_VALUE);
                formats.endTag(null, MediaBitstreams.DYNAMIC_CONFIG_ENTRY);

            }

            formats.endTag(null, MediaBitstreams.DYNAMIC_CONFIG);
            formats.endDocument();

        }
    }

    static class GenerateSupportedBitstreamsFormatsTxt implements ReportCallback {

        @Override
        public void run(OutputStream out) throws Exception {

            PrintStream ps = new PrintStream(out);
            Bundle args = InstrumentationRegistry.getArguments();
            String prefix = args.getString(MediaBitstreams.OPT_BITSTREAMS_PREFIX, "");
            DynamicConfigDeviceSide config = new DynamicConfigDeviceSide(MediaBitstreams.K_MODULE);

            for (String path : config.keySet()) {

                if (!path.startsWith(prefix)) {
                    continue;
                }

                String formatStr = config.getValue(path);
                if (formatStr == null || formatStr.isEmpty()) {
                    continue;
                }

                MediaFormat format = parseTrackFormat(formatStr);
                String mime = format.getString(MediaFormat.KEY_MIME);
                String[] decoders = MediaUtils.getDecoderNamesForMime(mime);
                fixFormat(format, path);

                ps.println(path);
                ps.println(decoders.length);
                for (String name : decoders) {
                    ps.println(name);
                    ps.println(MediaUtils.supports(name, format));
                }

            }

            ps.flush();
        }
    }

    static class TestBitstreamsConformance implements ReportCallback {

        ExecutorService mExecutorService;

        private SharedPreferences getSettings() {
            Context ctx = InstrumentationRegistry.getContext();
            SharedPreferences settings = ctx.getSharedPreferences(MediaBitstreams.K_MODULE, 0);
            return settings;
        }

        private void setup() {
            Bundle args = InstrumentationRegistry.getArguments();
            String lastCrash = args.getString(MediaBitstreams.OPT_LAST_CRASH);
            if (lastCrash != null) {
                SharedPreferences settings = getSettings();
                int n = settings.getInt(lastCrash, 0);
                Editor editor = settings.edit();
                editor.putInt(lastCrash, n + 1);
                editor.commit();
            }
        }

        @Override
        public void run(OutputStream out) throws Exception {
            setup();
            mExecutorService = Executors.newFixedThreadPool(3);
            try (
                Scanner sc = new Scanner(
                        new File(mDeviceBitstreamsPath, MediaBitstreams.K_BITSTREAMS_LIST_TXT));
                PrintStream ps = new PrintStream(out, true)
            ) {
                while (sc.hasNextLine()) {
                    verifyBitstream(ps, sc.nextLine());
                }
            } finally {
                mExecutorService.shutdown();
            }
        }

        private List<String> getDecodersForPath(String path) throws IOException {
            List<String> decoders = new ArrayList<>();
            MediaExtractor ex = new MediaExtractor();
            try {
                ex.setDataSource(path);
                MediaFormat format = ex.getTrackFormat(0);
                fixFormat(format, path);
                boolean[] vendors = new boolean[] {false, true};
                for (boolean v : vendors) {
                    for (String name : MediaUtils.getDecoderNames(v, format)) {
                        decoders.add(name);
                    }
                }
            } finally {
                ex.release();
            }
            return decoders;
        }

        private List<String> getFrameChecksumsForPath(String path) throws IOException {
            String md5Path = MediaBitstreams.getMd5Path(path);
            List<String> frameMD5Sums = Files.readAllLines(
                    new File(mDeviceBitstreamsPath, md5Path).toPath());
            for (int i = 0; i < frameMD5Sums.size(); i++) {
                String line = frameMD5Sums.get(i);
                frameMD5Sums.set(i, line.split(" ")[0]);
            }
            return frameMD5Sums;
        }

        private void verifyBitstream(PrintStream ps, String relativePath) {
            ps.println(relativePath);

            List<String> decoders = new ArrayList<>();
            List<String> frameChecksums = new ArrayList<>();
            SharedPreferences settings = getSettings();
            String fullPath = new File(mDeviceBitstreamsPath, relativePath).toString();
            try {
                String lastCrash = MediaBitstreams.generateCrashSignature(relativePath, "");
                if (settings.getInt(lastCrash, 0) >= 3) {
                    ps.println(MediaBitstreams.K_NATIVE_CRASH);
                    return;
                }
                decoders = getDecodersForPath(fullPath);
                frameChecksums = getFrameChecksumsForPath(relativePath);
                ps.println(false);
            } catch (Exception e) {
                ps.println(true);
                ps.println(e.toString());
                return;
            }

            ps.println(decoders.size());
            for (String name : decoders) {
                ps.println(name);
                String lastCrash = MediaBitstreams.generateCrashSignature(relativePath, name);
                if (settings.getInt(lastCrash, 0) >= 3) {
                    ps.println(MediaBitstreams.K_NATIVE_CRASH);
                } else {
                    ps.println(verifyBitstream(fullPath, name, frameChecksums));
                }
            }

        }

        private String verifyBitstream(String path, String name, List<String> frameChecksums)  {
            MediaExtractor ex = new MediaExtractor();
            MediaCodec d = null;
            try {
                Future<MediaCodec> dec = mExecutorService.submit(new Callable<MediaCodec>() {
                    @Override
                    public MediaCodec call() throws Exception {
                        return MediaCodec.createByCodecName(name);
                    }
                });
                MediaCodec decoder = d = dec.get(1, TimeUnit.SECONDS);
                Future<Boolean> conform = mExecutorService.submit(new Callable<Boolean>() {
                    @Override
                    public Boolean call() throws Exception {
                        ex.setDataSource(path);
                        ex.selectTrack(0);
                        ex.seekTo(0, MediaExtractor.SEEK_TO_NEXT_SYNC);
                        return MediaUtils.verifyDecoder(decoder, ex, frameChecksums);
                    }
                });
                return conform.get(15, TimeUnit.SECONDS).toString();
            } catch (Exception e) {
                return e.toString();
            } finally {
                ex.release();
                if (d != null) {
                    d.release();
                }
            }
        }

    }

    private void generateReportFile(String suffix, String reportKey, ReportCallback callback)
            throws IOException, FileNotFoundException, Exception {

        OutputStream out = new ByteArrayOutputStream(0);

        try {

            File tmpf = File.createTempFile(getClass().getSimpleName(), suffix, mAppCache);
            Instrumentation inst = InstrumentationRegistry.getInstrumentation();
            Bundle bundle = new Bundle();
            bundle.putString(MediaBitstreams.KEY_APP_CACHE_DIR, mAppCache.getCanonicalPath());
            bundle.putString(reportKey, tmpf.getCanonicalPath());
            inst.sendStatus(INST_STATUS_IN_PROGRESS, bundle);

            out = new FileOutputStream(tmpf);
            callback.run(out);
            out.flush();

        } finally {

            out.close();

        }
    }

    @Test
    public void testGetBitstreamsFormats() throws Exception {
        generateReportFile(".xml",
                MediaBitstreams.KEY_BITSTREAMS_FORMATS_XML,
                new GenerateBitstreamsFormatsXml());
    }

    @Test
    public void testGetSupportedBitstreams() throws Exception {
        generateReportFile(".txt",
                MediaBitstreams.KEY_SUPPORTED_BITSTREAMS_TXT,
                new GenerateSupportedBitstreamsFormatsTxt());
    }

    @Test
    public void testBitstreamsConformance() throws Exception {
        generateReportFile(".txt",
                MediaBitstreams.KEY_BITSTREAMS_VALIDATION_TXT,
                new TestBitstreamsConformance());
    }

    /**
     * Converts a single media track format string into a MediaFormat object
     *
     * @param trackFormatString a string representation of the format of one media track
     * @return a MediaFormat
     */
    private static MediaFormat parseTrackFormat(String trackFormatString) {
        MediaFormat format = new MediaFormat();
        format.setString(MediaFormat.KEY_MIME, "");
        for (String entry : trackFormatString.split(",")) {
            String[] kv = entry.split("=");
            if (kv.length < 2 || kv[1].isEmpty()) {
                continue;
            }
            String k = kv[0];
            String v = kv[1];
            try {
                format.setInteger(k, Integer.parseInt(v));
            } catch (NumberFormatException e) {
                format.setString(k, v);
            }
        }
        return format;
    }
}
