"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@angular/core");
const material_1 = require("@angular/material");
const store_1 = require("@ngrx/store");
const json5 = require("json5");
const lodash_1 = require("lodash");
const control_state_sync_service_1 = require("./control-state-sync.service");
require("rxjs/add/operator/combineLatest");
require("rxjs/add/operator/distinctUntilChanged");
require("rxjs/add/operator/filter");
require("rxjs/add/operator/map");
require("rxjs/add/operator/mapTo");
require("rxjs/add/operator/startWith");
require("rxjs/add/operator/take");
require("../util/takeUntilDestroyed");
const participant_1 = require("@mcph/miix-std/dist/participant");
const console_service_1 = require("../console/console.service");
const project_1 = require("../redux/project");
const ds_1 = require("../util/ds");
/**
 * The RemoteControlsComponent hosts the frame containing remote Interactive
 * controls.
 */
let RemoteControlsComponent = class RemoteControlsComponent {
    constructor(store, snackRef, project, controls, console) {
        this.store = store;
        this.snackRef = snackRef;
        this.project = project;
        this.controls = controls;
        this.console = console;
    }
    ngAfterContentInit() {
        this.store
            .select(state => state.connect.join)
            .filter(ds_1.exists)
            .takeUntilDestroyed(this)
            .distinctUntilChanged((a, b) => a.address === b.address)
            .combineLatest(this.controls.getRefresh().startWith(undefined))
            .subscribe(([join]) => {
            this.startConnect(join);
        });
    }
    ngOnDestroy() {
        if (this.participant) {
            this.participant.destroy();
            this.participant = undefined;
        }
    }
    onExit(ev) {
        if (ev.keyCode === 27) {
            // escape
            this.project.disconnectControls();
        }
    }
    /**
     * startConnect is called when we get interactive join data from the state.
     */
    startConnect(join) {
        this.store
            .map(state => state.code.participant)
            .take(1)
            .map(participant => {
            const xAuthUser = { ID: 1, Username: 'tester' };
            try {
                const parsed = json5.parse(participant.join('\n'));
                xAuthUser.ID = parsed.userID;
                xAuthUser.Username = parsed.username;
            }
            catch (_e) {
                // ignored. We try to parse it to be nice but no biggie if we can't
            }
            return xAuthUser;
        })
            .combineLatest(this.controls.getSettings())
            .takeUntilDestroyed(this)
            .subscribe(([xAuthUser, settings]) => {
            if (this.participant) {
                this.participant.destroy();
            }
            const iframe = this.iframe.nativeElement;
            this.participant = new participant_1.Participant(iframe, settings)
                .on('loaded', () => {
                this.afterConnect();
            })
                .on('close', close => {
                this.onClose(close);
            })
                .on('transmit', lodash_1.throttle(() => {
                this.onTransmit();
            }, 50))
                .on('moveVideo', size => {
                this.controls.setVideoSize(size);
            })
                .on('unload', () => {
                this.controls.requestRefresh();
            })
                .on('log', data => {
                this.console.addLog(data);
            })
                .connect({
                contentAddress: '/?',
                socketAddress: join.address,
                ugcAddress: join.ugcAddress,
                xAuthUser,
                key: join.key,
            });
            this.participant.runOnRpc(rpc => {
                this.console.bindToRPC(rpc);
            });
        });
    }
    /**
     * Called when the participant socket closes, for any reason.
     */
    onClose(close) {
        if (close.expected) {
            // webpack reloaded the controls
            return;
        }
        this.snackRef.open(`The interactive connection was closed with code ${close.code}${close.message ? `: ${close.message}` : ''}`, undefined, { duration: 8000 });
        this.project.disconnectControls();
    }
    /**
     * Called after the pariticipant socket opens.
     */
    afterConnect() {
        this.snackRef.open('Connected! Press ESC to exit Interactive.', undefined, { duration: 2000 });
    }
    /**
     * Called whenever a packet is transmitted over the Interactive connection.
     */
    onTransmit() {
        if (!this.participant) {
            return; // could have closed before the throttle fired
        }
        this.participant
            .dumpState()
            .then(dump => {
            if (dump) {
                this.project.setControlsState(dump);
            }
        })
            .catch(() => undefined); // ignored
    }
};
__decorate([
    core_1.ViewChild('iframe'),
    __metadata("design:type", core_1.ElementRef)
], RemoteControlsComponent.prototype, "iframe", void 0);
__decorate([
    core_1.HostListener('window:keydown', ['$event']),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [KeyboardEvent]),
    __metadata("design:returntype", void 0)
], RemoteControlsComponent.prototype, "onExit", null);
RemoteControlsComponent = __decorate([
    core_1.Component({
        selector: 'editor-remote-controls',
        template: '<iframe frameborder="0" #iframe></iframe>',
        styleUrls: ['./controls.component.scss'],
        changeDetection: core_1.ChangeDetectionStrategy.OnPush,
    }),
    __metadata("design:paramtypes", [store_1.Store,
        material_1.MatSnackBar,
        project_1.ProjectService,
        control_state_sync_service_1.ControlStateSyncService,
        console_service_1.ConsoleService])
], RemoteControlsComponent);
exports.RemoteControlsComponent = RemoteControlsComponent;
