function Controller(apikey, url) { const apiKey = apikey; // Replace with your actual API key const apiUrl = url ?? 'https://localhost:7005/api/Score'; // Replace with your API endpoint URL console.log(apiKey); var self = this; //API poll variables var INTERVAL = 5000; var timeout = null; var currentReq = null; this.isConnected = ko.observable(false); //knockout variables this.gameState = ko.observable(""); this.half = ko.observable("Pre"); this.kickOffTime = ko.observable(new Date()); this.gameOn = ko.observable(false); this.eventList = ko.observableArray([]); this.homeTeamName = ko.observable("Uckfield RFC"); this.homeTeamColor = ko.observable("#ff0000"); this.homeTeamPoints = ko.observable(0); this.homeTeamLogo = ko.observable(""); this.awayTeamName = ko.observable("Away team"); this.awayTeamColor = ko.observable("#0000ff"); this.awayTeamPoints = ko.observable(0); this.awayTeamLogo = ko.observable(""); self.calculateRemainingTime = ko.computed(function () { if (self.half() === 'Pre') { return "---"; } if (self.gameState() === 'HalfTime') { return '40:00'; } if (self.gameState() === 'Finished') { return '80:00'; } return calc(); }); var isSecondHalfEvent = function (matchEvts) { return !!matchEvts.find(e => e.eventType === 'SecondHalfStart'); }; var calc = function (eventId = 0, minsOnly = false) { var matchEvts = self.eventList().filter(x => (x.category === 'Match' && x.id <= eventId) || x.id === eventId); var initialTime = self.kickOffTime(); //IF FIRST HALF, WORK OUT FOR IF SECOND HALF var halfStart = self.kickOffTime(); var offsetMins = 0; if ((eventId != 0 && isSecondHalfEvent(matchEvts)) || (eventId == 0 && self.half() === 'Second')) { var secondHalfEvent = self.eventList().find(x => x.eventType === 'SecondHalfStart'); if (!secondHalfEvent) { throw 'Invalid System Event State, Second Half without Second Half Event'; } halfStart = new Date(secondHalfEvent.timeStamp); initialTime = new Date(secondHalfEvent.timeStamp); offsetMins = 40; matchEvts = self.eventList().filter(x => x.id >= secondHalfEvent.id && (x.category === 'Match' || x.id === eventId)) } if (!matchEvts || matchEvts.length <= 1) { const diff = calcDiff(initialTime, new Date()); return `${String(diff.mins + offsetMins).padStart(2, "0")}:${String(diff.secs).padStart(2, "0")}` } var totalMins = offsetMins; var totalSecs = 0; matchEvts.forEach((evt, idx, src) => { if (eventId === 0 || evt.id <= eventId) { if (evt.eventType === 'TimeOff') { var t = calcDiff(initialTime, new Date(evt.timeStamp)); totalMins += t.mins; totalSecs += t.secs; } if (evt.eventType === 'TimeOn') { initialTime = new Date(evt.timeStamp); if (idx === (src.length - 1)) { var t = calcDiff(new Date(evt.timeStamp), new Date()); totalMins += t.mins; totalSecs += t.secs; } } if (eventId != 0 && eventId === evt.id) { var t = calcDiff(initialTime, new Date(evt.timeStamp)); totalMins += t.mins; totalSecs += t.secs; } } }); if (totalSecs >= 60) { totalMins += 1; totalSecs = totalSecs % 60; } if (minsOnly) { return `${String(totalMins).padStart(2, "0")}`; } return `${String(totalMins).padStart(2, "0")}:${String(totalSecs).padStart(2, "0")}`; } self.halfIndicator = ko.computed(function () { const gameState = self.gameState(); if (gameState === "WaitingForStart") { var dt = self.kickOffTime(); return `${String(dt.getHours()).padStart(2, "0")}:${String(dt.getMinutes()).padStart(2, "0")} KO`; } if (gameState === "FirstHalf") { return "1st Half"; } if (gameState === "SecondHalf") { return "2nd Half"; } if (gameState === "TimeOff") { return "Time Off"; } }); var fetchNewData = function () { currentReq = fetch(apiUrl, { method: 'GET', headers: { 'x-api-key': apiKey }, }); currentReq .then(processResponse) .then(processJson) .catch((error) => { self.isConnected(false); console.log(`Error Occurred retrieving data ${error}`); }) .then(scheduleNewDataFetch); }; var processResponse = function (response) { if (!response.ok) { self.isConnected(false); throw new Error('Network response was not ok'); } self.isConnected(true); if (response.status === 204) { self.gameOn(false); INTERVAL = 60000; return Promise.reject('no game'); } INTERVAL = 5000; return response.json(); }; var processJson = function (data) { self.eventList(data.eventHistory); self.gameOn(true); self.gameState(data.state); self.half(data.half); self.kickOffTime(new Date(data.startedAt)); self.homeTeamName(data.home.name); self.awayTeamName(data.away.name); self.homeTeamPoints(data.home.points); self.awayTeamPoints(data.away.points); }; self.deleteEvent = function (id) { console.log(`Call to delete event ${id}`); fetch(`${apiUrl}/event/${id}`, { method: 'DELETE', headers: { 'x-api-key': apiKey } }) .then(fetchNewData); }; var scheduleNewDataFetch = function () { if (timeout) { clearTimeout(timeout); } timeout = setTimeout(fetchNewData, INTERVAL); }; self.getMatchPendingMessage = function () { if (self.gameState() === "") { return "No Match has been configured at this time."; } return `The match has not started yet.. Kick off is scheduled for ${self.kickOffTime()}.`; }; self.addTeamEvent = function (team, evtType) { const eventData = { eventType: evtType, category: team, timeStamp: new Date().toISOString() }; fetch(`${apiUrl}/${selectedTeam}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey, }, body: JSON.stringify(eventData), }) .then(response => response.json()) .then(data => { console.log('Event data sent successfully:', data); }) .catch(error => { console.error('Error sending event data:', error); }); }; self.getEventMessage = function (evt) { var eventMins = self.getEventTime(evt); var eventMsg = parseEventType(evt.eventType); if (evt.category !== "Match") { if (evt.eventType === "YellowCard" || evt.eventType === "RedCard") { return `${eventMins} mins: ${eventMsg}`; } return `${eventMins} mins: ${eventMsg} Scored`; } return `${eventMsg}`; } self.getScoreAtEvent = function (evtId) { var evts = self.eventList(); var homeScore = 0; var awayScore = 0; evts.forEach(evt => { if (evt.id <= evtId) { if (evt.category === 'Home') { homeScore += evt.points; } else { awayScore += evt.points; } } }); return `${homeScore} - ${awayScore}`; } self.getEventTime = function (evt) { if (evt.category === 'Match') { return; } let t = calc(evt.id, true); return t; } var parseEventType = function (evtType) { switch (evtType) { case 'DropGoal': return 'Drop Goal'; case 'HalfTime': return 'Half Time'; case 'MatchStart': return 'Match Start'; case 'SecondHalfStart': return 'Second Half Start'; case 'TimeOff': return 'Time Off'; case 'TimeOn': return 'Time On'; case 'YellowCard': return 'Yellow Card'; case 'RedCard': return 'Red Card'; case 'MatchEnd': return 'Full Time'; default: return evtType; } } var calcDiff = function (startTimeStamp, endTimeStamp) { var diff = endTimeStamp - startTimeStamp; const minutes = Math.floor(diff / 60000); const seconds = Math.floor((diff % 60000) / 1000); return { mins: minutes, secs: seconds } } self.disconnectedMessage = function() { return `Unable to connect to server: ${apiUrl}`; }; fetchNewData(); // Starts the update loop } var paramsString = window.location.search.split("?")[1]; var paramValues = paramsString.split("&"); var params = {}; paramValues.forEach((param) => { var paramValue = param.split("="); params[paramValue[0]] = paramValue[1]; }); ko.applyBindings(new Controller(params.apiKey, params.url));