// Copyright 2021 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/download/model/vcard_tab_helper.h"

#import "base/files/file_path.h"
#import "base/strings/sys_string_conversions.h"
#import "ios/chrome/browser/download/model/vcard_tab_helper_delegate.h"
#import "ios/chrome/browser/shared/model/utils/mime_type_util.h"
#import "ios/web/public/download/download_task.h"
#import "ios/web/public/navigation/navigation_context.h"
#import "net/base/apple/url_conversions.h"

#pragma mark - Initialization

VcardTabHelper::VcardTabHelper(web::WebState* web_state)
    : web_state_(web_state) {
  CHECK(web_state_);
  web_state_observation_.Observe(web_state);
}

VcardTabHelper::~VcardTabHelper() {
  for (auto& task : tasks_) {
    task->RemoveObserver(this);
  }
}

#pragma mark - Public

void VcardTabHelper::Download(std::unique_ptr<web::DownloadTask> task) {
  DCHECK(task->GetMimeType() == kVcardMimeType ||
         task->GetMimeType() == kXVcardMimeType);
  web::DownloadTask* task_ptr = task.get();

  // Add the task to the set of unfinished tasks before calling
  // Start() because the download may make progress synchronously
  // and OnDownloadUpdated called immediately.
  tasks_.insert(std::move(task));
  task_ptr->AddObserver(this);
  task_ptr->Start(base::FilePath());
}

#pragma mark - WebStateObserver

void VcardTabHelper::WasShown(web::WebState* web_state) {
  CHECK_EQ(web_state_, web_state);
  if (delegate_ && pending_vcard_) {
    [delegate_ openVcardFromData:pending_vcard_];
    pending_vcard_ = nil;
  }
}

void VcardTabHelper::DidStartNavigation(
    web::WebState* web_state,
    web::NavigationContext* navigation_context) {
  CHECK_EQ(web_state_, web_state);
  if (!navigation_context->IsSameDocument()) {
    pending_vcard_ = nil;
  }
}

#pragma mark - DownloadTaskObserver

void VcardTabHelper::OnDownloadUpdated(web::DownloadTask* updated_task) {
  auto iterator = tasks_.find(updated_task);
  DCHECK(iterator != tasks_.end());
  if (!updated_task->IsDone()) {
    return;
  }

  // Extract the std::unique_ptr<> from the std::set<>.
  auto node = tasks_.extract(iterator);
  auto task = std::move(node.value());
  DCHECK_EQ(task.get(), updated_task);

  // Stop observing the task as its ownership is transfered to the callback
  // that will destroy when it is invoked or cancelled.
  updated_task->RemoveObserver(this);
  updated_task->GetResponseData(
      base::BindOnce(&VcardTabHelper::OnDownloadDataRead,
                     weak_factory_.GetWeakPtr(), std::move(task)));
}

#pragma mark - Private

void VcardTabHelper::OnDownloadDataRead(std::unique_ptr<web::DownloadTask> task,
                                        NSData* data) {
  DCHECK(task);
  if (web_state_->IsVisible()) {
    [delegate_ openVcardFromData:data];
  } else {
    pending_vcard_ = data;
  }
}
