/*
 * Copyright 2016 Eric Peterson
 *
 * 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 co.ericp.flashlight;

import android.annotation.TargetApi;
import android.content.Context;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.RequiresDevice;
import android.support.test.filters.SdkSuppress;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.*;

@RunWith(AndroidJUnit4.class)
@SdkSuppress(minSdkVersion = 23)
@TargetApi(23)
@RequiresDevice
@SmallTest
public class FlashlightImplTest {

    CameraManager cm;
    String id;

    @Before
    public void getCameraManager() {
        cm = (CameraManager) InstrumentationRegistry
                .getTargetContext()
                .getSystemService(Context.CAMERA_SERVICE);
    }

    @Test
    public void turnsOnFlashlight() throws Exception {

        FlashlightImpl flashlight = new FlashlightImpl(cm);

        flashlight.toggle();

        assertTrue(flashlight.isOn);

        //TODO test external state, not internal state
    }

    @After
    public void clearSingleton() {
        FlashlightProvider.clear();
    }

    @After
    public void shutdownFlash() throws Exception {
        for (String id : cm.getCameraIdList()) {
            Boolean hasCamera = cm
                    .getCameraCharacteristics(id)
                    .get(CameraCharacteristics.FLASH_INFO_AVAILABLE);

            if (hasCamera != null && hasCamera) {
                cm.setTorchMode(id, false);
            }
        }
    }
}

@@ -729,31 +729,23 @@
 2.Camera
-Characteristics
+Manager
 ;%0Aimport
@@ -775,32 +775,142 @@
 a2.CameraManager
+.TorchCallback;%0Aimport android.os.Handler;%0Aimport android.os.Looper;%0Aimport android.support.annotation.NonNull
 ;%0Aimport android
@@ -1472,16 +1472,80 @@
 ring id;
+%0A    boolean isOn = false;%0A    boolean awaitingCallback = false;
 %0A%0A    @B
@@ -1807,16 +1807,45 @@
 ption %7B%0A
+        // Given a flashlight
 %0A       
@@ -1901,85 +1901,267 @@
 m);%0A
-%0A        flashlight.toggle();%0A%0A        assertTrue(flashlight.isOn
+        id = flashlight.cameraId;%0A%0A        // When I toggle the flashlight%0A        flashlight.toggle();%0A%0A        // Then the flashlight should be on.%0A        awaitingCallback = true;%0A        BackgroundThread backgroundThread = new BackgroundThread(
 );%0A
-%0A
         
 //TO
@@ -2160,418 +2160,1293 @@
     
-//TODO test external state, not internal state%0A    %7D%0A%0A    @After%0A    public void clearSingleton() %7B%0A        FlashlightProvider.clear();%0A    %7D%0A%0A    @After%0A    public void shutdownFlash() throws Exception %7B%0A        for (String id : cm.getCameraIdList()) %7B%0A            Boolean hasCamera = cm%0A                    .getCameraCharacteristics(id)%0A                    .get(CameraCharacteristics.FLASH_INFO_AVAILABLE
+backgroundThread.start();%0A        synchronized (this) %7B%0A            while (backgroundThread.handler == null) %7B%0A                wait(500L);%0A            %7D%0A        %7D%0A        cm.registerTorchCallback(torchCallback, backgroundThread.handler);%0A%0A        while (awaitingCallback) %7B%0A            synchronized (this) %7B%0A                wait(500L);%0A            %7D%0A        %7D%0A%0A        assertTrue(isOn);%0A    %7D%0A%0A    @After%0A    public void clearSingleton() %7B%0A        FlashlightProvider.clear();%0A    %7D%0A%0A    @After%0A    public void shutdownFlash() throws Exception %7B%0A        cm.setTorchMode(id, false);%0A    %7D%0A%0A    @After%0A    public void unregisterCallback() %7B%0A        cm.unregisterTorchCallback(torchCallback);%0A    %7D%0A%0A    TorchCallback torchCallback = new TorchCallback() %7B%0A        @Override%0A        public void onTorchModeChanged(@NonNull String cameraId, boolean enabled) %7B%0A            if (cameraId.equals(id)) %7B%0A                isOn = enabled;%0A                awaitingCallback = false;%0A                synchronized (FlashlightImplTest.this) %7B%0A                    FlashlightImplTest.this.notifyAll();%0A                %7D%0A            %7D%0A        %7D%0A    %7D;%0A%0A    private class BackgroundThread extends Thread %7B%0A        Handler handler;%0A%0A        @Override%0A        public void run() %7B%0A            Looper.prepare(
 );%0A
-%0A
     
@@ -3457,103 +3457,179 @@
     
-if (hasCamera != null && hasCamera) %7B%0A                cm.setTorchMode(id, false);%0A            %7D
+handler = new Handler();%0A            synchronized (FlashlightImplTest.this) %7B%0A                FlashlightImplTest.this.notifyAll();%0A            %7D%0A            Looper.loop();
 %0A   

Test external state, not internal state in FlashlightImplTest