// Initially we hardcoded the default strings here.
// Next, we used html.css to store the default label for various types
// of buttons. (nsGfxButtonControlFrame::DoNavQuirksReflow rev 1.20)
// However, since html.css is not internationalized, we now grab the default
// label from a string bundle as is done for all other UI strings.
// See bug 16999 for further details.
nsresult
nsGfxButtonControlFrame::GetDefaultLabel(nsXPIDLString& aString) const
{
  nsCOMPtr<nsIFormControl> form = do_QueryInterface(mContent);
  NS_ENSURE_TRUE(form, NS_ERROR_UNEXPECTED);

  int32_t type = form->GetType();
  const char *prop;
  if (type == NS_FORM_INPUT_RESET) {
    prop = "Reset";
  }
  else if (type == NS_FORM_INPUT_SUBMIT) {
    prop = "Submit";
  }
  else if (IsFileBrowseButton(type)) {
    prop = "Browse";
  }
  else {
    aString.Truncate();
    return NS_OK;
  }

  return nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
                                            prop, aString);
}
nsresult
nsGfxButtonControlFrame::GetLabel(nsXPIDLString& aLabel)
{
  // Get the text from the "value" property on our content if there is
  // one; otherwise set it to a default value (localized).
  nsresult rv;
  nsCOMPtr<nsIDOMHTMLInputElement> elt = do_QueryInterface(mContent);
  if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::value) && elt) {
    rv = elt->GetValue(aLabel);
  } else {
    // Generate localized label.
    // We can't make any assumption as to what the default would be
    // because the value is localized for non-english platforms, thus
    // it might not be the string "Reset", "Submit Query", or "Browse..."
    rv = GetDefaultLabel(aLabel);
  }

  NS_ENSURE_SUCCESS(rv, rv);

  // Compress whitespace out of label if needed.
  if (!GetStyleText()->WhiteSpaceIsSignificant()) {
    aLabel.CompressWhitespace();
  } else if (aLabel.Length() > 2 && aLabel.First() == ' ' &&
             aLabel.CharAt(aLabel.Length() - 1) == ' ') {
    // This is a bit of a hack.  The reason this is here is as follows: we now
    // have default padding on our buttons to make them non-ugly.
    // Unfortunately, IE-windows does not have such padding, so people will
    // stick values like " ok " (with the spaces) in the buttons in an attempt
    // to make them look decent.  Unfortunately, if they do this the button
    // looks way too big in Mozilla.  Worse yet, if they do this _and_ set a
    // fixed width for the button we run into trouble because our focus-rect
    // border/padding and outer border take up 10px of the horizontal button
    // space or so; the result is that the text is misaligned, even with the
    // recentering we do in nsHTMLButtonFrame::Reflow.  So to solve this, even
    // if the whitespace is significant, single leading and trailing _spaces_
    // (and not other whitespace) are removed.  The proper solution, of
    // course, is to not have the focus rect painting taking up 6px of
    // horizontal space. We should do that instead (via XBL form controls or
    // changing the renderer) and remove this.
    aLabel.Cut(0, 1);
    aLabel.Truncate(aLabel.Length() - 1);
  }

  return NS_OK;
}
//----------------------------------------------------------------------------------
// Returns a Global Moveable Memory Handle to a DevMode
// from the Printer by the name of aPrintName
//
// NOTE:
//   This function assumes that aPrintName has already been converted from 
//   unicode
//
HGLOBAL CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName, nsIPrintSettings* aPS)
{
  HGLOBAL hGlobalDevMode = nullptr;

  HANDLE hPrinter = nullptr;
  // const cast kludge for silly Win32 api's
  LPWSTR printName = const_cast<wchar_t*>(static_cast<const wchar_t*>(aPrintName.get()));
  BOOL status = ::OpenPrinterW(printName, &hPrinter, nullptr);
  if (status) {

    LPDEVMODEW  pNewDevMode;
    DWORD       dwNeeded, dwRet;

    // Get the buffer size
    dwNeeded = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, nullptr, nullptr, 0);
    if (dwNeeded == 0) {
      return nullptr;
    }

    // Allocate a buffer of the correct size.
    pNewDevMode = (LPDEVMODEW)::HeapAlloc (::GetProcessHeap(), HEAP_ZERO_MEMORY, dwNeeded);
    if (!pNewDevMode) return nullptr;

    hGlobalDevMode = (HGLOBAL)::GlobalAlloc(GHND, dwNeeded);
    if (!hGlobalDevMode) {
      ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
      return nullptr;
    }

    dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, pNewDevMode, nullptr, DM_OUT_BUFFER);

    if (dwRet != IDOK) {
      ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
      ::GlobalFree(hGlobalDevMode);
      ::ClosePrinter(hPrinter);
      return nullptr;
    }

    // Lock memory and copy contents from DEVMODE (current printer)
    // to Global Memory DEVMODE
    LPDEVMODEW devMode = (DEVMODEW *)::GlobalLock(hGlobalDevMode);
    if (devMode) {
      memcpy(devMode, pNewDevMode, dwNeeded);
      // Initialize values from the PrintSettings
      nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(aPS);
      MOZ_ASSERT(psWin);
      psWin->CopyToNative(devMode);

      // Sets back the changes we made to the DevMode into the Printer Driver
      dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, devMode, devMode, DM_IN_BUFFER | DM_OUT_BUFFER);
      if (dwRet != IDOK) {
        ::GlobalUnlock(hGlobalDevMode);
        ::GlobalFree(hGlobalDevMode);
        ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
        ::ClosePrinter(hPrinter);
        return nullptr;
      }

      ::GlobalUnlock(hGlobalDevMode);
    } else {
      ::GlobalFree(hGlobalDevMode);
      hGlobalDevMode = nullptr;
    }

    ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);

    ::ClosePrinter(hPrinter);

  } else {
    return nullptr;
  }

  return hGlobalDevMode;
}
//----------------------------------------------------------------------------------
// Returns a Global Moveable Memory Handle to a DevMode
// from the Printer by the name of aPrintName
//
// NOTE:
//   This function assumes that aPrintName has already been converted from 
//   unicode
//
static nsReturnRef<nsHGLOBAL>
CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName,
                           nsIPrintSettings* aPS)
{
  nsHPRINTER hPrinter = nullptr;
  // const cast kludge for silly Win32 api's
  LPWSTR printName = const_cast<wchar_t*>(static_cast<const wchar_t*>(aPrintName.get()));
  BOOL status = ::OpenPrinterW(printName, &hPrinter, nullptr);
  if (!status) {
    return nsReturnRef<nsHGLOBAL>();
  }

  // Make sure hPrinter is closed on all paths
  nsAutoPrinter autoPrinter(hPrinter);

  // Get the buffer size
  DWORD dwNeeded = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, nullptr,
                                         nullptr, 0);
  if (dwNeeded == 0) {
    return nsReturnRef<nsHGLOBAL>();
  }

  // Allocate a buffer of the correct size.
  nsAutoDevMode newDevMode((LPDEVMODEW)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY,
                                                   dwNeeded));
  if (!newDevMode) {
    return nsReturnRef<nsHGLOBAL>();
  }

  nsHGLOBAL hDevMode = ::GlobalAlloc(GHND, dwNeeded);
  nsAutoGlobalMem globalDevMode(hDevMode);
  if (!hDevMode) {
    return nsReturnRef<nsHGLOBAL>();
  }

  DWORD dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, newDevMode,
                                      nullptr, DM_OUT_BUFFER);
  if (dwRet != IDOK) {
    return nsReturnRef<nsHGLOBAL>();
  }

  // Lock memory and copy contents from DEVMODE (current printer)
  // to Global Memory DEVMODE
  LPDEVMODEW devMode = (DEVMODEW *)::GlobalLock(hDevMode);
  if (!devMode) {
    return nsReturnRef<nsHGLOBAL>();
  }

  memcpy(devMode, newDevMode.get(), dwNeeded);
  // Initialize values from the PrintSettings
  nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(aPS);
  MOZ_ASSERT(psWin);
  psWin->CopyToNative(devMode);

  // Sets back the changes we made to the DevMode into the Printer Driver
  dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, devMode, devMode,
                                DM_IN_BUFFER | DM_OUT_BUFFER);
  if (dwRet != IDOK) {
    ::GlobalUnlock(hDevMode);
    return nsReturnRef<nsHGLOBAL>();
  }

  ::GlobalUnlock(hDevMode);

  return globalDevMode.out();
}