// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/browser/infobars/model/overlays/infobar_banner_overlay_request_cancel_handler.h"

#import "ios/chrome/browser/infobars/model/infobar_ios.h"
#import "ios/chrome/browser/infobars/model/overlays/infobar_overlay_type.h"
#import "ios/chrome/browser/infobars/model/overlays/infobar_overlay_util.h"
#import "ios/chrome/browser/overlays/model/public/overlay_request_queue.h"

#pragma mark - InfobarBannerOverlayRequestCancelHandler

InfobarBannerOverlayRequestCancelHandler::
    InfobarBannerOverlayRequestCancelHandler(
        OverlayRequest* request,
        OverlayRequestQueue* queue,
        InfoBarIOS* infobar,
        InfobarOverlayRequestInserter* inserter,
        InfobarModalCompletionNotifier* modal_completion_notifier)
    : InfobarOverlayRequestCancelHandler(request, queue, infobar),
      inserter_(inserter),
      modal_completion_observer_(this, modal_completion_notifier, infobar),
      modal_insertion_observer_(inserter, infobar, this) {
  DCHECK(inserter_);
}

InfobarBannerOverlayRequestCancelHandler::
    ~InfobarBannerOverlayRequestCancelHandler() = default;

#pragma mark Private

void InfobarBannerOverlayRequestCancelHandler::ModalCompleted() {
  // Only cancel the banner if the modal being completed was presented from this
  // banner.
  if (presenting_modal_) {
    CancelRequest();
  }
}

#pragma mark InfobarOverlayRequestCancelHandler

void InfobarBannerOverlayRequestCancelHandler::HandleReplacement(
    InfoBarIOS* replacement) {
  // If an infobar is replaced while a request for its banner is in the queue,
  // a request for the replacement's banner should be inserted in back of the
  // handler's request.
  size_t index = 0;
  bool request_found =
      GetInfobarOverlayRequestIndex(queue(), infobar(), &index);
  DCHECK(request_found);

  InsertParams params(replacement);
  params.overlay_type = InfobarOverlayType::kBanner;
  params.insertion_index = index + 1;
  params.source = InfobarOverlayInsertionSource::kInfoBarManager;
  inserter_->InsertOverlayRequest(params);
}

#pragma mark - InsertionObserver

InfobarBannerOverlayRequestCancelHandler::InsertionObserver::InsertionObserver(
    InfobarOverlayRequestInserter* inserter,
    InfoBarIOS* infobar,
    InfobarBannerOverlayRequestCancelHandler* cancel_handler)
    : cancel_handler_(cancel_handler), infobar_(infobar) {
  DCHECK(inserter);
  DCHECK(infobar);
  DCHECK(cancel_handler);
  scoped_observation_.Observe(inserter);
}

InfobarBannerOverlayRequestCancelHandler::InsertionObserver::
    ~InsertionObserver() = default;

void InfobarBannerOverlayRequestCancelHandler::InsertionObserver::
    InfobarRequestInserted(InfobarOverlayRequestInserter* inserter,
                           const InsertParams& params) {
  if (infobar_ == params.infobar &&
      params.source == InfobarOverlayInsertionSource::kBanner) {
    cancel_handler_->ModalPresentedFromBanner();
  }
}

void InfobarBannerOverlayRequestCancelHandler::InsertionObserver::
    InserterDestroyed(InfobarOverlayRequestInserter* inserter) {
  DCHECK(scoped_observation_.IsObservingSource(inserter));
  scoped_observation_.Reset();
}

#pragma mark - InfobarBannerOverlayRequestCancelHandler::ModalCompletionObserver

InfobarBannerOverlayRequestCancelHandler::ModalCompletionObserver::
    ModalCompletionObserver(
        InfobarBannerOverlayRequestCancelHandler* cancel_handler,
        InfobarModalCompletionNotifier* completion_notifier,
        InfoBarIOS* infobar)
    : cancel_handler_(cancel_handler), infobar_(infobar) {
  DCHECK(cancel_handler_);
  DCHECK(infobar_);
  DCHECK(completion_notifier);
  scoped_observation_.Observe(completion_notifier);
}

InfobarBannerOverlayRequestCancelHandler::ModalCompletionObserver::
    ~ModalCompletionObserver() = default;

void InfobarBannerOverlayRequestCancelHandler::ModalCompletionObserver::
    InfobarModalsCompleted(InfobarModalCompletionNotifier* notifier,
                           InfoBarIOS* infobar) {
  if (infobar_ == infobar) {
    cancel_handler_->ModalCompleted();
    // The cancel handler is destroyed after CancelForModalCompletion(), so no
    // code can be added after this call.
  }
}

void InfobarBannerOverlayRequestCancelHandler::ModalCompletionObserver::
    InfobarModalCompletionNotifierDestroyed(
        InfobarModalCompletionNotifier* notifier) {
  DCHECK(scoped_observation_.IsObservingSource(notifier));
  scoped_observation_.Reset();
  cancel_handler_->ModalCompleted();
  // The cancel handler is destroyed after CancelForModalCompletion(), so no
  // code can be added after this call.
}
