1 package org.wcb.model.service.impl;
2
3 import org.wcb.model.service.IValidatorService;
4 import org.wcb.model.vo.hibernate.Logbook;
5 import org.wcb.gui.util.ApplicationPreferences;
6 import org.wcb.gui.util.IPilotsLogApplicationPreferenceKeys;
7
8 import java.util.List;
9 import java.util.Date;
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 public class RecencyExperianceValidationService implements IValidatorService {
34
35 private List<Logbook> allEntriesList;
36
37 private static long DAYS90 = 129600;
38 private static long DAYS180 = 259200;
39 private StringBuilder messages;
40 private int countNightLanding = 0;
41 private int countDayLanding = 0;
42 private int countApproaches = 0;
43 private int countWarningNightLanding = 0;
44 private int countWarningDayLanding = 0;
45 private int countWarningApproaches = 0;
46 private int DAYSWARNING60 = 60;
47 private int DAYSWARNING150 = 150;
48 private int CURRENCY_90 = 90;
49 private int CURRENCY_180 = 180;
50
51 public Object getObject() {
52 return allEntriesList;
53 }
54
55 public void setObject(Object logObject) {
56 if (logObject instanceof List) {
57 this.allEntriesList = (List) logObject;
58 }
59 }
60
61 public String getMessage() {
62 return messages.toString();
63 }
64
65
66
67
68
69 public boolean validate() {
70 countNightLanding = 0;
71 countDayLanding = 0;
72 countApproaches = 0;
73 countWarningApproaches = 0;
74 countWarningDayLanding = 0;
75 countWarningNightLanding = 0;
76 boolean currentPassengers = false;
77 boolean currentNight = false;
78 boolean currentIFR = true;
79 boolean warningPassengers = false;
80 boolean warningIfr = false;
81 boolean warningNight = false;
82 for (Logbook objValue : allEntriesList) {
83 if (!isOver90Days(objValue.getEntryDate())) {
84
85
86 checkCurrentNight(objValue);
87
88 countDayLanding = countDayLanding + objValue.getDayLandings() + objValue.getNightLandings();
89 if (!isOverUserDefinedDays(objValue.getEntryDate(), ApplicationPreferences.getInstance().getInt(IPilotsLogApplicationPreferenceKeys.DAYS_WARNING_CARRY_PASSENGERS, DAYSWARNING60))) {
90 countWarningDayLanding = countWarningDayLanding + objValue.getDayLandings() + objValue.getNightLandings();
91 }
92 }
93
94 if (ApplicationPreferences.getInstance().getBoolean(IPilotsLogApplicationPreferenceKeys.CHECK_IFR)) {
95 if (!isOver180Days(objValue.getEntryDate())) {
96 countApproaches = countApproaches + objValue.getInstrumentApproaches();
97 if (!isOverUserDefinedDays(objValue.getEntryDate(), ApplicationPreferences.getInstance().getInt(IPilotsLogApplicationPreferenceKeys.DAYS_WARNING_IFR, DAYSWARNING150))) {
98 countWarningApproaches = countWarningApproaches + objValue.getInstrumentApproaches();
99 }
100 }
101 }
102 }
103 messages = new StringBuilder();
104
105 currentNight = this.addMessageNightCurrency(messages, countNightLanding, countWarningNightLanding);
106 currentPassengers = this.addMessageCarryingDayPassengers(messages, countDayLanding, countWarningDayLanding);
107 if (ApplicationPreferences.getInstance().getBoolean(IPilotsLogApplicationPreferenceKeys.CHECK_IFR)) {
108 currentIFR = this.addMessageIFR(messages, countApproaches, countWarningApproaches);
109 }
110 return currentPassengers && currentNight && currentIFR;
111 }
112
113 private void checkCurrentNight(Logbook obj) {
114 if(obj.getConditionNight() > 0) {
115 countNightLanding = countNightLanding + obj.getNightLandings();
116 if (!isOverUserDefinedDays(obj.getEntryDate(), ApplicationPreferences.getInstance().getInt(IPilotsLogApplicationPreferenceKeys.DAYS_WARNING_CARRY_NIGHT, 90))) {
117 countWarningNightLanding = countWarningNightLanding + obj.getNightLandings();
118 }
119 }
120 }
121
122
123
124
125
126
127
128
129 private boolean addMessageNightCurrency(StringBuilder messages, int nightLanding, int warnNightLanding) {
130 if (nightLanding > 3) {
131 messages.append("You are current for passenger carry on a night flight.\n \n");
132 if(warnNightLanding <= 3) {
133 messages.append("WARNING: You will not be current to carry passengers at night in less then ");
134 messages.append(CURRENCY_90 - ApplicationPreferences.getInstance().getInt(IPilotsLogApplicationPreferenceKeys.DAYS_WARNING_CARRY_NIGHT, DAYSWARNING60));
135 messages.append(" days.\n");
136 return false;
137 }
138 return true;
139 }
140 else {
141 messages.append("You are NOT night current.\n");
142 messages.append("FAR 61.57 \n");
143 messages.append("(b) Night takeoff and landing experience.\n (1) Except as provided in paragraph (e) of this section, \n no person may act as pilot in command of an aircraft carrying passengers during the period beginning 1 hour after sunset and ending 1 hour before sunrise,\n unless within the preceding 90 days that person has made at least three takeoffs and three landings to a full stop during the period beginning 1 hour after sunset and ending 1 hour before sunrise, and—\n");
144 messages.append("(i) That person acted as sole manipulator of the flight controls; and\n");
145 messages.append("(ii) The required takeoffs and landings were performed in an aircraft of the same category, class, and type (if a type rating is required).\n \n");
146 }
147 return false;
148 }
149
150
151
152
153
154
155
156 private boolean addMessageIFR(StringBuilder messages, int approaches, int warningApproaches) {
157 if (approaches >=6 ) {
158 messages.append("You are current for instrument flights. (FAR 61.57, C. Instrument Experience)\n \n");
159 if(warningApproaches < 6 ) {
160 messages.append("WARNING: You will not be current for instruments in less then ");
161 messages.append(CURRENCY_180 - ApplicationPreferences.getInstance().getInt(IPilotsLogApplicationPreferenceKeys.DAYS_WARNING_IFR, DAYSWARNING150));
162 messages.append(" days.\n");
163 return false;
164 }
165 return true;
166 }
167 else {
168 messages.append("You are not current for instruments.\n");
169 messages.append(" (c) Instrument experience. Except as provided in paragraph (e) of this section, no person may act as pilot in command under\n IFR or in weather conditions less than the minimums prescribed for VFR, unless within the preceding 6 calendar months, that person has:\n");
170 messages.append("(1) For the purpose of obtaining instrument experience in an aircraft (other than a glider), performed and logged under actual \n or simulated instrument conditions, either in flight in the appropriate category of aircraft for the instrument privileges sought or in a flight simulator or flight training device that is representative of the aircraft category for the instrument privileges sought—\n");
171 messages.append("(i) At least six instrument approaches;\n");
172 messages.append("(ii) Holding procedures; and\n");
173 messages.append("(iii) Intercepting and tracking courses through the use of navigation systems.\n \n");
174 }
175 return false;
176 }
177
178
179
180
181
182
183
184
185 private boolean addMessageCarryingDayPassengers(StringBuilder messages, int landings, int warningDay) {
186 if (landings > 3) {
187 messages.append("You are current for passenger carry on DAY flight. (FAR 61.57 Recent Flight experience: Pilot in command.)\n \n");
188 if(warningDay <= 3) {
189 messages.append("WARNING: You will not be current to carry passengers in less than ");
190 messages.append(CURRENCY_90 - ApplicationPreferences.getInstance().getInt(IPilotsLogApplicationPreferenceKeys.DAYS_WARNING_CARRY_PASSENGERS, DAYSWARNING60));
191 messages.append(" days.\n");
192 return false;
193 }
194 return true;
195 }
196 else {
197 messages.append("You are NOT current to carry passengers. \n");
198 messages.append("FAR 61.57 \n");
199 messages.append("(a) General experience. (1) Except as provided in paragraph (e) of this section, no person may act as a pilot in command of an aircraft carrying passengers or of an aircraft certificated for more than one pilot flight crewmember unless that person has made at least three takeoffs and three landings within the preceding 90 days, and—\n");
200 messages.append("(i) The person acted as the sole manipulator of the flight controls; and\n");
201 messages.append("(ii) The required takeoffs and landings were performed in an aircraft of the same category, class, and type (if a type rating is required), and, if the aircraft to be flown is an airplane with a tailwheel, the takeoffs and landings must have been made to a full stop in an airplane with a tailwheel.\n");
202 messages.append("(2) For the purpose of meeting the requirements of paragraph (a)(1) of this section, a person may act as a pilot in command of an aircraft under day VFR or day IFR, provided no persons or property are carried on board the aircraft, other than those necessary for the conduct of the flight.\n");
203 messages.append("(3) The takeoffs and landings required by paragraph (a)(1) of this section may be accomplished in a flight simulator or flight training device that is—\n");
204 messages.append("(i) Approved by the Administrator for landings; and\n");
205 messages.append("(ii) Used in accordance with an approved course conducted by a training center certificated under part 142 of this chapter.\n \n");
206 }
207 return false;
208 }
209
210 private boolean isOver90Days(Date d1) {
211 Date currentDate = new Date();
212 long diff = currentDate.getTime() - d1.getTime();
213 long minutes = diff / (1000 * 60);
214 return minutes > DAYS90;
215 }
216
217 private boolean isOver180Days(Date d1) {
218 Date currentDate = new Date();
219 long diff = currentDate.getTime() - d1.getTime();
220 long minutes = diff / (1000 * 60);
221 return minutes > DAYS180;
222 }
223
224 private boolean isOverUserDefinedDays(Date dl, int days) {
225 Date currentDate = new Date();
226 long diff = currentDate.getTime() - dl.getTime();
227 long minutes = diff / (1000 * 60);
228 long userDefinedTime = days * 1440;
229 return minutes > userDefinedTime;
230 }
231 }