"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
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.Server = void 0;
const http = __importStar(require("http"));
const path_1 = __importDefault(require("path"));
const fs_1 = require("fs");
const cors_1 = __importDefault(require("cors"));
const express_1 = __importDefault(require("express"));
const socket_io_1 = __importDefault(require("socket.io"));
const axios_1 = __importDefault(require("axios"));
const POLL_TIMEOUT = 1000;
const rooms = {
    client: 'CLIENT',
    builder: 'BUILDER',
};
const messages = {
    builder: {
        registerBuilder: 'REGISTER-BUILDER',
        initClient: 'BUILDER: INIT-CLIENT',
        clientReady: 'BUILDER: CLIENT-READY',
        setServer: 'BUILDER: SET-SERVER',
        initBuilder: 'BUILDER: INIT-BUILDER',
        initApi: 'BUILDER: INIT-API',
        navigatePage: 'BUILDER: NAVIGATE-PAGE',
    },
    client: {
        registerClient: 'REGISTER-CLIENT',
        initClient: 'CLIENT: INIT-CLIENT',
        updateTree: 'CLIENT: UPDATE-TREE',
        setOpenApiEndpoint: 'CLIENT: SET-OPEN-API-ENDPOINT',
        reloadOpenApi: 'CLIENT: RELOAD-OPEN-API',
        reloadComponents: 'CLIENT: RELOAD-COMPONENTS',
        navigatePage: 'CLIENT: NAVIGATE-PAGE',
        selectElement: 'CLIENT: SELECT-ELEMENT',
        hoverElement: 'CLIENT: HOVER-ELEMENT',
    },
};
class Server {
    constructor({ REPO_PATH, SERVER_PORT, PREVIEW_CLIENT_PORT }) {
        this.clientReady = false;
        this.clientUrl = '/';
        this.start = () => {
            this.server.listen(this.port);
            this.pollClient();
        };
        this.reloadComponents = () => {
            if (this.io) {
                this.io.to(rooms.client).emit(messages.client.reloadComponents);
            }
        };
        this.reloadOpenApiSpec = () => {
            if (this.io) {
                this.io.to(rooms.client).emit(messages.client.reloadOpenApi);
            }
        };
        this.createApp = () => {
            const app = (0, express_1.default)();
            app.use((0, cors_1.default)());
            app.use(express_1.default.static(path_1.default.join(__dirname, 'client')));
            app.get('/', (req, res) => {
                res.sendFile(path_1.default.join(__dirname, 'client', 'index.html'));
            });
            return app;
        };
        this.createServer = (app) => {
            const server = http.createServer(app);
            return server;
        };
        this.createWebSocket = (server, REPO_PATH) => {
            const io = (0, socket_io_1.default)(server);
            io.origins('*:*');
            io.on('connection', (socket) => {
                const clientJsonPath = path_1.default.join(REPO_PATH, 'client.json');
                const clientJson = JSON.parse((0, fs_1.readFileSync)(clientJsonPath).toString());
                const packageJsonPath = path_1.default.join(REPO_PATH, 'package.json');
                const packageJson = JSON.parse((0, fs_1.readFileSync)(packageJsonPath).toString());
                const { openAPIEndpoint } = packageJson.uiStudio;
                socket.on(messages.builder.registerBuilder, () => {
                    this.registerBuilder(io, socket, clientJson, clientJsonPath);
                });
                socket.on(messages.client.registerClient, () => {
                    this.registerClient(io, socket, clientJson, openAPIEndpoint);
                });
            });
            return io;
        };
        this.registerBuilder = (io, socket, clientJson, clientJsonPath) => {
            socket.join(rooms.builder, () => {
                if (this.clientReady) {
                    io.to(socket.id).emit(messages.builder.clientReady);
                }
                io.to(socket.id).emit(messages.builder.initClient, clientJson);
                io.to(socket.id).emit(messages.builder.setServer, {
                    host: 'http://localhost',
                    clientPort: this.clientPort,
                });
                socket.on(messages.client.updateTree, (elements) => {
                    socket.to(rooms.client).emit(messages.client.updateTree, elements);
                    (0, fs_1.writeFileSync)(clientJsonPath, JSON.stringify(Object.assign({ version: clientJson.version }, elements), null, 4));
                });
                socket.on(messages.client.navigatePage, (r) => {
                    socket.to(rooms.client).emit(messages.client.navigatePage, r);
                });
                socket.on(messages.client.hoverElement, (r) => {
                    socket.to(rooms.client).emit(messages.client.hoverElement, r);
                });
                socket.on(messages.client.selectElement, (r) => {
                    socket.to(rooms.client).emit(messages.client.selectElement, r);
                });
            });
        };
        this.registerClient = (io, socket, clientJson, openAPIEndpoint) => {
            socket.join(rooms.client, () => {
                io.to(socket.id).emit(messages.client.initClient, clientJson);
                io.to(socket.id).emit(messages.client.setOpenApiEndpoint, openAPIEndpoint);
                socket.on(messages.builder.navigatePage, (r) => {
                    socket.to(rooms.builder).emit(messages.builder.navigatePage, r);
                });
                socket.on(messages.builder.initApi, (r) => {
                    socket.to(rooms.builder).emit(messages.builder.initApi, r);
                });
                socket.on(messages.builder.initBuilder, (r) => {
                    socket.to(rooms.builder).emit(messages.builder.initBuilder, r);
                });
            });
        };
        this.pollClient = () => {
            let timeout = null;
            const doPoll = () => __awaiter(this, void 0, void 0, function* () {
                try {
                    yield axios_1.default.get(`http://localhost:${this.clientPort}`);
                    this.clientReady = true;
                    this.io.to(rooms.builder).emit(messages.builder.clientReady);
                }
                catch (_a) {
                    timeout = setTimeout(doPoll, POLL_TIMEOUT);
                }
            });
            doPoll();
        };
        this.port = SERVER_PORT;
        this.clientPort = PREVIEW_CLIENT_PORT;
        const app = this.createApp();
        this.server = this.createServer(app);
        this.io = this.createWebSocket(this.server, REPO_PATH);
    }
}
exports.Server = Server;
//# sourceMappingURL=server.js.map