// Copyright (c) 1997-1999 Microsoft Corporation
//
// demote page
//
// 1-20-98 sburns



#include "headers.hxx"
#include "page.hpp"
#include "DemotePage.hpp"
#include "resource.h"
#include "state.hpp"
#include "ds.hpp"
#include "common.hpp"



DemotePage::DemotePage()
   :
   DCPromoWizardPage(
      IDD_DEMOTE,
      IDS_DEMOTE_PAGE_TITLE,
      IDS_DEMOTE_PAGE_SUBTITLE),
   bulletFont(0),
   warnIcon(0)
{
   LOG_CTOR(DemotePage);
}



DemotePage::~DemotePage()
{
   LOG_DTOR(DemotePage);

   HRESULT hr = S_OK;

   if (warnIcon)
   {
      hr = Win::DestroyIcon(warnIcon);

      ASSERT(SUCCEEDED(hr));
   }

   if (bulletFont)
   {
      hr = Win::DeleteObject(bulletFont);

      ASSERT(SUCCEEDED(hr));
   }
}



void
DemotePage::SetBulletFont()
{
   LOG_FUNCTION(DemotePage::SetBulletFont);

   HRESULT hr = S_OK;
   do
   {
      NONCLIENTMETRICS ncm;
      memset(&ncm, 0, sizeof(ncm));
      ncm.cbSize = sizeof(ncm);
      hr = Win::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
      BREAK_ON_FAILED_HRESULT(hr);

      LOGFONT logFont = ncm.lfMessageFont;

      logFont.lfWeight = FW_BOLD;

      String fontName = String::load(IDS_BULLET_FONT_NAME);

      // ensure null termination

      memset(logFont.lfFaceName, 0, LF_FACESIZE * sizeof(TCHAR));
      size_t fnLen = fontName.length();
      fontName.copy(
         logFont.lfFaceName,

         // don't copy over the last null

         min(LF_FACESIZE - 1, fnLen));
    
      hr = Win::CreateFontIndirect(logFont, bulletFont);
      BREAK_ON_FAILED_HRESULT(hr);

      SetControlFont(hwnd, IDC_BULLET1, bulletFont);
      SetControlFont(hwnd, IDC_BULLET2, bulletFont);
   }
   while (0);
}



void
DemotePage::OnInit()
{
   LOG_FUNCTION(DemotePage::OnInit);

   // 361172
   //
   // CODEWORK: the bullets aren't very impressive.  I'm told an icon is
   // a better way to do this

   SetBulletFont();

   HRESULT hr = Win::LoadImage(IDI_WARN, warnIcon);

   ASSERT(SUCCEEDED(hr));

   if (SUCCEEDED(hr))
   {
      Win::SendMessage(
         Win::GetDlgItem(hwnd, IDC_WARNING_ICON),
         STM_SETICON,
         reinterpret_cast<WPARAM>(warnIcon),
         0);
   }

   State& state = State::GetInstance();
   if (state.UsingAnswerFile())
   {
      String option =
         state.GetAnswerFileOption(State::OPTION_IS_LAST_DC);
      if (option.icompare(State::VALUE_YES) == 0)
      {
         Win::CheckDlgButton(hwnd, IDC_LAST, BST_CHECKED);
         return;
      }
   }
   else
   {
      // determine if this machine is a GC, if so pop up a warning message

      if (state.IsGlobalCatalog())
      {
         popup.Info(GetHWND(), IDS_DEMOTE_GC_WARNING);
      }
   }

   // you may ask yourself: "Why not set the state of the checkbox based
   // on the result of IsReallyLastDcInDomain?"  Because demoting the
   // last DC deletes the domain, too.  We want the user to be very
   // deliberate when checking that checkbox.
}



bool
DemotePage::OnSetActive()
{
   LOG_FUNCTION(DemotePage::OnSetActive);

   State& state = State::GetInstance();
   
   if (state.RunHiddenUnattended())
   {
      int nextPage = DemotePage::Validate();
      if (nextPage != -1)
      {
         GetWizard().SetNextPageID(hwnd, nextPage);
      }
      else
      {
         state.ClearHiddenWhileUnattended();
      }

   }

   Win::PropSheet_SetWizButtons(
      Win::GetParent(hwnd),
      PSWIZB_BACK | PSWIZB_NEXT);

   return true;
}



bool
OtherDcFound(const String& domainName)
{
   LOG_FUNCTION2(OtherDcFound, domainName);
   ASSERT(!domainName.empty());

   bool result = false;
   HRESULT hr = S_OK;

   do
   {
      DOMAIN_CONTROLLER_INFO* info = 0;
      hr =
         MyDsGetDcName(
            0,
            domainName,  
               DS_FORCE_REDISCOVERY
            |  DS_AVOID_SELF
            |  DS_DIRECTORY_SERVICE_REQUIRED,
            info);
      BREAK_ON_FAILED_HRESULT(hr);

      ASSERT(info->DomainControllerName);

      ::NetApiBufferFree(info);

      result = true;
   }
   while (0);

   LOG_HRESULT(hr);
   LOG(result ? L"true" : L"false");

   return result;
}



int
DemotePage::Validate()
{
   LOG_FUNCTION(DemotePage::Validate);

   State& state = State::GetInstance();
   ASSERT(state.GetOperation() == State::DEMOTE);

   bool isLast = Win::IsDlgButtonChecked(hwnd, IDC_LAST);

   if (isLast)
   {
      if (!state.IsReallyLastDcInDomain())
      {
         // user checked the box, but we found other dc objects in the DS.
         // verify that the user really meant to check the checkbox.

         if (
            popup.MessageBox(
               hwnd,
               String::format(
                  IDS_VERIFY_LAST_DC,
                  state.GetComputer().GetDomainDnsName().c_str()),
               MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2) != IDYES)
         {
            state.SetIsLastDCInDomain(false);
            return -1;
         }
      }
   }
   else
   {
      // the user unchecked the box, check for other DCs for that domain

      Win::WaitCursor cursor;

      if (!OtherDcFound(state.GetComputer().GetDomainDnsName()))
      {
         if (
            popup.MessageBox(
               hwnd,
               String::format(
                  IDS_VERIFY_NOT_LAST_DC,
                  state.GetComputer().GetDomainDnsName().c_str()),
               MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2) != IDYES)
         {
            // user clicked no or cancel

            state.SetIsLastDCInDomain(false);
            return -1;
         }

         // The user clicked "yes, proceed even if I lose changes"

         // CODEWORK: set flag to allow demote and abandon local changes
         // here...

      }
   }

   state.SetIsLastDCInDomain(isLast);

   // jump to credentials page if the user checked the "last dc in domain"
   // checkbox, unless this is last dc in forest root domain. 318736, 391440

   const Computer& computer = state.GetComputer();
   bool isForestRootDomain =
      (computer.GetDomainDnsName().icompare(computer.GetForestDnsName()) == 0);

   return
         isLast and !isForestRootDomain
      ?  IDD_GET_CREDENTIALS
      :  IDD_ADMIN_PASSWORD;
}