-
Notifications
You must be signed in to change notification settings - Fork 0
/
emp-app.ts
192 lines (156 loc) · 7.62 KB
/
emp-app.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
import { Employee, IEmployeeOrgApp, ceo, bob, georgina } from "./constant";
class EmployeeOrgApp implements IEmployeeOrgApp {
ceo: Employee;
private previousActions: {
move: { employeeID: number, supervisorID: number }, undo: {
subordinates: Employee[]; employeeID: number, supervisorID: number
}
}[] = [];
private currentActionIndex = -1;
constructor(ceo: Employee) {
this.ceo = ceo;
}
public findEmployee(employeeID: number, currentEmployee: Employee): Employee | null {
// Return current employee if ids are equal
if (currentEmployee.uniqueId === employeeID) {
return currentEmployee;
}
// Recursively search for employee in the subordinates of current employee
for (const subordinate of currentEmployee.subordinates) {
const subEmployee = this.findEmployee(employeeID, subordinate);
if (subEmployee) {
return subEmployee;
}
}
// Return null if employee is not found in the subordinates of the current employee
return null;
}
public findSupervisor(employee: Employee, currentEmployee: Employee): Employee | null {
// Return current employee if employee is found in the list of subordinates
if (currentEmployee.subordinates.includes(employee)) {
return currentEmployee;
}
// Return employee if it is the CEO
if (employee === this.ceo) {
return employee;
}
// Recursively search for supervisor in the subordinates of current employee
for (const subordinate of currentEmployee.subordinates) {
const supervisor = this.findSupervisor(employee, subordinate);
if (supervisor) {
return supervisor;
}
}
// Return null if the employee is not found in the subordinates of the current employee
return null;
}
move(employeeID: number, supervisorID: number): void {
// Find employee with the given employeeID
const employee = this.findEmployee(employeeID, this.ceo);
if (!employee) {
throw new Error(`Employee with ID ${employeeID} not found.`);
}
// Find supervisor with the given supervisorID
const supervisor = this.findEmployee(supervisorID, this.ceo);
if (!supervisor) {
throw new Error(`Supervisor with ID ${supervisorID} not found.`);
}
// Find current supervisor of the employee
const currentSupervisor = this.findSupervisor(employee, this.ceo);
if (!currentSupervisor) {
throw new Error(`Current supervisor of employee with ID ${employeeID} not found.`);
}
// Remove employee from the list of subordinates of their current supervisor
currentSupervisor.subordinates = currentSupervisor.subordinates.filter(e => e.uniqueId !== employee.uniqueId);
// Move employee's subordinate to current supervisor subordinates
currentSupervisor.subordinates = [...currentSupervisor.subordinates, ...employee.subordinates];
const tempSubordinates = [...employee.subordinates];
// Remove employee's subordinate
employee.subordinates = [];
// Add employee to the list of subordinates of the new supervisor
supervisor.subordinates.push(employee);
// Store the employee's previous supervisor and subordinates
const undoAction = {
employeeID: employee.uniqueId,
supervisorID: currentSupervisor.uniqueId,
subordinates: tempSubordinates
};
this.previousActions.push({ move: { employeeID, supervisorID }, undo: undoAction });
this.currentActionIndex++;
}
undo(): void {
// Check if there are some actions to undo
if (this.currentActionIndex < 0) {
throw new Error('There is no action to undo.');
}
// Get current action and the previous action
const currentAction = this.previousActions[this.currentActionIndex];
// Check if current action is a move action
if (currentAction.move) {
// Find employee and supervisor of the current action
const employee = this.findEmployee(currentAction.move.employeeID, this.ceo);
if (!employee) {
throw new Error(`Employee with ID ${currentAction.move.employeeID} not found.`);
}
const supervisor = this.findEmployee(currentAction.move.supervisorID, this.ceo);
if (!supervisor) {
throw new Error(`Supervisor with ID ${currentAction.move.supervisorID} not found.`);
}
// Remove employee from the list of subordinates of their current supervisor
supervisor.subordinates = supervisor.subordinates.filter(e => e.uniqueId !== employee.uniqueId);
// Add employee to the list of subordinates of their previous supervisor
const previousSupervisor = this.findEmployee(currentAction.undo.supervisorID, this.ceo);
if (!previousSupervisor) {
throw new Error(`Supervisor with ID ${currentAction.undo.supervisorID} not found.`);
}
previousSupervisor.subordinates.push(employee);
// Restore the employee's previous subordinates
employee.subordinates = currentAction.undo.subordinates;
const removeEmployee = (employeeID: number, subordinates: Employee[]): Employee[] => {
return subordinates.filter(employee => employee.uniqueId !== employeeID);
}
// Remove employee's subordinate include in employee's supervisor's subordinates
employee.subordinates.map(sub => {
previousSupervisor.subordinates = removeEmployee(sub.uniqueId, previousSupervisor.subordinates);
});
}
// Update current action index
this.currentActionIndex--;
}
redo(): void {
// Check if there are any actions to redo
if (this.currentActionIndex >= this.previousActions.length - 1) {
return;
}
// Retrieve next move action
const { move } = this.previousActions[this.currentActionIndex + 1];
const { employeeID, supervisorID } = move;
// Find employee and the supervisor involved in the move action
const employee = this.findEmployee(employeeID, this.ceo);
if (!employee) {
throw new Error(`Employee with ID ${employeeID} not found.`);
}
const supervisor = this.findEmployee(supervisorID, this.ceo);
if (!supervisor) {
throw new Error(`Supervisor with ID ${supervisorID} not found.`);
}
// Remove employee from the list of subordinates of their current supervisor
const currentSupervisor = this.findSupervisor(employee, this.ceo);
if (!currentSupervisor) {
throw new Error(`Supervisor with ID ${supervisorID} not found.`);
}
currentSupervisor.subordinates = currentSupervisor.subordinates.filter(e => e.uniqueId !== employee.uniqueId);
// Move employee's subordinate to current supervisor subordinates
currentSupervisor.subordinates = [...currentSupervisor.subordinates, ...employee.subordinates];
employee.subordinates = [];
// Add employee to the list of subordinates of the new supervisor
supervisor.subordinates.push(employee);
// Increment current action index
this.currentActionIndex++;
}
}
// Create a new instance of the EmployeeOrgApp class with the CEO
const app = new EmployeeOrgApp(ceo);
app.move(bob.uniqueId, georgina.uniqueId);
app.undo();
app.redo();