import { QContextMenu } from '../e2elib/lib/api/pageobjects/qcontextmenu.component'; 
 | 
import { GanttChartNode } from '../e2elib/lib/src/pageobjects/ganttchart/ganttchartnode'; 
 | 
import { GanttChartRow } from '../e2elib/lib/src/pageobjects/ganttchart/ganttchartrow'; 
 | 
import { GanttChartBase } from '../libappbase/ganttchartbase'; 
 | 
import { convertDateToUTC } from '../libappbase/timeutils'; 
 | 
import { getHtmlContent } from '../libappbase/utils'; 
 | 
import { ColorSOP } from './colorsop'; 
 | 
import { ContextMenuItemSOP, ContextMenuSOP } from './contextmenusop'; 
 | 
  
 | 
export class GanttChartSOP extends GanttChartBase { 
 | 
  private readonly _contextMenu: QContextMenu; 
 | 
  private readonly _cmMenuMap: Map<string, QContextMenu> = new Map(); 
 | 
  
 | 
  /** 
 | 
   * Format the node filtering criteria to be used in step description object. 
 | 
   * 
 | 
   * @param nodeCriteria The node filtering criteria (e.g filter by color). 
 | 
   * @returns The filtering text to be used in step description object. 
 | 
   */ 
 | 
  public static formatStepDescriptionNodeCriteria(nodeCriteria?: GanttChartNodeSOPCriteria): string { 
 | 
    const criteriaArr: string[] = []; 
 | 
    if (nodeCriteria) { 
 | 
      if (nodeCriteria.ColorHex) { 
 | 
        criteriaArr.push(`ColorHex = ${nodeCriteria?.ColorHex}`); 
 | 
      } 
 | 
  
 | 
      // Extend with more criteria in future 
 | 
    } 
 | 
  
 | 
    // If node criteria undefined, meaning retrieve nodes without filtering thus no criteria text to return 
 | 
    const criteriaTextResult = nodeCriteria ? ` Node filtering criteria: ${criteriaArr.join(', ')}.` : ''; 
 | 
  
 | 
    return criteriaTextResult; 
 | 
  } 
 | 
  
