/** 
 | 
 * @file        S&OP DateTimeSelector component to wrap common methods the team encounter during development 
 | 
 * @description DateTimeSelector class extending Abstraction API's QDateTimeSelector. 
 | 
 * All S&OP page objects inherit from our own class (inheriting e2e/Abstraction API), but we can propose common methods to them. 
 | 
 * @author      Clarence (clarence.chan@3ds.com) 
 | 
 * @copyright   Dassault Systèmes 
 | 
 */ 
 | 
import { QDateTimeSelector } from '../e2elib/lib/api/pageobjects/qdatetimeselector.component'; 
 | 
import { ElementFinder } from '../e2elib/node_modules/protractor/built'; 
 | 
import { UIActionSOP } from './objectsop'; 
 | 
import { QUtils } from '../e2elib/lib/src/main/qutils.class'; 
 | 
import { QDateTimeOmitOptions } from '../e2elib/lib/api/types'; 
 | 
  
 | 
export class DateTimeSelectorSOP extends QDateTimeSelector implements UIActionSOP { 
 | 
  private readonly _separator = '-'; 
 | 
  private readonly _omit: QDateTimeOmitOptions; // Hide the datetime portions that are not present for this field in web app 
 | 
  
 | 
  public constructor(componentPath: string, omit: QDateTimeOmitOptions = {hour: true, minute: true, second: true}, isCustomPath?: boolean, elementObj?: ElementFinder) { 
 | 
    super(componentPath, isCustomPath, elementObj); 
 | 
    this._omit = omit; 
 | 
  } 
 | 
  
 | 
  public async clickActionLinkText(expectedActionLinkText: string): Promise<void> { 
 | 
    const isActionLinkMatch = await this.hasActionLink() && await this.getActionLinkText() === expectedActionLinkText; 
 | 
    expect(isActionLinkMatch).toBe(true, `Unable to proceed click action link for datetimeselector ${await this.getComponentLabel()}. Expecting action link text '${expectedActionLinkText}'.`); 
 | 
  
 | 
    if (isActionLinkMatch) { 
 | 
      await this.clickActionLink(); 
 | 
    } 
 | 
  } 
 | 
  
