bool CXFA_FFDateTimeEdit::LoadWidget() {
  CFWL_DateTimePicker* pWidget = new CFWL_DateTimePicker(GetFWLApp());
  pWidget->Initialize();
  m_pNormalWidget = pWidget;
  m_pNormalWidget->SetLayoutItem(this);
  IFWL_Widget* pIWidget = m_pNormalWidget->GetWidget();
  CFWL_NoteDriver* pNoteDriver = pIWidget->GetOwnerApp()->GetNoteDriver();
  pNoteDriver->RegisterEventTarget(pIWidget, pIWidget);

  m_pOldDelegate = m_pNormalWidget->GetDelegate();
  m_pNormalWidget->SetDelegate(this);
  m_pNormalWidget->LockUpdate();

  CFX_WideString wsText;
  m_pDataAcc->GetValue(wsText, XFA_VALUEPICTURE_Display);
  pWidget->SetEditText(wsText);
  if (CXFA_Value value = m_pDataAcc->GetFormValue()) {
    switch (value.GetChildValueClassID()) {
      case XFA_Element::Date: {
        if (!wsText.IsEmpty()) {
          CXFA_LocaleValue lcValue = XFA_GetLocaleValue(m_pDataAcc);
          CFX_Unitime date = lcValue.GetDate();
          if ((FX_UNITIME)date != 0) {
            pWidget->SetCurSel(date.GetYear(), date.GetMonth(), date.GetDay());
          }
        }
      } break;
      default:
        break;
    }
  }
  UpdateWidgetProperty();
  m_pNormalWidget->UnlockUpdate();
  return CXFA_FFField::LoadWidget();
}
FX_BOOL CXFA_LocaleValue::SetTime(const CFX_Unitime& t) {
  m_dwType = XFA_VT_TIME;
  m_wsValue.Format(L"%02d:%02d:%02d", t.GetHour(), t.GetMinute(),
                   t.GetSecond());
  if (t.GetMillisecond() > 0) {
    CFX_WideString wsTemp;
    wsTemp.Format(L"%:03d", t.GetMillisecond());
    m_wsValue += wsTemp;
  }
  return TRUE;
}
CFX_WideString CXFA_FFNotify::GetCurrentDateTime() {
  CFX_Unitime dataTime;
  dataTime.Now();
  CFX_WideString wsDateTime;
  wsDateTime.Format(L"%d%02d%02dT%02d%02d%02d", dataTime.GetYear(),
                    dataTime.GetMonth(), dataTime.GetDay(), dataTime.GetHour(),
                    dataTime.GetMinute(), dataTime.GetSecond());
  return wsDateTime;
}
FX_BOOL CXFA_LocaleValue::SetDateTime(const CFX_Unitime& dt) {
  m_dwType = XFA_VT_DATETIME;
  m_wsValue.Format(L"%04d-%02d-%02dT%02d:%02d:%02d", dt.GetYear(),
                   dt.GetMonth(), dt.GetDay(), dt.GetHour(), dt.GetMinute(),
                   dt.GetSecond());
  if (dt.GetMillisecond() > 0) {
    CFX_WideString wsTemp;
    wsTemp.Format(L"%:03d", dt.GetMillisecond());
    m_wsValue += wsTemp;
  }
  return TRUE;
}
FX_BOOL CXFA_FFDateTimeEdit::LoadWidget() {
  CFWL_DateTimePicker* pWidget = CFWL_DateTimePicker::Create();
  pWidget->Initialize();
  m_pNormalWidget = (CFWL_Widget*)pWidget;
  IFWL_Widget* pIWidget = m_pNormalWidget->GetWidget();
  m_pNormalWidget->SetPrivateData(pIWidget, this, NULL);
  IFWL_NoteDriver* pNoteDriver = FWL_GetApp()->GetNoteDriver();
  pNoteDriver->RegisterEventTarget(pIWidget, pIWidget);
  m_pOldDelegate = m_pNormalWidget->SetDelegate(this);
  m_pNormalWidget->LockUpdate();
  CFX_WideString wsText;
  m_pDataAcc->GetValue(wsText, XFA_VALUEPICTURE_Display);
  pWidget->SetEditText(wsText);
  XFA_DATETIMETYPE eType = XFA_DATETIMETYPE_DateAndTime;
  if (CXFA_Value value = m_pDataAcc->GetFormValue()) {
    switch (value.GetChildValueClassID()) {
      case XFA_ELEMENT_Date: {
        eType = XFA_DATETIMETYPE_Date;
        if (!wsText.IsEmpty()) {
          CXFA_LocaleValue lcValue = XFA_GetLocaleValue(m_pDataAcc);
          CFX_Unitime date = lcValue.GetDate();
          if ((FX_UNITIME)date != 0) {
            pWidget->SetCurSel(date.GetYear(), date.GetMonth(), date.GetDay());
          }
        }
      } break;
      case XFA_ELEMENT_Time:
        eType = XFA_DATETIMETYPE_Time;
        break;
      default:
        eType = XFA_DATETIMETYPE_DateAndTime;
        break;
    }
  }
  UpdateWidgetProperty();
  m_pNormalWidget->UnlockUpdate();
  return CXFA_FFField::LoadWidget();
}
void CXFA_FFDateTimeEdit::OnSelectChanged(IFWL_Widget* pWidget,
                                          int32_t iYear,
                                          int32_t iMonth,
                                          int32_t iDay) {
  CFX_WideString wsPicture;
  m_pDataAcc->GetPictureContent(wsPicture, XFA_VALUEPICTURE_Edit);
  CXFA_LocaleValue date(XFA_VT_DATE, GetDoc()->GetXFADoc()->GetLocalMgr());
  CFX_Unitime dt;
  dt.Set(iYear, iMonth, iDay);
  date.SetDate(dt);
  CFX_WideString wsDate;
  date.FormatPatterns(wsDate, wsPicture, m_pDataAcc->GetLocal(),
                      XFA_VALUEPICTURE_Edit);
  CFWL_DateTimePicker* pDateTime = (CFWL_DateTimePicker*)m_pNormalWidget;
  pDateTime->SetEditText(wsDate);
  pDateTime->Update();
  GetDoc()->GetDocEnvironment()->SetFocusWidget(GetDoc(), nullptr);
  CXFA_EventParam eParam;
  eParam.m_eType = XFA_EVENT_Change;
  eParam.m_pTarget = m_pDataAcc;
  m_pDataAcc->GetValue(eParam.m_wsNewText, XFA_VALUEPICTURE_Raw);
  m_pDataAcc->ProcessEvent(XFA_ATTRIBUTEENUM_Change, &eParam);
}
bool CXFA_FFDateTimeEdit::UpdateFWLData() {
  if (!m_pNormalWidget) {
    return false;
  }
  XFA_VALUEPICTURE eType = XFA_VALUEPICTURE_Display;
  if (IsFocused()) {
    eType = XFA_VALUEPICTURE_Edit;
  }
  CFX_WideString wsText;
  m_pDataAcc->GetValue(wsText, eType);
  ((CFWL_DateTimePicker*)m_pNormalWidget)->SetEditText(wsText);
  if (IsFocused() && !wsText.IsEmpty()) {
    CXFA_LocaleValue lcValue = XFA_GetLocaleValue(m_pDataAcc);
    CFX_Unitime date = lcValue.GetDate();
    if (lcValue.IsValid()) {
      if ((FX_UNITIME)date != 0) {
        ((CFWL_DateTimePicker*)m_pNormalWidget)
            ->SetCurSel(date.GetYear(), date.GetMonth(), date.GetDay());
      }
    }
  }
  m_pNormalWidget->Update();
  return true;
}
FX_BOOL CXFA_LocaleValue::ValidateCanonicalDate(const CFX_WideString& wsDate,
                                                CFX_Unitime& unDate) {
  const uint16_t LastDay[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  const uint16_t wCountY = 4, wCountM = 2, wCountD = 2;
  int nLen = wsDate.GetLength();
  if (nLen < wCountY || nLen > wCountY + wCountM + wCountD + 2) {
    return FALSE;
  }
  const bool bSymbol = wsDate.Find(0x2D) != -1;
  uint16_t wYear = 0;
  uint16_t wMonth = 0;
  uint16_t wDay = 0;
  const FX_WCHAR* pDate = wsDate.c_str();
  int nIndex = 0, nStart = 0;
  while (pDate[nIndex] != '\0' && nIndex < wCountY) {
    if (!FXSYS_isDecimalDigit(pDate[nIndex])) {
      return FALSE;
    }
    wYear = (pDate[nIndex] - '0') + wYear * 10;
    nIndex++;
  }
  if (bSymbol) {
    if (pDate[nIndex] != 0x2D) {
      return FALSE;
    }
    nIndex++;
  }
  nStart = nIndex;
  while (pDate[nIndex] != '\0' && nIndex - nStart < wCountM && nIndex < nLen) {
    if (!FXSYS_isDecimalDigit(pDate[nIndex])) {
      return FALSE;
    }
    wMonth = (pDate[nIndex] - '0') + wMonth * 10;
    nIndex++;
  }
  if (bSymbol) {
    if (pDate[nIndex] != 0x2D) {
      return FALSE;
    }
    nIndex++;
  }
  nStart = nIndex;
  while (pDate[nIndex] != '\0' && nIndex - nStart < wCountD && nIndex < nLen) {
    if (!FXSYS_isDecimalDigit(pDate[nIndex])) {
      return FALSE;
    }
    wDay = (pDate[nIndex] - '0') + wDay * 10;
    nIndex++;
  }
  if (nIndex != nLen) {
    return FALSE;
  }
  if (wYear < 1900 || wYear > 2029) {
    return FALSE;
  }
  if (wMonth < 1 || wMonth > 12) {
    if (wMonth == 0 && nLen == wCountY) {
      return TRUE;
    }
    return FALSE;
  }
  if (wDay < 1) {
    if (wDay == 0 && (nLen == wCountY + wCountM)) {
      return TRUE;
    }
    return FALSE;
  }
  if (wMonth == 2) {
    if (wYear % 400 == 0 || (wYear % 100 != 0 && wYear % 4 == 0)) {
      if (wDay > 29) {
        return FALSE;
      }
    } else {
      if (wDay > 28) {
        return FALSE;
      }
    }
  } else if (wDay > LastDay[wMonth - 1]) {
    return FALSE;
  }
  CFX_Unitime ut;
  ut.Set(wYear, static_cast<uint8_t>(wMonth), static_cast<uint8_t>(wDay));
  unDate = unDate + ut;
  return TRUE;
}
FX_BOOL CXFA_LocaleValue::SetDate(const CFX_Unitime& d) {
  m_dwType = XFA_VT_DATE;
  m_wsValue.Format(L"%04d-%02d-%02d", d.GetYear(), d.GetMonth(), d.GetDay());
  return TRUE;
}