 | 
  public constructor(formName: string, componentPath: string, contextMenuName?: string) { 
 | 
    super(formName, componentPath); 
 | 
  
 | 
    if (contextMenuName) { 
 | 
      this._contextMenu = new QContextMenu(contextMenuName); 
 | 
    } 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Select multiple nodes (based on one or more index, 0-based) in a gantt chart row, right click and select context menu item. 
 | 
   * 
 | 
   * @param row Row to right click select nodes 
 | 
   * @param indexes Index of nodes to select (0-based index) 
 | 
   * @param contextMenuItem Context menu item to select 
 | 
   */ 
 | 
  public async rightClickNodeIndexesAndSelectContextMenu(row: GanttChartRow, indexes: number[], contextMenuItem: ContextMenuItemSOP): Promise<void> { 
 | 
    const nodes = await this.getAllNodes(row); 
 | 
    for (const i of indexes) { 
 | 
      const node = nodes[i]; 
 | 
      await this.rightClickNode(node, await node.getStartDate(), true); 
 | 
    } 
 | 
    await this._contextMenu.selectMenuItem(contextMenuItem.Name); 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Right click row and select menu in context menu. 
 | 
   * 
 | 
   * @param gcRow row to right click. 
 | 
   * @param contextMenuItem Context menu item to select. 
 | 
   */ 
 | 
  public async rightClickRowAndSelectMenu(gcRow: GanttChartRow, contextMenuItem: ContextMenuItemSOP): Promise<void> { 
 | 
    const contextMenu = this.findCreateContextMenu(contextMenuItem.ContextMenu); 
 | 
    await this.rightClickRow(gcRow); 
 | 
  
 | 
    expect(await contextMenu!.isVisible()).toBe(true, 'ContextMenu on GanttChart shall be seen'); 
 | 
    await contextMenu!.selectMenuItem(contextMenuItem.Name); 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * To find and verify the gantt chart node exists for certain start and end date. 
 | 
   * 
 | 
   * @param rowName The gantt chart row name. 
 | 
   * @param start The start date of the node. 
 | 
   * @param end The end date of the node. 
 | 
   * @param nodeColor The background color of the node. 
 | 
   */ 
 | 
  public async verifyNodeExists(rowName: string, start: Date, end: Date, nodeColor?: ColorSOP): Promise<void> { 
 | 
    const rows = await this.getAllRows(); 
 | 
    let row: GanttChartRow | undefined; 
 | 
  
 | 
    // Find matching row 
 | 
    for (const r of rows) { 
 | 
      const rTitle = await r.getTitle(); 
 | 
      // Remove HTML content to get the title 
 | 
      if (getHtmlContent(rTitle)[0] === rowName) { 
 | 
        row = r; 
 | 
        break; 
 | 
      } 
 | 
    } 
 | 
  
 | 
    if (row !== undefined) { 
 | 
      const s = await (await row.getNode(0))?.getStartDate(); 
 | 
      const e = await (await row.getNode(0))?.getEndDate(); 
 | 
  
 | 
      expect(s?.getTime()).toBe(convertDateToUTC(start).getTime(), 'Start date is different.'); 
 | 
      expect(e?.getTime()).toBe(convertDateToUTC(end).getTime(), 'End date is different.'); 
 | 
  
 | 
      if (nodeColor) { 
 | 
        const bgcolor = (await row.getNode(0))?.getBackgroundColor(); 
 | 
        expect(bgcolor).toBe(nodeColor.Hex, 'Node color is different.'); 
 | 
      } 
 | 
    } else { 
 | 
      fail(`Unable to find the gantt chart row ${  rowName}`); 
 | 
    } 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Verifies if the gantt chart row has the expected number of nodes. 
 | 
   * 
 | 
   * @param gcRow The row to check if it has the expected number of nodes. 
 | 
   * @param expectedNum The expected number of nodes. 
 | 
   * @param nodeCriteria The criteria to count node 
 | 
   */ 
 | 
  public async verifyNodeCount(gcRow: GanttChartRow, expectedNum: number, nodeCriteria?: GanttChartNodeSOPCriteria): Promise<void> { 
 | 
    let numNodes = 0; 
 | 
    if (nodeCriteria) { 
 | 
      const nodes = await this.getAllNodes(gcRow); 
 | 
      for (const node of nodes) { 
 | 
        if (nodeCriteria.ColorHex && nodeCriteria.ColorHex === (await node.getBackgroundColor())) { 
 | 
          numNodes++; 
 | 
        } 
 | 
      } 
 | 
    } else { 
 | 
      numNodes = await gcRow.getNumNodes(); 
 | 
    } 
 | 
    expect(numNodes).toBe(expectedNum, `Verify fail for retrieving node count.${GanttChartSOP.formatStepDescriptionNodeCriteria(nodeCriteria)}`); 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Verifies when node is right clicked, the context menu item is disabled and shows the expected tooltip. 
 | 
   * 
 | 
   * @param rowTitle Gantt chart row title 
 | 
   * @param nodeStartOrIndex Node index number (to enhance with start in future if needed) 
 | 
   * @param contextMenuItem Context menu item that should be disabled 
 | 
   * @param tooltip Tooltip expected when context menu item is about to be selected 
 | 
   */ 
 | 
  public async verifyNodeContextMenuItemDisabled(rowTitle: string, nodeStartOrIndex: number, contextMenuItem: ContextMenuItemSOP, tooltip: string): Promise<void> { 
 | 
    const contextMenu = this.findCreateContextMenu(contextMenuItem.ContextMenu); 
 | 
  
 | 
    const row = (await this.getRowsByTitle(rowTitle))[0]; 
 | 
    const node = (await row.getNode(nodeStartOrIndex)) as GanttChartNode; 
 | 
  
 | 
    if (this.verifyNodeDefined(node, rowTitle, nodeStartOrIndex)) { 
 | 
      await this.rightClickNode(node); 
 | 
  
 | 
      const [isClickable, actualToolTip] = await ContextMenuSOP.verifyIsMenuItemClickable(contextMenu!, contextMenuItem.Name, true); 
 | 
      expect(isClickable).toBe(false, `Expected context menu "${contextMenuItem.Label}" disabled for node index ${nodeStartOrIndex} in row = "${rowTitle}".`); 
 | 
      expect(actualToolTip).toBe(tooltip, `Verify tooltip fail for context menu "${contextMenuItem.Label}" on node index ${nodeStartOrIndex} in row = "${rowTitle}"."`); 
 | 
    } 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Verifies when row is right clicked, the context menu item is disabled and shows the expected tool tip. 
 | 
   * 
 | 
   * @param rowTitle Row title to right click and check 
 | 
   * @param contextMenuItem Context menu item that should be disabled 
 | 
   * @param tooltip Tooltip expected when context menu item is about to be selected 
 | 
   * @param tooltipExactMatch true by default. If true, the expected tooltip is to be exactly the same. Else, the expected tooltip is expected to contain the tooltip parameter. 
 | 
   */ 
 | 
  public async verifyRowContextMenuItemDisabled(rowTitle: string, contextMenuItem: ContextMenuItemSOP, tooltip: string, tooltipExactMatch: boolean = true): Promise<void> { 
 | 
    const contextMenu = this.findCreateContextMenu(contextMenuItem.ContextMenu); 
 | 
  
 | 
    const row = (await this.getRowsByTitle(rowTitle))[0]; 
 | 
    await this.rightClickRow(row); 
 | 
  
 | 
    const [isClickable, actualToolTip] = await ContextMenuSOP.verifyIsMenuItemClickable(contextMenu!, contextMenuItem.Name, true); 
 | 
    expect(isClickable).toBe(false, `Expected context menu "${contextMenuItem.Label}" disabled for row = "${rowTitle}".`); 
 | 
    if (tooltipExactMatch) { 
 | 
      expect(actualToolTip).toBe(tooltip, `Verify tooltip fail for context menu "${contextMenuItem.Label}" on row = "${rowTitle}".`); 
 | 
    } else { 
 | 
      expect(actualToolTip).toContain(tooltip, `Verify tooltip fail for context menu "${contextMenuItem.Label}" on row = "${rowTitle}".`); 
 | 
    } 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Throws error if gantt chart node is undefined. Use in method to verify before proceeding with more node related actions. 
 | 
   * 
 | 
   * @param node Node to verify. 
 | 
   * @param rowTitle Gantt chart row title, to be used in error message if node is undefined. 
 | 
   * @param nodeStartOrIndex Gantt chart node start time or index, to be used in error message if node is undefined. 
 | 
   * @returns True if node is defined, else method will already throw error before reach return statement. 
 | 
   */ 
 | 
  private verifyNodeDefined(node: GanttChartNode | undefined, rowTitle: string, nodeStartOrIndex: number): boolean { 
 | 
    if (node === undefined) { 
 | 
      throw Error(`Cannot find gantt chart node with row title = "${rowTitle}" and node index = "${nodeStartOrIndex}".`); 
 | 
    } 
 | 
  
 | 
    return true; 
 | 
  } 
 | 
  
 | 
  public async verifyRowExists(rowTitle: string): Promise<void> { 
 | 
    const rows = await this.getRowsByTitle(rowTitle); 
 | 
    expect(rows.length === 1).toBe(true, `Cannot find gantt chart row with title "${rowTitle}".`); 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Returns the context menu from stored map if previously created, else create, store and return it. 
 | 
   * 
 | 
   * @param name Context menu name. 
 | 
   * @returns Context menu from stored map. 
 | 
   */ 
 | 
  private findCreateContextMenu(name: string): QContextMenu | undefined { 
 | 
    let cmMenu: QContextMenu | undefined; 
 | 
    if (this._cmMenuMap.has(name)) { 
 | 
      cmMenu = this._cmMenuMap.get(name); 
 | 
    } else { 
 | 
      cmMenu = new QContextMenu(name); 
 | 
      this._cmMenuMap.set(name, cmMenu); 
 | 
    } 
 | 
  
 | 
    return cmMenu; 
 | 
  } 
 | 
} 
 | 
  
 | 
/** 
 | 
 * One or more criteria defining the gantt chart node. To be used when verifying if node(s) fulfills the criteria. 
 | 
 * Example: verify number of nodes that are blue in color. 
 | 
 */ 
 | 
export interface GanttChartNodeSOPCriteria { 
 | 
  ColorHex?: string; 
 | 
} 
 | 
  
 | 
// Step description to re-use in spec file to prevent scriptor re-write each time 
 | 
const stepGanttChart = { 
 | 
  ensureVisible: (gcName: string, startDate: string): string => `In gantt chart "${gcName}", scroll gantt chart time such that date "${startDate}" is visible.`, 
 | 
  rightClickNodeIndexesAndSelectContextMenu: (gcName: string, gcRowTitle: string, indexes: number[], menuLabel: string): string => `In gantt chart "${gcName}" and in row "${gcRowTitle}", right click node(s) with index "${indexes}" and select menu "${menuLabel}".`, 
 | 
  rightClickRowAndSelectContextMenu: (gcName: string, gcRowTitle: string, menuLabel: string): string => `In gantt chart "${gcName}", right click row "${gcRowTitle}" and select menu "${menuLabel}".`, 
 | 
  verifyNodeExists: (gcName: string, gcRowTitle: string, start: Date, end: Date, nodeColor?: string): string => { 
 | 
    const verifyColor = nodeColor ? ` Verify node color = "${nodeColor}".` : ''; 
 | 
    return `In gantt chart "${gcName}", verify node exists for row = "${gcRowTitle}", start = "${start.toString()}" and end = "${end.toString()}".${verifyColor}`; 
 | 
  }, 
 | 
  verifyNodeValue: (gcName: string, gcRowTitle: string, start: string, end: string, expectedValue: string): string => `In gantt chart "${gcName}", verify node value = ${expectedValue} for row = "${gcRowTitle}", start = "${start}" and end = "${end}".`, 
 | 
  verifyNodeContextMenuItemDisabled: (gcName: string, gcRowTitle: string, gcNodeIndex: string, menuLabel: string, tooltip: string): string => 
 | 
    `In gantt chart "${gcName}", verify node at row "${gcRowTitle}" and node index "${gcNodeIndex}" when right clicked, menu item "${menuLabel}" is disabled and shows tooltip "${tooltip}".`, 
 | 
  verifyNodeCount: (gcName: string, gcRowTitle: string, expectedNum: number, nodeCriteria?: GanttChartNodeSOPCriteria): string => 
 | 
    `In gantt chart "${gcName}", verify number of nodes in row "${gcRowTitle}" to be "${expectedNum}".${GanttChartSOP.formatStepDescriptionNodeCriteria(nodeCriteria)}`, 
 | 
  verifyRowContextMenuItemDisabled: (gcName: string, gcRowTitle: string, label: string, tooltip: string): string => 
 | 
    `In gantt chart "${gcName}", verify when row "${gcRowTitle}" is right clicked, menu item "${label}" is disabled and shows tooltip "${tooltip}".`, 
 | 
  verifyRowExists: (gcName: string, rowTitle: string): string => `In gantt chart "${gcName}", verify row "${rowTitle}" exists.`, 
 | 
}; 
 | 
  
 | 
export { stepGanttChart as StepGanttChart }; 
 |