/// <summary> /// Эта функция служит для переупорядочивания записей в том случае, когда чёрный экран всплывает по бездействию, /// т.к. запись "continue" может быть уже после того, как программа убедится в бездействии пользователя и зачтёт часть времени бездействия в минус от текущего времени. /// </summary> private static void correctTimeRecordsFromAutoBlack(TimeRecordsList result) { lock (result) for (int i = 1; i < result.Count; i++) // 0 - самый недавний элемент { if (result[i - 1].timeMark - result[i].timeMark < 0) { if (!result[i - 1].isOffAction) { throw new Exception("Фатальная ошибка в функции correctTimeRecordsFromAutoBlack. Сообщите разработчику [email protected]. " + result[i - 1].type + "/" + result[i].type + "//" + result[i - 1].timeMark + "/" + result[i].timeMark + "-" + i); } if (result[i].isOnAction) { result.RemoveAt(i); i--; currentStatus.modify(result[i]); } else { var o = result[i]; result.RemoveAt(i); result.Insert(i - 1, o); } } } }
private long calcLastRelaxTime(TimeRecordsList records, long minFullRelaxInterval, long maxRelaxTime) { long lastTime = DateTime.Now.Ticks; for (int i = 0; i < records.Count; i++) { if (records[i].isOffAction) { /*int k = getTimeRecordWithAction(records, true, i + 1); * if (k < 0) * return lastTime; * if (lastTime - records[k - 1].timeMark > minRelaxInterval) */ if (lastTime - records[i].timeMark > minRelaxInterval) { return(lastTime); } } else if (records[i].isOnAction) { lastTime = records[i].timeMark; } } return(records[records.Count - 1].timeMark); }
private static void TrimTimeRecords(TimeRecordsList result, long workInterval) { if (trimmedCount == result.Count) { return; } correctTimeRecordsFromAutoBlack(result); correctTimeRecordsFromBreakdown(result); trimmedCount = 0; if (result.Count <= 1) { return; } long lastMarkTime = 0; //if (result[0].isOffAction) lastMarkTime = DateTime.Now.Ticks; for (int i = 0; i < result.Count; i++) { long timeMark = result[i].timeMark; if (lastMarkTime - timeMark > workInterval) { result.RemoveRange(i, result.Count - i); break; } lastMarkTime = timeMark; } trimmedCount = result.Count; }
private void ParseTimeRecords(string[] t, TimeRecordsList result) { for (int i = t.Length - 1; i >= 0; i--) { var rec = new TimeRecord(t[i]); result.Add(rec); } }
double calcRelaxState(TimeRecordsList records, long relaxByHour, long maxRelaxTime) { double result = 1.0; long lastTime = 0; var relax = new TimeRecord.status(); for (int i = records.Count - 1; i >= -1; i--) { if (relax.modify(records[i]) || (i < 0 && lastTime != 0)) { if (relax.workOldState == TimeRecord.status.st.No) { if (lastTime == 0) { throw new Exception("В расчёте времени отдыха зафиксирована невозможная ситуация типа TimeRecord.status.st.No==TimeRecord.status.st.Unknown"); } long relaxTime = records[i].timeMark - lastTime; if (relaxTime < minRelaxInterval) { relaxTime = 0; } result += (double)relaxTime / (double)relaxByHour / 2.0; // в 0 за два часа if (result > 1.0) { result = 1.0; // нельзя отдохнуть более, чем на 100% } } else if (relax.workOldState == TimeRecord.status.st.Yes) { if (lastTime == 0) { throw new Exception("В расчёте времени отдыха зафиксирована невозможная ситуация типа TimeRecord.status.st.Yes==TimeRecord.status.st.Unknown"); } result -= (double)(records[i].timeMark - lastTime) / (double)(hour - relaxByHour) / 2.0; // на 1 за два часа (работы и отдыха в заданном режиме) } if (relax.work != TimeRecord.status.st.Unknown) { lastTime = records[i].timeMark; } else { lastTime = 0; } } } if (result > 1.0) { result = 1.0; // нельзя отдохнуть более, чем на 100% } return(result); }
private static void ShiftTimeRecords(TimeRecordsList result) { long timeShift = 0; for (int i = 0; i < result.Count; i++) { var rec = result[i]; rec.timeMark = rec.timeMark1 + timeShift; rec.shifted = timeShift; if (rec.type == TimeRecord.timeChanged) { timeShift += rec.timeMark1 - rec.timeMark2; } } }
private TimeRecordsList readAndParse() { string[] t = new String[0]; if (File.Exists(logFileName)) { t = File.ReadAllLines(logFileName); } var result = new TimeRecordsList(Math.Min(t.Length, 1024)); // Берём из настроек workInterval, т.к. этот метод запускается ещё до анализа и workInterval ещё не инициализирован long maxRelaxTime, relaxByHour, relaxEventInterval, RelaxTime, minShortWorkInterval; getTimes(out maxRelaxTime, out workInterval, out relaxByHour, out relaxEventInterval, out RelaxTime, out minShortWorkInterval); ParseTimeRecords(t, result); ShiftAndTrim(result); return(result); }
int getTimeRecordWithAction(TimeRecordsList records, bool onAction, int startI) { for (int i = startI; i < records.Count; i++) { if (onAction) { if (records[i].isOnAction) { return(i); } } else if (records[i].isOffAction) { return(i); } } return(-1); }
/// <summary> /// В случае, если продолжительное время не было сообщений от программы, вставить сообщение, что программа была завершена /// </summary> private static void correctTimeRecordsFromBreakdown(TimeRecordsList result) { var lastTime = DateTime.Now.Ticks; for (int i = 0; i < result.Count; i++) // 0 - самый недавний элемент { if (!result[i].isOffAction && lastTime - result[i].timeMark > continueInterval + 6 * second) { var time = result[i].timeMark + (continueInterval >> 1); if (time > lastTime) { throw new Exception("Фатальная ошибка в функции correctTimeRecordsFromBreakdown. Сообщите разработчику [email protected]"); } var tr = new TimeRecord(time, result[i].shifted); result.Insert(i, tr); } lastTime = result[i].timeMark; } }
private void ParseAndTrimLog() { if (timeRecords == null || trimmedCount < 0) { timeRecords = readAndParse(); for (int i = timeRecords.Count - 1; i >= 0; i--) { currentStatus.modify(timeRecords[i]); } if (timeRecords.Count == 0) { File.WriteAllText(logFileName, ""); } else if (timeRecords.Count == 1 && timeRecords[0].type == TimeRecord.started) { File.WriteAllText(logFileName, ""); logServiceTime(timeRecords[0].type, timeRecords[0].timeMark); } } }
private static void ShiftAndTrim(TimeRecordsList result) { ShiftTimeRecords(result); TrimTimeRecords(result, workInterval); }
private long checkToRelax(TimeRecordsList records, out long relax, out long work, out long toRelax, out int relaxSimpleStatus, out double relaxState) { long maxRelaxTime, relaxByHour, relaxEventInterval, RelaxTime, minShortWorkInterval; getTimes(out maxRelaxTime, out workInterval, out relaxByHour, out relaxEventInterval, out RelaxTime, out minShortWorkInterval); relax = calcRelaxTime(timeRecords, workInterval, maxRelaxTime); work = calcWorkTime(timeRecords, workInterval, maxRelaxTime); relaxState = calcRelaxState(timeRecords, relaxByHour, maxRelaxTime); long lastr = calcLastRelaxTime(timeRecords, workInterval, maxRelaxTime); var oneRelax = (double)relaxEventInterval / (double)hour / 2.0; // что даёт одна релаксация (считая полный цикл за два часа) var WallRelax = 1.0 - oneRelax; toRelax = (long)(2 * relaxByHour * (1.0 - relaxState)); // отдых от relaxState=0 занимает два часа общего времени (включая рабочее) relaxSimpleStatus = 0; long now = DateTime.Now.Ticks; DbgLog.dbg.dataToLog("checkToRelax", "relax data", new { toRelax = toRelax, RelaxTime = RelaxTime, relaxEventInterval = relaxEventInterval, work = work, relax = relax, oneRelax = oneRelax, WallRelax = WallRelax, relaxState = relaxState, lastr = lastr, minShortWorkInterval = minShortWorkInterval, now = now, maxRelaxTime = maxRelaxTime, minFullRelaxInterval = workInterval, relaxByHour = relaxByHour }); if (toRelax < 0 || RelaxTime < 0) { Program.ToLogFile("toRelax < 0 || RelaxTime < 0"); throw new Exception("Программа произвела неверный расчёт времени отдыха. Сообщите об этом разработчику!"); } if (toRelax > relaxByHour * 2) { relaxSimpleStatus = 1; } if (toRelax > relaxByHour * 3) { relaxSimpleStatus = 2; } var trlt = Math.Max(RelaxTime, toRelax) / 10000 + 1.0; var s = ((double)(RelaxTime / 10000) / trlt); if ( work < (relaxEventInterval - RelaxTime) // || lastr + (relaxEventInterval - RelaxTime) * s > now ) { return(0); } if (lastr + minShortWorkInterval * s > now) { return(0); } // rc/wc = (r + x)/w => w*rc/wc - r = x if (toRelax >= RelaxTime) { return(toRelax); } return(0); }