/*
 * Copyright 2021 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 com.google.android.exoplayer2.transformer.mh;

import static com.google.common.truth.Truth.assertWithMessage;
import static java.util.concurrent.TimeUnit.SECONDS;

import android.content.Context;
import android.net.Uri;
import android.os.Build;
import androidx.annotation.Nullable;
import androidx.test.platform.app.InstrumentationRegistry;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.transformer.Transformer;
import com.google.android.exoplayer2.util.Assertions;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
import org.checkerframework.checker.nullness.compatqual.NullableType;

/** Utilities for instrumentation tests. */
/* package */ final class AndroidTestUtil {
  public static final String MP4_ASSET_URI_STRING = "asset:///media/mp4/sample.mp4";
  public static final String SEF_ASSET_URI_STRING = "asset:///media/mp4/sample_sef_slow_motion.mp4";
  public static final String REMOTE_MP4_10_SECONDS_URI_STRING =
      "https://storage.googleapis.com/exoplayer-test-media-1/mp4/android-screens-10s.mp4";

  /** Information about the result of successfully running a transformer. */
  public static final class TransformationResult {
    public final String testId;
    public final long outputSizeBytes;

    private TransformationResult(String testId, long outputSizeBytes) {
      this.testId = testId;
      this.outputSizeBytes = outputSizeBytes;
    }
  }

  /**
   * Transforms the {@code uriString} with the {@link Transformer}.
   *
   * @param context The {@link Context}.
   * @param testId An identifier for the test.
   * @param transformer The {@link Transformer} that performs the transformation.
   * @param uriString The uri (as a {@link String}) that will be transformed.
   * @param timeoutSeconds The transformer timeout. An assertion confirms this is not exceeded.
   * @return The {@link TransformationResult}.
   * @throws Exception The cause of the transformation not completing.
   */
  public static TransformationResult runTransformer(
      Context context, String testId, Transformer transformer, String uriString, int timeoutSeconds)
      throws Exception {
    AtomicReference<@NullableType Exception> exceptionReference = new AtomicReference<>();
    CountDownLatch countDownLatch = new CountDownLatch(1);

    Transformer testTransformer =
        transformer
            .buildUpon()
            .setListener(
                new Transformer.Listener() {
                  @Override
                  public void onTransformationCompleted(MediaItem inputMediaItem) {
                    countDownLatch.countDown();
                  }

                  @Override
                  public void onTransformationError(MediaItem inputMediaItem, Exception exception) {
                    exceptionReference.set(exception);
                    countDownLatch.countDown();
                  }
                })
            .build();

    Uri uri = Uri.parse(uriString);
    File outputVideoFile = createExternalCacheFile(context, /* fileName= */ testId + "-output.mp4");
    InstrumentationRegistry.getInstrumentation()
        .runOnMainSync(
            () -> {
              try {
                testTransformer.startTransformation(
                    MediaItem.fromUri(uri), outputVideoFile.getAbsolutePath());
              } catch (IOException e) {
                exceptionReference.set(e);
              }
            });

    assertWithMessage("Transformer timed out after " + timeoutSeconds + " seconds.")
        .that(countDownLatch.await(timeoutSeconds, SECONDS))
        .isTrue();
    @Nullable Exception exception = exceptionReference.get();
    if (exception != null) {
      throw exception;
    }
    long outputSizeBytes = outputVideoFile.length();

    TransformationResult result = new TransformationResult(testId, outputSizeBytes);
    writeTransformationResultToFile(context, result);
    return result;
  }

  private static void writeTransformationResultToFile(Context context, TransformationResult result)
      throws IOException {
    File analysisFile =
        createExternalCacheFile(context, /* fileName= */ result.testId + "-result.txt");
    FileWriter fileWriter = new FileWriter(analysisFile);
    String fileContents =
        "test="
            + result.testId
            + ", deviceBrand="
            + Build.MANUFACTURER
            + ", deviceModel="
            + Build.MODEL
            + ", sdkVersion="
            + Build.VERSION.SDK_INT
            + ", outputSizeBytes="
            + result.outputSizeBytes;
    try {
      fileWriter.write(fileContents);
    } finally {
      fileWriter.close();
    }
  }

  private static File createExternalCacheFile(Context context, String fileName) throws IOException {
    File file = new File(context.getExternalCacheDir(), fileName);
    Assertions.checkState(
        !file.exists() || file.delete(), "Could not delete file: " + file.getAbsolutePath());
    Assertions.checkState(file.createNewFile(), "Could not create file: " + file.getAbsolutePath());
    return file;
  }

  private AndroidTestUtil() {}
}

@@ -4895,24 +4895,29 @@
 .txt%22);%0A    
+try (
 FileWriter f
@@ -4956,18 +4956,22 @@
 sisFile)
-;%0A
+) %7B%0A  
     Stri
@@ -5000,16 +5000,18 @@
     
+  
 %22test=%22%0A
     
@@ -5006,16 +5006,18 @@
 %22test=%22%0A
+  
         
@@ -5040,32 +5040,34 @@
 tId%0A            
+ 
+ 
 + %22, deviceBrand
@@ -5069,16 +5069,18 @@
 Brand=%22%0A
+  
         
@@ -5104,16 +5104,18 @@
 ACTURER%0A
+  
         
@@ -5141,32 +5141,34 @@
 l=%22%0A            
+  
 + Build.MODEL%0A  
@@ -5165,16 +5165,18 @@
 d.MODEL%0A
+  
         
@@ -5197,16 +5197,18 @@
 rsion=%22%0A
+  
         
@@ -5243,24 +5243,26 @@
             
+  
 + %22, outputS
@@ -5272,16 +5272,18 @@
 Bytes=%22%0A
+  
         
@@ -5312,26 +5312,16 @@
 eBytes;%0A
-    try %7B%0A
       fi
@@ -5354,50 +5354,8 @@
 s);%0A
-    %7D finally %7B%0A      fileWriter.close();%0A
     

Make use of try with-resources to auto close file.