@Test(
      description =
          "Close modifying appt and take action from warning dialog : Save Changes and send updates",
      groups = {"functional"})
  public void ModifyAppointment_01() throws HarnessException {

    // Create appointment data
    String tz, apptSubject, apptAttendee1, apptAttendee2;
    apptSubject = ZimbraSeleniumProperties.getUniqueString();
    apptAttendee1 = ZimbraAccount.AccountA().EmailAddress;
    apptAttendee2 = ZimbraAccount.AccountB().EmailAddress;

    // Absolute dates in UTC zone
    tz = ZTimeZone.TimeZoneEST.getID();
    Calendar now = this.calendarWeekDayUTC;
    ZDate startUTC =
        new ZDate(
            now.get(Calendar.YEAR),
            now.get(Calendar.MONTH) + 1,
            now.get(Calendar.DAY_OF_MONTH),
            12,
            0,
            0);
    ZDate endUTC =
        new ZDate(
            now.get(Calendar.YEAR),
            now.get(Calendar.MONTH) + 1,
            now.get(Calendar.DAY_OF_MONTH),
            14,
            0,
            0);

    // Create appointment
    app.zGetActiveAccount()
        .soapSend(
            "<CreateAppointmentRequest xmlns='urn:zimbraMail'>"
                + "<m>"
                + "<inv method='REQUEST' type='event' status='CONF' draft='0' class='PUB' fb='B' transp='O' allDay='0' name='"
                + apptSubject
                + "'>"
                + "<s d='"
                + startUTC.toTimeZone(tz).toYYYYMMDDTHHMMSS()
                + "' tz='"
                + tz
                + "'/>"
                + "<e d='"
                + endUTC.toTimeZone(tz).toYYYYMMDDTHHMMSS()
                + "' tz='"
                + tz
                + "'/>"
                + "<or a='"
                + app.zGetActiveAccount().EmailAddress
                + "'/>"
                + "<at role='REQ' ptst='NE' rsvp='1' a='"
                + apptAttendee1
                + "' d='2'/>"
                + "<at role='REQ' ptst='NE' rsvp='1' a='"
                + apptAttendee2
                + "' d='2'/>"
                + "</inv>"
                + "<e a='"
                + ZimbraAccount.AccountA().EmailAddress
                + "' t='t'/>"
                + "<mp content-type='text/plain'>"
                + "<content>"
                + ZimbraSeleniumProperties.getUniqueString()
                + "</content>"
                + "</mp>"
                + "<su>"
                + apptSubject
                + "</su>"
                + "</m>"
                + "</CreateAppointmentRequest>");
    app.zPageCalendar.zToolbarPressButton(Button.B_REFRESH);

    // Remove attendee and close the appt
    app.zPageCalendar.zListItem(Action.A_DOUBLECLICK, apptSubject);
    FormApptNew apptForm = new FormApptNew(app);
    apptForm.zRemoveAttendee(apptAttendee2);
    apptForm.zToolbarPressButton(Button.B_CLOSE);

    DialogConfirmModification confirmClose =
        (DialogConfirmModification) new DialogConfirmModification(app, app.zPageCalendar);
    confirmClose.zClickButton(Button.B_SAVE_MODIFICATION);
    DialogSendUpdatetoAttendees sendUpdateDialog =
        (DialogSendUpdatetoAttendees) new DialogSendUpdatetoAttendees(app, app.zPageCalendar);
    sendUpdateDialog.zClickButton(Button.B_OK);

    // Verify if an attendee is removed from appt and attendee gets update
    AppointmentItem actual =
        AppointmentItem.importFromSOAP(app.zGetActiveAccount(), "subject:(" + apptSubject + ")");
    ZAssert.assertEquals(actual.getSubject(), apptSubject, "Subject: Verify the appointment data");
    ZAssert.assertStringDoesNotContain(
        actual.getAttendees(), apptAttendee2, "Attendees: Verify the attendee data");

    // Verify attendee2 receives cancellation message
    ZimbraAccount.AccountB()
        .soapSend(
            "<SearchRequest xmlns='urn:zimbraMail' types='message'>"
                + "<query>subject:"
                + (char) 34
                + "Cancelled: "
                + apptSubject
                + (char) 34
                + "</query>"
                + "</SearchRequest>");
    String id = ZimbraAccount.AccountB().soapSelectValue("//mail:m", "id");
    ZAssert.assertNotNull(id, "Verify attendee2 receives cancelled meeting message");

    // Verify appointment is deleted from attendee2's calendar
    AppointmentItem removedAttendee =
        AppointmentItem.importFromSOAP(ZimbraAccount.AccountB(), "subject:(" + apptSubject + ")");
    ZAssert.assertNull(removedAttendee, "Verify meeting is deleted from attendee2's calendar");
  }
  @Test(
      description =
          "Create weekly recurring invite with attendee and location with every Monday, end after 2 occurrences",
      groups = {"smoke"})
  public void WeeklyEveryXdayEndAfterYoccurrences_01() throws HarnessException {

    // Create appointment data
    AppointmentItem appt = new AppointmentItem();
    String apptSubject, apptAttendee, apptContent, apptLocation;
    ZimbraResource location = new ZimbraResource(ZimbraResource.Type.LOCATION);

    apptSubject = ZimbraSeleniumProperties.getUniqueString();
    apptAttendee = ZimbraAccount.AccountA().EmailAddress;
    apptContent = ZimbraSeleniumProperties.getUniqueString();
    apptLocation = location.EmailAddress;

    // Absolute dates in UTC zone
    Calendar now = this.calendarWeekDayUTC;
    ZDate startUTC =
        new ZDate(
            now.get(Calendar.YEAR),
            now.get(Calendar.MONTH) + 1,
            now.get(Calendar.DAY_OF_MONTH),
            20,
            0,
            0);
    ZDate endUTC =
        new ZDate(
            now.get(Calendar.YEAR),
            now.get(Calendar.MONTH) + 1,
            now.get(Calendar.DAY_OF_MONTH),
            22,
            0,
            0);

    appt.setSubject(apptSubject);
    appt.setAttendees(apptAttendee);
    appt.setStartTime(startUTC);
    appt.setEndTime(endUTC);
    appt.setLocation(apptLocation);
    appt.setContent(apptContent);

    // Compose appointment and send it to invitee
    FormApptNew apptForm = (FormApptNew) app.zPageCalendar.zToolbarPressButton(Button.B_NEW);
    apptForm.zFill(appt);
    apptForm.zRepeat(
        Button.O_EVERY_WEEK_MENU,
        Button.B_EVERY_X_RADIO_BUTTON,
        "Monday",
        Button.B_END_AFTER_X_OCCURRENCES_RADIO_BUTTON,
        "2");
    ZAssert.assertStringContains(
        app.zPageCalendar.zGetRecurringLink(),
        "Every Monday End after 2 occurrence(s) Effective ",
        "Recurring link: Verify the appointment data");

    apptForm.zSubmit();
    SleepUtil.sleepLong(); // SOAP gives wrong response

    app.zGetActiveAccount()
        .soapSend(
            "<SearchRequest xmlns='urn:zimbraMail' types='appointment' calExpandInstStart='"
                + startUTC.addDays(-10).toMillis()
                + "' calExpandInstEnd='"
                + endUTC.addDays(10).toMillis()
                + "'>"
                + "<query>"
                + apptSubject
                + "</query>"
                + "</SearchRequest>");

    String attendeeInvId = app.zGetActiveAccount().soapSelectValue("//mail:appt", "invId");
    app.zGetActiveAccount()
        .soapSend("<GetAppointmentRequest  xmlns='urn:zimbraMail' id='" + attendeeInvId + "'/>");

    String ruleFrequency =
        app.zGetActiveAccount().soapSelectValue("//mail:appt//mail:rule", "freq");
    String count = app.zGetActiveAccount().soapSelectValue("//mail:appt//mail:count", "num");
    String interval = app.zGetActiveAccount().soapSelectValue("//mail:appt//mail:interval", "ival");
    String weekday = app.zGetActiveAccount().soapSelectValue("//mail:appt//mail:wkday", "day");

    // Verify appointment exists on server meeting with correct recurring details
    AppointmentItem actual =
        AppointmentItem.importFromSOAP(
            app.zGetActiveAccount(),
            "subject:(" + appt.getSubject() + ")",
            appt.getStartTime().addDays(-7),
            appt.getEndTime().addDays(7));
    ZAssert.assertNotNull(actual, "Verify the new appointment is created");
    ZAssert.assertEquals(
        actual.getSubject(), appt.getSubject(), "Subject: Verify the appointment data");
    ZAssert.assertEquals(
        actual.getAttendees(), apptAttendee, "Attendees: Verify the appointment data");
    ZAssert.assertEquals(
        actual.getLocation(), apptLocation, "Location: Verify the appointment data");
    ZAssert.assertEquals(ruleFrequency, "WEE", "Repeat frequency: Verify the appointment data");
    ZAssert.assertEquals(count, "2", "No. of occurrences: Verify the appointment data");
    ZAssert.assertEquals(interval, "1", "Repeat interval: Verify the appointment data");
    ZAssert.assertEquals(weekday, "MO", "Weekday: Verify the appointment data");
    ZAssert.assertEquals(
        actual.getContent(), appt.getContent(), "Content: Verify the appointment data");

    // Verify location free/busy status shows as psts=AC
    String locationStatus =
        app.zGetActiveAccount().soapSelectValue("//mail:at[@a='" + apptLocation + "']", "ptst");
    ZAssert.assertEquals(
        locationStatus, "AC", "Verify that the location status shows as 'ACCEPTED'");

    ZimbraAccount.AccountA()
        .soapSend(
            "<SearchRequest xmlns='urn:zimbraMail' types='appointment' calExpandInstStart='"
                + startUTC.addDays(-10).toMillis()
                + "' calExpandInstEnd='"
                + endUTC.addDays(10).toMillis()
                + "'>"
                + "<query>"
                + apptSubject
                + "</query>"
                + "</SearchRequest>");

    attendeeInvId = ZimbraAccount.AccountA().soapSelectValue("//mail:appt", "invId");
    ZimbraAccount.AccountA()
        .soapSend("<GetAppointmentRequest  xmlns='urn:zimbraMail' id='" + attendeeInvId + "'/>");

    ruleFrequency = app.zGetActiveAccount().soapSelectValue("//mail:appt//mail:rule", "freq");
    count = app.zGetActiveAccount().soapSelectValue("//mail:appt//mail:count", "num");
    interval = app.zGetActiveAccount().soapSelectValue("//mail:appt//mail:interval", "ival");
    weekday = app.zGetActiveAccount().soapSelectValue("//mail:appt//mail:wkday", "day");

    // Verify the attendee receives the meeting with correct recurring details
    AppointmentItem received =
        AppointmentItem.importFromSOAP(
            ZimbraAccount.AccountA(),
            "subject:(" + appt.getSubject() + ")",
            appt.getStartTime().addDays(-7),
            appt.getEndTime().addDays(7));
    ZAssert.assertNotNull(received, "Verify the new appointment is created");
    ZAssert.assertEquals(
        received.getSubject(), appt.getSubject(), "Subject: Verify the appointment data");
    ZAssert.assertEquals(
        received.getAttendees(), apptAttendee, "Attendees: Verify the appointment data");
    ZAssert.assertEquals(
        received.getLocation(), apptLocation, "Location: Verify the appointment data");
    ZAssert.assertEquals(ruleFrequency, "WEE", "Repeat frequency: Verify the appointment data");
    ZAssert.assertEquals(count, "2", "No. of occurrences: Verify the appointment data");
    ZAssert.assertEquals(interval, "1", "Repeat interval: Verify the appointment data");
    ZAssert.assertEquals(weekday, "MO", "Weekday: Verify the appointment data");
    ZAssert.assertEquals(
        received.getContent(), appt.getContent(), "Content: Verify the appointment data");

    // Verify the attendee receives the invitation
    MailItem invite =
        MailItem.importFromSOAP(ZimbraAccount.AccountA(), "subject:(" + appt.getSubject() + ")");
    ZAssert.assertNotNull(invite, "Verify the invite is received");
    ZAssert.assertEquals(
        invite.dSubject, appt.getSubject(), "Subject: Verify the appointment data");

    // Go to next/previous week and verify correct number of recurring instances
    app.zPageCalendar.zToolbarPressButton(Button.B_NEXT_PAGE);
    SleepUtil.sleepMedium(); // Let UI draw first and important for calendar testcases reliability
    ZAssert.assertEquals(
        app.zPageCalendar.zGetApptCountWorkWeekView(),
        2,
        "Verify correct no. of recurring instances are present in calendar view");

    app.zPageCalendar.zToolbarPressButton(Button.B_NEXT_PAGE);
    app.zPageCalendar.zToolbarPressButton(Button.B_NEXT_PAGE);
    SleepUtil.sleepMedium(); // Let UI draw first and important for calendar testcases reliability
    ZAssert.assertEquals(
        app.zPageCalendar.zGetApptCountWorkWeekView(),
        0,
        "Verify correct no. of recurring instances are present in calendar view");
  }
  @Test(
      description =
          "Close modifying appt and take action from warning dialog : Dont save But keep open",
      groups = {"functional"})
  public void ModifyAppointment_03() throws HarnessException {

    // Creating object for appointment data
    AppointmentItem appt = new AppointmentItem();
    String tz, apptSubject, apptAttendee1, apptAttendee2, editApptSubject;
    tz = ZTimeZone.TimeZoneEST.getID();

    apptSubject = ZimbraSeleniumProperties.getUniqueString();
    editApptSubject = ZimbraSeleniumProperties.getUniqueString();
    apptAttendee1 = ZimbraAccount.AccountA().EmailAddress;
    apptAttendee2 = ZimbraAccount.AccountB().EmailAddress;

    // Absolute dates in UTC zone
    Calendar now = this.calendarWeekDayUTC;
    ZDate startUTC =
        new ZDate(
            now.get(Calendar.YEAR),
            now.get(Calendar.MONTH) + 1,
            now.get(Calendar.DAY_OF_MONTH),
            12,
            0,
            0);
    ZDate endUTC =
        new ZDate(
            now.get(Calendar.YEAR),
            now.get(Calendar.MONTH) + 1,
            now.get(Calendar.DAY_OF_MONTH),
            14,
            0,
            0);

    app.zGetActiveAccount()
        .soapSend(
            "<CreateAppointmentRequest xmlns='urn:zimbraMail'>"
                + "<m>"
                + "<inv method='REQUEST' type='event' status='CONF' draft='0' class='PUB' fb='B' transp='O' allDay='0' name='"
                + apptSubject
                + "'>"
                + "<s d='"
                + startUTC.toTimeZone(tz).toYYYYMMDDTHHMMSS()
                + "' tz='"
                + tz
                + "'/>"
                + "<e d='"
                + endUTC.toTimeZone(tz).toYYYYMMDDTHHMMSS()
                + "' tz='"
                + tz
                + "'/>"
                + "<or a='"
                + app.zGetActiveAccount().EmailAddress
                + "'/>"
                + "<at role='REQ' ptst='NE' rsvp='1' a='"
                + apptAttendee1
                + "' d='2'/>"
                + "<at role='REQ' ptst='NE' rsvp='1' a='"
                + apptAttendee2
                + "' d='2'/>"
                + "</inv>"
                + "<e a='"
                + ZimbraAccount.AccountA().EmailAddress
                + "' t='t'/>"
                + "<mp content-type='text/plain'>"
                + "<content>"
                + ZimbraSeleniumProperties.getUniqueString()
                + "</content>"
                + "</mp>"
                + "<su>"
                + apptSubject
                + "</su>"
                + "</m>"
                + "</CreateAppointmentRequest>");
    app.zPageCalendar.zToolbarPressButton(Button.B_REFRESH);
    String apptId =
        app.zGetActiveAccount().soapSelectValue("//mail:CreateAppointmentResponse", "apptId");

    // Try to remove attendee and press close button
    app.zPageCalendar.zListItem(Action.A_DOUBLECLICK, apptSubject);
    FormApptNew apptForm = new FormApptNew(app);
    appt.setSubject(editApptSubject);
    apptForm.zRemoveAttendee(apptAttendee2);
    apptForm.zToolbarPressButton(Button.B_CLOSE);

    DialogConfirmModification confirmClose =
        (DialogConfirmModification) new DialogConfirmModification(app, app.zPageCalendar);
    confirmClose.zClickButton(Button.B_DONTSAVE_KEEP_OPEN);
    confirmClose.zClickButton(Button.B_SAVE_MODIFICATION);

    // Verify 'Save Appointment' dialog is closed
    ZAssert.assertFalse(confirmClose.zIsActive(), "Verify 'Save Appointment' dialog is closed");

    // Verify new appt page is still open
    ZAssert.assertFalse(apptForm.zVerifyNewApptTabClosed(), "Verify new appt page is still open");

    app.zGetActiveAccount()
        .soapSend("<GetAppointmentRequest  xmlns='urn:zimbraMail' id='" + apptId + "'/>");
    AppointmentItem modifyAppt =
        AppointmentItem.importFromSOAP(ZimbraAccount.AccountA(), "subject:(" + apptSubject + ")");

    // Verify that appointment subject is not modified
    ZAssert.assertEquals(
        app.zGetActiveAccount()
            .soapMatch("//mail:GetAppointmentResponse//mail:comp", "name", apptSubject),
        true,
        "");

    // Verify meeting attendees remains as it is
    ZAssert.assertStringContains(
        modifyAppt.getAttendees(),
        apptAttendee2,
        "Attendees: Verify attendee1 is present in the meeting invite");
    ZAssert.assertStringContains(
        modifyAppt.getAttendees(),
        apptAttendee1,
        "Attendees: Verify attendee2 is present in the meeting invite");
  }