"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SpeedRunApp = exports.SpeedRunAppImpl = void 0;
const react_1 = __importDefault(require("react"));
const react_dom_1 = __importDefault(require("react-dom"));
const material_1 = require("@mui/material");
const styles_1 = require("@mui/styles");
const css_1 = require("@emotion/css");
const client_1 = require("../client");
const styles_2 = require("@mui/material/styles");
const theme = (0, styles_2.createTheme)({
    palette: {
        mode: 'dark',
    },
});
const duration_timer_1 = require("../components/duration_timer");
class SpeedRunAppImpl extends react_1.default.Component {
    constructor(props) {
        super(props);
        this.state = {
            width: "auto",
            height: "auto",
        };
        this.containerRef = react_1.default.createRef();
        this.rowMap = {};
        this.headerRowRefs = [];
        this.maxRows = 7;
        this.bottomRows = 3;
        this.s = {
            errorColor: (0, css_1.css) `
      color: ${this.props.theme.palette.error.light} !important;
    `,
            greenTextGradient: (0, css_1.css) `
      background: linear-gradient(180deg, rgba(128,255,162,1) 35%, rgba(0,163,44,1) 100%);
      -webkit-background-clip: text;
      -webkit-text-fill-color: transparent;
    `,
            blueTextGradient: (0, css_1.css) `
      background: linear-gradient(180deg, rgba(138, 210, 255,1) 35%, rgba(16, 132, 204,1) 100%);
      -webkit-background-clip: text;
      -webkit-text-fill-color: transparent;
    `,
            redTextGradient: (0, css_1.css) `
      background: linear-gradient(180deg, rgba(255, 128, 128,1) 35%, rgba(163, 0, 0,1) 100%);
      -webkit-background-clip: text;
      -webkit-text-fill-color: transparent;
    `,
            grayTextGradient: (0, css_1.css) `
      background: linear-gradient(180deg, rgba(191, 191, 191, 1) 35%, rgba(82, 82, 82, 1) 100%);
      -webkit-background-clip: text;
      -webkit-text-fill-color: transparent;
    `,
            splitActive: (0, css_1.css) `
      background-color: ${this.props.theme.palette.action.hover}
    `
        };
    }
    getUserDefinedDimension(num) {
        if (num.trim() === 'auto' || num.trim() === '') {
            return '100%';
        }
        let isNumber = true;
        for (let i = 0; i < num.length; ++i) {
            const c = num.charAt(i);
            if (!(c >= '0' && c <= '9')) {
                isNumber = false;
                break;
            }
        }
        return `${num}${isNumber ? 'px' : ''}`;
    }
    splitsUpdated(splitsData) {
        this.setState({
            width: this.getUserDefinedDimension(splitsData.pageSettings.width),
            height: this.getUserDefinedDimension(splitsData.pageSettings.height),
            splitsData,
        });
    }
    componentDidMount() {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                this.client = yield (0, client_1.connect)();
                this.client.on('splits-updated', this.splitsUpdated.bind(this));
                this.client.emit('notify-configuration-available', {
                    name: 'speed-run.html',
                    configuration: {
                        logo_image: {
                            type: 'file',
                            label: 'Logo Image',
                            helperText: 'Add a logo to display on your splits!',
                        },
                    },
                }, (err) => {
                    console.log('ERROR?', err);
                });
            }
            catch (err) {
                console.error(err);
                const error = err;
                this.setState({ errorMessage: error.message });
            }
        });
    }
    componentWillUnmount() {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.client) {
                this.client.disconnect();
                delete this.client;
            }
        });
    }
    renderSplitDuration(split, addMillis = 0) {
        if (!this.state.splitsData) {
            return null;
        }
        const { attemptDuration } = this.state.splitsData;
        if (!attemptDuration.splits[split.id]) {
            return null;
        }
        if (split.active) {
            return (react_1.default.createElement(duration_timer_1.DurationTimer, { milliseconds: attemptDuration.attempt, activeAt: attemptDuration.attemptActiveAt }));
        }
        return (react_1.default.createElement(duration_timer_1.DurationTimer, { milliseconds: attemptDuration.splits[split.id].milliseconds + addMillis, activeAt: attemptDuration.splits[split.id].activeAt }));
    }
    renderSplits() {
        if (!this.state.splitsData) {
            return;
        }
        const splitEndTime = {};
        const splitAddTime = {};
        const splitPbTotal = {};
        const { attemptDuration } = this.state.splitsData;
        let addMillis = 0;
        let idxActive = 0;
        let pbTotal = 0;
        for (let i = 0; i < this.state.splitsData.activeSplits.length; ++i) {
            const split = this.state.splitsData.activeSplits[i];
            pbTotal += split.pb_time || 0;
            splitPbTotal[split.id] = pbTotal;
            if (split.active) {
                idxActive = i;
                break;
            }
            const duration = attemptDuration.splits[split.id];
            if (duration) {
                splitAddTime[split.id] = addMillis;
                addMillis += duration.milliseconds;
                splitEndTime[split.id] = addMillis;
            }
        }
        const len = this.state.splitsData.activeSplits.length;
        const factor = this.maxRows - this.bottomRows;
        let offsetFrom = 0;
        let offsetTo = this.maxRows;
        if ((idxActive + 1) - factor > 0 && idxActive + 1 + this.bottomRows < len) {
            offsetFrom = idxActive - factor;
            offsetTo = idxActive + this.bottomRows;
        }
        else if (len > this.maxRows && idxActive + 1 + this.bottomRows >= len) {
            offsetFrom = len - this.maxRows;
            offsetTo = len;
        }
        return this.state.splitsData.activeSplits.slice(offsetFrom, offsetTo).map((split) => {
            return (react_1.default.createElement(react_1.default.Fragment, { key: `split_row_fragment_${split.id}` },
                react_1.default.createElement(material_1.Box, { className: (0, css_1.cx)({ [this.s.splitActive]: split.active }), sx: {
                        pr: 1,
                        pl: 1,
                        fontFamily: "'Fira Sans'",
                        whiteSpace: 'nowrap',
                        textOverflow: 'ellipsis',
                        overflow: 'hidden',
                    } }, split.name),
                react_1.default.createElement(material_1.Box, { className: (0, css_1.cx)({
                        [this.s.splitActive]: split.active,
                    }) },
                    react_1.default.createElement(material_1.Box, { className: (0, css_1.cx)({
                            [this.s.blueTextGradient]: split.active,
                            [this.s.redTextGradient]: !split.active && (splitEndTime[split.id] - splitPbTotal[split.id] > 0),
                            [this.s.greenTextGradient]: !split.active && (splitEndTime[split.id] - splitPbTotal[split.id] < 0),
                        }), sx: {
                            textAlign: 'right',
                            pr: 1,
                            fontFamily: "timer",
                            whiteSpace: 'nowrap',
                        } }, this.renderSplitDuration(split, splitAddTime[split.id] || 0)))));
        });
    }
    getTimerColor() {
        if (!this.state.splitsData) {
            return this.s.grayTextGradient;
        }
        const { activeRoute, attemptDuration } = this.state.splitsData;
        if (!attemptDuration.attemptActiveAt) {
            if ((activeRoute.pb_time || 0) - attemptDuration.attempt < 0) {
                return this.s.redTextGradient;
            }
            return this.s.grayTextGradient;
        }
        return this.s.blueTextGradient;
    }
    renderTime() {
        if (!this.state.splitsData) {
            return null;
        }
        const { attemptDuration } = this.state.splitsData;
        return (react_1.default.createElement(duration_timer_1.DurationTimer, { type: "large", milliseconds: attemptDuration.attempt, activeAt: attemptDuration.attemptActiveAt }));
    }
    renderPreviousSegment() {
        if (!this.state.splitsData) {
            return null;
        }
        if (!this.state.splitsData.attemptDuration) {
            return null;
        }
        const splits = this.state.splitsData.activeSplits;
        const attemptDuration = this.state.splitsData.attemptDuration;
        let attemptTime = 0;
        let pbTime = 0;
        let result = 0;
        for (let i = 0; i < splits.length; ++i) {
            const split = splits[i];
            const timePoint = attemptDuration.splits[split.id];
            if (split.active) {
                const lastSplit = splits[i - 1];
                if (!lastSplit) {
                    break;
                }
                result = attemptTime - pbTime;
                break;
            }
            attemptTime += timePoint ? timePoint.milliseconds : 0;
            pbTime += split.pb_time || 0;
        }
        return (react_1.default.createElement(material_1.Box, { sx: { display: 'flex', flexDirection: 'row' } },
            react_1.default.createElement(material_1.Typography, { variant: "subtitle1", sx: {
                    fontFamily: "'Fira Sans'",
                    padding: 1,
                } }, "Previous Segment:\u00A0"),
            react_1.default.createElement(material_1.Typography, { variant: "subtitle1", className: (0, css_1.cx)({
                    [this.s.redTextGradient]: result >= 0,
                    [this.s.greenTextGradient]: result < 0,
                }), sx: {
                    fontFamily: 'timer',
                    padding: 1,
                    pl: 0,
                } },
                react_1.default.createElement(duration_timer_1.DurationTimer, { activeAt: 0, milliseconds: result, showSign: true }))));
        return null;
    }
    renderPersonalBest() {
        if (!this.state.splitsData) {
            return null;
        }
        const { activeRoute } = this.state.splitsData;
        return (react_1.default.createElement(material_1.Box, { sx: { display: 'flex', flexDirection: 'row' } },
            react_1.default.createElement(material_1.Typography, { variant: "subtitle1", sx: {
                    fontFamily: "'Fira Sans'",
                    padding: 1,
                } }, "Personal Best:\u00A0"),
            react_1.default.createElement(material_1.Typography, { variant: "subtitle1", className: this.s.blueTextGradient, sx: {
                    fontFamily: 'timer',
                    padding: 1,
                    pl: 0,
                } },
                react_1.default.createElement(duration_timer_1.DurationTimer, { activeAt: 0, milliseconds: activeRoute.pb_time || 0 }))));
    }
    renderLogo() {
        if (!this.state.splitsData) {
            return null;
        }
        let logoImage = '0';
        if (this.state.splitsData.pageSettings.viewerSettings['speed-run.html']) {
            const viewerSettings = this.state.splitsData.pageSettings.viewerSettings['speed-run.html'];
            if (viewerSettings.logo_image &&
                typeof viewerSettings.logo_image === 'string') {
                logoImage = `/api/configured-resource?absolute_path=${viewerSettings.logo_image}`;
            }
            else {
                return null;
            }
        }
        return (react_1.default.createElement("img", { className: (0, css_1.css) `
          max-width: 58px;
          max-height: 58px;
          position: absolute;
          left: 8px;
          top: 0;
        `, src: logoImage }));
    }
    render() {
        if (!this.state.splitsData) {
            return null;
        }
        const { css } = this.state.splitsData.pageSettings;
        return (react_1.default.createElement(material_1.Paper, null,
            react_1.default.createElement("style", { dangerouslySetInnerHTML: { __html: css } }),
            react_1.default.createElement(material_1.Box, { sx: {
                    display: 'grid',
                    gridTemplateColumns: '1fr auto',
                    gridAutoRows: 'min-content',
                    width: this.state.width,
                    height: this.state.height,
                } }, this.renderSplits()),
            react_1.default.createElement(material_1.Box, { sx: { textAlign: 'right', pr: 1, position: 'relative' }, className: this.getTimerColor() },
                this.renderLogo(),
                this.renderTime()),
            react_1.default.createElement(material_1.Box, null, this.renderPreviousSegment()),
            react_1.default.createElement(material_1.Box, null, this.renderPersonalBest())));
    }
}
exports.SpeedRunAppImpl = SpeedRunAppImpl;
exports.SpeedRunApp = (0, styles_1.withTheme)(SpeedRunAppImpl);
react_dom_1.default.render(react_1.default.createElement(material_1.ThemeProvider, { theme: theme },
    react_1.default.createElement(material_1.CssBaseline, null),
    react_1.default.createElement(exports.SpeedRunApp, null)), document.querySelector('#root'));
//# sourceMappingURL=speed-run.js.map