# Copyright 2013 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.
"""Verifies settings latch on the correct frame."""


import logging
import os.path
import matplotlib
from matplotlib import pylab
from mobly import test_runner

import its_base_test
import camera_properties_utils
import capture_request_utils
import image_processing_utils
import its_session_utils
import target_exposure_utils

EXP_GAIN_FACTOR = 2
NAME = os.path.splitext(os.path.basename(__file__))[0]
PATCH_H = 0.1  # center 10%
PATCH_W = 0.1
PATCH_X = 0.5 - PATCH_W/2
PATCH_Y = 0.5 - PATCH_H/2
REQ_PATTERN = ['base', 'base', 'iso', 'iso', 'base', 'base', 'exp',
               'base', 'iso', 'base', 'exp', 'base', 'exp', 'exp']
PATTERN_CHECK = [False if r == 'base' else True for r in REQ_PATTERN]


class LatchingTest(its_base_test.ItsBaseTest):
  """Test that settings latch on the right frame.

  Takes a sequence of 14 shots using back-to-back requests, varying the capture
  request gain and exp parameters between shots. Check images that come back
  have the properties.

  Pattern is described in EXP_GAIN_HIGH_PATTERN where False is NOM, True is High
  """

  def test_latching(self):
    logging.debug('Starting %s', NAME)
    with its_session_utils.ItsSession(
        device_id=self.dut.serial,
        camera_id=self.camera_id,
        hidden_physical_id=self.hidden_physical_id) as cam:
      props = cam.get_camera_properties()
      props = cam.override_with_hidden_physical_camera_props(props)
      log_path = self.log_path

      # check SKIP conditions
      camera_properties_utils.skip_unless(
          camera_properties_utils.full_or_better(props))

      # Load chart for scene
      its_session_utils.load_scene(
          cam, props, self.scene, self.tablet, self.chart_distance)

      # Create requests, do captures and extract means for each image
      _, fmt = capture_request_utils.get_fastest_manual_capture_settings(props)
      e, s = target_exposure_utils.get_target_exposure_combos(
          log_path, cam)['midExposureTime']

      e /= EXP_GAIN_FACTOR
      r_means = []
      g_means = []
      b_means = []
      reqs = []
      base_req = capture_request_utils.manual_capture_request(
          s, e, 0.0, True, props)
      iso_mult_req = capture_request_utils.manual_capture_request(
          s * EXP_GAIN_FACTOR, e, 0.0, True, props)
      exp_mult_req = capture_request_utils.manual_capture_request(
          s, e * EXP_GAIN_FACTOR, 0.0, True, props)
      for req_type in REQ_PATTERN:
        if req_type == 'base':
          reqs.append(base_req)
        elif req_type == 'exp':
          reqs.append(exp_mult_req)
        elif req_type == 'iso':
          reqs.append(iso_mult_req)
        else:
          raise AssertionError(f'Incorrect capture request! {req_type}')

      caps = cam.do_capture(reqs, fmt)
      for i, cap in enumerate(caps):
        img = image_processing_utils.convert_capture_to_rgb_image(cap)
        image_processing_utils.write_image(img, '%s_i=%02d.jpg' % (
            os.path.join(log_path, NAME), i))
        patch = image_processing_utils.get_image_patch(
            img, PATCH_X, PATCH_Y, PATCH_W, PATCH_H)
        rgb_means = image_processing_utils.compute_image_means(patch)
        r_means.append(rgb_means[0])
        g_means.append(rgb_means[1])
        b_means.append(rgb_means[2])
      logging.debug('G means: %s', str(g_means))

      # Plot results
      idxs = range(len(r_means))
      pylab.figure(NAME)
      pylab.plot(idxs, r_means, '-ro')
      pylab.plot(idxs, g_means, '-go')
      pylab.plot(idxs, b_means, '-bo')
      pylab.ylim([0, 1])
      pylab.title(NAME)
      pylab.xlabel('capture')
      pylab.ylabel('RGB means')
      matplotlib.pyplot.savefig('%s_plot_means.png' % os.path.join(
          log_path, NAME))

      # check G mean pattern for correctness
      g_avg_for_caps = sum(g_means) / len(g_means)
      g_high = [g / g_avg_for_caps > 1 for g in g_means]
      if g_high != PATTERN_CHECK:
        raise AssertionError(f'G means: {g_means}, TEMPLATE: {REQ_PATTERN}')

if __name__ == '__main__':
  test_runner.main()

