| 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 }; |