diff --git a/robbery.js b/robbery.js index 4a8309d..99f77dd 100644 --- a/robbery.js +++ b/robbery.js @@ -4,7 +4,7 @@ * Сделано задание на звездочку * Реализовано оба метода и tryLater */ -exports.isStar = true; +exports.isStar = false; /** * @param {Object} schedule – Расписание Банды @@ -14,8 +14,147 @@ exports.isStar = true; * @param {String} workingHours.to – Время закрытия, например, "18:00+5" * @returns {Object} */ +var DAYS_FOR_ROBBERY = ['ПН', 'ВТ', 'СР']; +var MINUTES_IN_HOUR = 60; +var resArrayIsAlreadyCreated = false; +var resultIndex = 0; +var whenBusyFrom = []; +var whenBusyTo = []; +var whenGangIsCan = []; +var incorrectData = false; + exports.getAppropriateMoment = function (schedule, duration, workingHours) { - console.info(schedule, duration, workingHours); + var bankFrom = hoursToMinutes(workingHours.from); + var bankTo = hoursToMinutes(workingHours.to); + var result = []; + + + function isFreeToday(name, day) { + var isBusy = false; + for (var i = 0; i < schedule[name].length; i++) { + var robberyFrom = convertToTimezone(schedule[name][i].from, workingHours); + var robberyTo = convertToTimezone(schedule[name][i].to, workingHours); + if (robberyFrom.indexOf(day) !== -1 && robberyTo.indexOf(day) !== -1) { + isBusy = checkBusyAllBankHours(hoursToMinutes(robberyFrom), + hoursToMinutes(robberyTo)); + + checkIntervalAndPush(hoursToMinutes(robberyFrom), hoursToMinutes(robberyTo)); + } else if (robberyFrom.indexOf(day) !== -1) { + isBusy = checkBusyAllBankHours( + hoursToMinutes(robberyFrom), + hoursToMinutes('23:59+5') + ); + + checkIntervalAndPush(hoursToMinutes(robberyFrom), bankTo); + } else if (robberyTo.indexOf(day) !== -1) { + isBusy = checkBusyAllBankHours(hoursToMinutes('00:00+5'), + hoursToMinutes(robberyTo)); + + checkIntervalAndPush(bankFrom, hoursToMinutes(robberyTo)); + } + if (isBusy) { + return false; + } + } + + return true; + } + + function checkIntervalAndPush(from, to) { + if (from <= bankTo && from >= bankFrom && to <= bankTo) { + whenBusyFrom.push(from); + whenBusyTo.push(to); + } + } + + function checkBusyAllBankHours(robFrom, robTo) { + if (robFrom <= bankFrom && robTo >= bankTo) { + return true; + } + + return false; + } + + function searchMiddleCases(i) { + var maxTo; + if (whenBusyTo[i] < whenBusyFrom[i + 1]) { + whenGangIsCan.push( + { fromInMins: whenBusyTo[i], + toInMins: whenBusyFrom[i + 1] }); + } else { + var nextTo; + while (whenBusyTo[i] > whenBusyFrom[i + 1]) { + maxTo = whenBusyTo[i + 1]; + i++; + } + if (whenBusyTo[i + 1] !== undefined) { + nextTo = whenBusyTo[i + 1]; + whenGangIsCan.push({ fromInMins: maxTo, toInMins: nextTo }); + } + + } + } + + function findWhenGangIsFree() { + whenBusyFrom.sort(function (a, b) { + return a - b; + }); + whenBusyTo.sort(function (a, b) { + return a - b; + }); + + if (whenBusyFrom[0] > bankFrom) { + whenGangIsCan.push({ fromInMins: bankFrom, toInMins: whenBusyFrom[0] }); + } + for (var i = 0; i < whenBusyFrom.length; i++) { + searchMiddleCases(i); + } + if (whenBusyTo[whenBusyTo.length - 1] < bankTo) { + whenGangIsCan.push({ + fromInMins: whenBusyTo[whenBusyTo.length - 1], + toInMins: bankTo }); + } + } + + function uniqueVal(value, index, self) { + return self.indexOf(value) === index && + self.indexOf(value) === index; + } + + function willRobThisDay(index) { + for (var i = 0; i < whenGangIsCan.length; i++) { + if ((whenGangIsCan[i].toInMins - whenGangIsCan[i].fromInMins) >= duration) { + result.push({ + resFrom: whenGangIsCan[i].fromInMins, + resTo: whenGangIsCan[i].toInMins, + day: DAYS_FOR_ROBBERY[index] + }); + } + } + + result.filter(uniqueVal); + + whenBusyFrom = []; + whenBusyTo = []; + whenGangIsCan = []; + + if (result.length !== 0) { + return true; + } + + return false; + } + + function gangIsFree(i) { + var allIsFree = true; + for (var robber in schedule) { + if ({}.hasOwnProperty.call(schedule, robber)) { + allIsFree = gangIsFree && isFreeToday(robber, DAYS_FOR_ROBBERY[i]); + } + } + + return allIsFree; + } return { @@ -24,7 +163,25 @@ exports.getAppropriateMoment = function (schedule, duration, workingHours) { * @returns {Boolean} */ exists: function () { - return false; + var willRob = false; + var isFree; + for (var i = 0; i < DAYS_FOR_ROBBERY.length; i++) { + isFree = gangIsFree(i); + if (isFree) { + findWhenGangIsFree(); + } + if (willRobThisDay(i, resArrayIsAlreadyCreated)) { + willRob = true; + } + } + if (willRob) { + resArrayIsAlreadyCreated = true; + } + if (incorrectData) { + return false; + } + + return willRob; }, /** @@ -35,7 +192,15 @@ exports.getAppropriateMoment = function (schedule, duration, workingHours) { * @returns {String} */ format: function (template) { - return template; + if (!this.exists()) { + return ''; + } + var timeArray = minutesToHours(result[resultIndex].resFrom); + + return template.replace('%HH', timeArray[0]) + .replace('%MM', timeArray[1]) + .replace('%DD', result[resultIndex].day); + }, /** @@ -44,7 +209,60 @@ exports.getAppropriateMoment = function (schedule, duration, workingHours) { * @returns {Boolean} */ tryLater: function () { + return false; } }; }; + +function hoursToMinutes(str) { + var timeArray = str.match(/\d{1,2}/g); + if (str.indexOf('+') === -1) { + incorrectData = true; + } + + return timeArray[0] * MINUTES_IN_HOUR + Number(timeArray[1]); +} + +function minutesToHours(inputMinutes) { + var hours = parseInt(inputMinutes / MINUTES_IN_HOUR); + var minutes = inputMinutes % MINUTES_IN_HOUR; + if (minutes < 10) { + minutes += '0'; + } + if (hours < 10) { + hours += '0'; + } + + return [hours, minutes]; +} + +function checkCorrectDay(day) { + if (day.indexOf(DAYS_FOR_ROBBERY[0]) === -1 && day.indexOf(DAYS_FOR_ROBBERY[1]) === -1 && + day.indexOf(DAYS_FOR_ROBBERY[2]) === -1) { + incorrectData = true; + } +} + +function convertToTimezone(str, workingHours) { + var bankTimezone = workingHours.from.search(/\+\d{1,2}/); + var timeArray = str.match(/\d{1,2}/g); + var dayOfWeek = str.match(/[А-Я]{2}/g); + checkCorrectDay(dayOfWeek[0]); + if (str.indexOf('+') === -1 || timeArray[2] > 23) { + incorrectData = true; + } + var deltaTimezone = Math.abs(parseInt(bankTimezone - timeArray[2])); + var newHours; + if (timeArray[2] < bankTimezone) { + newHours = Number(timeArray[0]) + deltaTimezone; + + return dayOfWeek[0] + ' ' + newHours + ':' + timeArray[1] + '+' + bankTimezone; + } else if (timeArray[2] > bankTimezone) { + newHours = Number(timeArray[0]) - deltaTimezone; + + return dayOfWeek[0] + ' ' + newHours + ':' + timeArray[1] + '+' + bankTimezone; + } + + return str; +}