// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome_frame/update_launcher.h"

#include <windows.h>
#include <Shellapi.h>

#include "base/win/scoped_com_initializer.h"
#include "base/win/scoped_comptr.h"
#include "base/win/scoped_handle.h"
#include "google_update/google_update_idl.h"

namespace {

const wchar_t kChromeFrameGuid[] = L"{8BA986DA-5100-405E-AA35-86F34A02ACBF}";

const DWORD kLaunchFailureExitCode = 0xFF;

const wchar_t kUpdateCommandFlag[] = L"--update-cmd";

// Waits indefinitely for the provided process to exit. Returns the process's
// exit code, or kLaunchFailureExitCode if an error occurs in the waiting.
DWORD WaitForProcessExitCode(HANDLE handle) {
  DWORD exit_code = 0;
  return ((::WaitForSingleObject(handle, INFINITE) == WAIT_OBJECT_0) &&
          ::GetExitCodeProcess(handle, &exit_code)) ?
      exit_code : kLaunchFailureExitCode;
}

}  // namespace

namespace update_launcher {

std::wstring GetUpdateCommandFromArguments(const wchar_t* command_line) {
  std::wstring command;

  if (command_line != NULL) {
    int num_args = 0;
    wchar_t** args = NULL;
    args = ::CommandLineToArgvW(command_line, &num_args);

    if (args) {
      if (num_args == 3 && _wcsicmp(args[1], kUpdateCommandFlag) == 0)
        command = args[2];
      ::LocalFree(args);
    }
  }

  return command;
}

DWORD LaunchUpdateCommand(const std::wstring& command) {
  base::win::ScopedCOMInitializer com_initializer;
  if (!com_initializer.succeeded())
    return kLaunchFailureExitCode;

  base::win::ScopedComPtr<IProcessLauncher> ipl;
  if (FAILED(ipl.CreateInstance(__uuidof(ProcessLauncherClass))))
    return kLaunchFailureExitCode;

  ULONG_PTR phandle = NULL;
  if (FAILED(ipl->LaunchCmdElevated(kChromeFrameGuid, command.c_str(),
                                    ::GetCurrentProcessId(), &phandle)))
    return kLaunchFailureExitCode;

  base::win::ScopedHandle process(reinterpret_cast<HANDLE>(phandle));
  return WaitForProcessExitCode(process);
}

}  // namespace process_launcher