 | 
  public getDateFromString(value: string): Date { 
 | 
    let date = new Date(1899, 11, 31, 0, 0, 0, 0); // This is default Quintiq value if datetime component only shows time 
 | 
    let dateOnly = ''; 
 | 
    if (!this._omit.date) { 
 | 
      const dateMatchArr = value.match(new RegExp('(\\d{1,2}-\\w{3}-\\d{4})', 'g')); 
 | 
      if (dateMatchArr !== null) { 
 | 
        dateOnly = dateMatchArr[0]; 
 | 
  
 | 
        const tokens = dateOnly.split(this._separator); 
 | 
        date = new Date(`${tokens[1]} ${tokens[0]}, ${tokens[2]}`); // Format "Jan 1, 2020" 
 | 
      } 
 | 
    } 
 | 
  
 | 
    const timeMatchArr = value.match(new RegExp('(\\d{2}:\\d{2}(:\\d{2})?)', 'g')); 
 | 
    let timeOnly = ''; 
 | 
    if (timeMatchArr !== null) { 
 | 
      timeOnly = timeMatchArr[0]; 
 | 
    } 
 | 
  
 | 
    const timeTokens = timeOnly.split(':'); 
 | 
    if (!this._omit.hour) { 
 | 
      const hourToken = timeTokens.shift(); 
 | 
      date.setHours(Number(hourToken)); 
 | 
    } 
 | 
  
 | 
    if (!this._omit.minute) { 
 | 
      const minToken = timeTokens.shift(); 
 | 
      date.setMinutes(Number(minToken)); 
 | 
    } 
 | 
  
 | 
    if (!this._omit.second) { 
 | 
      const secToken = timeTokens.shift(); 
 | 
      date.setSeconds(Number(secToken)); 
 | 
    } 
 | 
  
 | 
    return date; 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Returns the string representation of the datetimeselector for the visible datetime portions only. 
 | 
   * Thus not able use Abstraction API getDate/getDateTime methods as that returns Date. 
 | 
   * Example: If datetimeselector showing only hours and minutes, we will return only what is visible as string value. 
 | 
   * 
 | 
   * @returns Full datetime value string that potential to be returned is "1-Jan-2020 14:30:20" (down to the seconds). Or just either the date or time portion as string. 
 | 
   */ 
 | 
  public async getValueString(): Promise<string> { 
 | 
    let dateStr = ''; 
 | 
    // If field showing date, format the date str with format "1-Jan-2020" 
 | 
    if (!this._omit.date) { 
 | 
      const day = (await this.getDay()).padStart(2, '0'); 
 | 
      const month = await this.getMonth(); 
 | 
      const year = await this.getYear(); 
 | 
      dateStr = `${day}${this._separator}${month}${this._separator}${year}`; 
 | 
    } 
 | 
  
 | 
    // If field showing any time portions, format the string value 
 | 
    let timeStr = ''; 
 | 
    if (!this._omit.hour) { 
 | 
      timeStr = timeStr + (await this.getHour()).padStart(2, '0'); 
 | 
    } 
 | 
  
 | 
    if (!this._omit.minute) { 
 | 
      if (timeStr !== '') { 
 | 
        timeStr = `${timeStr  }:`; 
 | 
      } 
 | 
  
 | 
      timeStr = timeStr + (await this.getMinute()).padStart(2, '0'); 
 | 
    } 
 | 
  
 | 
    if (!this._omit.second) { 
 | 
      if (timeStr !== '') { 
 | 
        timeStr = `${timeStr  }:`; 
 | 
      } 
 | 
  
 | 
      timeStr = timeStr + (await this.getSecond()).padStart(2, '0'); 
 | 
    } 
 | 
  
 | 
    // Format the final string to return (either both date+time available, or only one of them). 
 | 
    const spaceBetweenDateAndTime = (dateStr !== '' && timeStr !== '') ? ' ' : ''; // If both date+time available, put a space between them. 
 | 
    const finalDateStr = `${dateStr}${spaceBetweenDateAndTime}${timeStr}`; 
 | 
  
 | 
    return finalDateStr; 
 | 
  } 
 | 
  
 | 
  public async setValue(value: string): Promise<void> { 
 | 
    // Convert user input string into Date object 
 | 
    const dateTime: Date = this.getDateFromString(value); 
 | 
  
 | 
    // Send the Date object into Abstraction API method which knows how to fill in our datetimeselector in web app 
 | 
    await this.setDateTime(dateTime, this._omit); 
 | 
  } 
 | 
  
 | 
  public async toggleValue(): Promise<void> { 
 | 
    const previousDateValue = await this.getValueString(); 
 | 
    const previousDate = this.getDateFromString(previousDateValue); 
 | 
    previousDate.setDate(previousDate.getDate() + 1); 
 | 
    previousDate.setHours(previousDate.getHours() + 1); 
 | 
    previousDate.setMinutes (previousDate.getMinutes() + 1); 
 | 
    previousDate.setSeconds(previousDate.getSeconds() + 1); 
 | 
    await this.setDateTime(previousDate, this._omit); 
 | 
  } 
 | 
  
 | 
  public async verifyBatchEditEnabled(expectedEnable: boolean, expectedActionLinkText: string): Promise<void> { 
 | 
    const isBatchEditEnableDisableOK = await this.hasActionLink() && 
 | 
                                       await this.getActionLinkText() === expectedActionLinkText && 
 | 
                                       !await this.isDisabled() === expectedEnable; 
 | 
    expect(isBatchEditEnableDisableOK).toBe(true, `Verify datetimeselector ${await this.getComponentLabel()} supports batch edit (expected enable = ${expectedEnable} & action link = ${expectedActionLinkText}).`); 
 | 
  } 
 | 
  
 | 
  public async verifyHasMaskError(expectedValue: boolean): Promise<void> { 
 | 
    // Implements UIActionSOP 
 | 
    await this.hasMaskError(expectedValue); 
 | 
  } 
 | 
  
 | 
  public async verifyTooltip(expectedValue: string): Promise<void> { 
 | 
    const tooltip = await QUtils.getTooltip(this.tooltipLabelElement, true, true, true); 
 | 
    expect(tooltip).toBe(expectedValue, `Hover ${await this.getComponentLabel()} to verify tooltip.`); 
 | 
  } 
 | 
  
 | 
  public async verifyEnabled(expectedEnable: boolean): Promise<void> { 
 | 
    expect(!await this.isDisabled()).toBe(expectedEnable, `Verify enable state for datetimeselector ${await this.getComponentLabel()}.`); 
 | 
  } 
 | 
  
 | 
  public async verifyValue(expectedValue: string): Promise<void> { 
 | 
    const actualDate = await this.getDateTime(); // Get Date object from the datetimeselector component in web app 
 | 
    const expectedDate = this.getDateFromString(expectedValue); // Get Date object from user expected string 
 | 
  
 | 
    // Cannot direct compare Dates, use valueOf which returns the primitive underlying value such as 823230245000 
 | 
    const datesEqual = actualDate.valueOf() === expectedDate.valueOf(); 
 | 
    expect(datesEqual).toBe(true, `Verify value fail for datetimeselector ${await this.getComponentLabel()}. Expected = ${expectedValue}, actual = ${await this.getValueString()}.`); 
 | 
  } 
 | 
  
 | 
  public async verifyVisible(expectedValue: string): Promise<void> { 
 | 
    expect(await this.isVisible()).toBe(expectedValue.toLowerCase() === 'true', `Verify visible state for datetimeselector ${await this.getComponentLabel()}.`); 
 | 
  } 
 | 
 } 
 |