"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 platform_browser_1 = require("@angular/platform-browser");
const store_1 = require("@ngrx/store");
const Observable_1 = require("rxjs/Observable");
require("rxjs/add/observable/combineLatest");
require("rxjs/add/observable/fromEvent");
require("rxjs/add/operator/debounceTime");
require("rxjs/add/operator/delay");
require("rxjs/add/operator/distinctUntilChanged");
require("rxjs/add/operator/do");
require("rxjs/add/operator/map");
require("rxjs/add/operator/startWith");
require("../util/takeUntilDestroyed");
const project_1 = require("../redux/project");
const control_state_sync_service_1 = require("./control-state-sync.service");
const devices_1 = require("./devices");
/**
 * One random background is chosen eac
 */
const backgrounds = [
    'https://mixer.com/_latest/assets/img/backgrounds/generic-001.jpg',
    'https://mixer.com/_latest/assets/img/backgrounds/generic-002.jpg',
    'https://mixer.com/_latest/assets/img/backgrounds/generic-art-001.jpg',
    'https://mixer.com/_latest/assets/img/backgrounds/generic-coding-001.jpg',
];
/**
 * The FrameComponent hosts the frame containing the developer's controls.
 */
let FrameComponent = FrameComponent_1 = class FrameComponent {
    constructor(el, cdRef, project, store, sanitizer, controls) {
        this.el = el;
        this.cdRef = cdRef;
        this.project = project;
        this.store = store;
        this.sanitizer = sanitizer;
        this.controls = controls;
        /**
         * Background to display behind the frame.
         */
        this.background = this.sanitizer.bypassSecurityTrustStyle(`url('${backgrounds[Math.floor(backgrounds.length * Math.random())]}')`);
        /**
         * Device "frame" to display.
         */
        this.state = this.store.select('frame');
        /**
         * The currently selected device.
         */
        this.device = this.state.map(s => devices_1.devices[s.chosenDevice]);
        /**
         * Whether the controls should be connected to production.
         */
        this.isConnectedToRemote = this.store.map(s => s.connect.state === 1 /* Active */);
        /**
         * Whether the frame should be masked
         */
        this.isMasked = this.store.map(s => s.frame.isMasked);
        /**
         * Fired when something that happens chat changes the layout.
         */
        this.layoutResized = Observable_1.Observable.combineLatest(this.state.distinctUntilChanged((a, b) => a.chosenDevice === b.chosenDevice && a.orientation === b.orientation), this.store
            .select('code')
            .map(c => c.width)
            .distinctUntilChanged(), this.store
            .select('code')
            .map(c => c.state)
            .distinctUntilChanged(), Observable_1.Observable.fromEvent(window, 'resize')
            .debounceTime(5)
            .startWith(null), state => state);
        /**
         * Observable for the computed video position, fitted with a 16:9 ratio into
         * the bounds provided by the controls.
         */
        this.videoFilledSize = this.controls
            .getVideoSize()
            .combineLatest(this.layoutResized.delay(1))
            .map(([rect]) => this.getFittedVideo(rect))
            .filter(rect => !!rect)
            .publishReplay(1)
            .refCount();
    }
    ngAfterContentInit() {
        this.layoutResized
            .delay(1)
            .takeUntilDestroyed(this)
            .subscribe(state => {
            this.refreshBlocks(state);
        });
        this.videoFilledSize.takeUntilDestroyed(this).subscribe(rect => {
            this.controls.updateFittedVideoSize(rect);
        });
    }
    ngOnDestroy() {
        /* noop */
    }
    refreshBlocks(state) {
        const el = this.el.nativeElement.getBoundingClientRect();
        const device = devices_1.devices[state.chosenDevice];
        const blocks = device.display(el.width - 2 * FrameComponent_1.padding, el.height - 2 * FrameComponent_1.padding, state.orientation);
        if (!state.dimensionsManuallySet) {
            this.project.setDeviceDisplayedSize(Math.round(blocks.reduce((max, b) => Math.max(max, b.width + b.x), 0)), Math.round(blocks.reduce((max, b) => Math.max(max, b.height + b.y), 0)));
        }
        const controlBlock = blocks.find(b => b.type === 'controls');
        if (!controlBlock) {
            throw new Error('Could not find control block for current layout');
        }
        this.stubBlocks = blocks.filter(b => b.type !== 'controls');
        this.controlsBlock = controlBlock;
        this.cdRef.markForCheck();
        this.cdRef.detectChanges();
    }
    getFittedVideo(rect) {
        const videoBlock = this.el.nativeElement.querySelector('.frame-backdrop');
        if (!videoBlock) {
            return null;
        }
        const backdropRect = videoBlock.getBoundingClientRect();
        const out = Object.assign({ left: 0, right: 0, bottom: 0, top: 0, width: 0, height: 0 }, rect);
        // Normalize any bottom/right bounds to width/height to make things easier.
        if (!out.width) {
            out.width = backdropRect.width - out.left - out.right;
            delete out.right;
        }
        if (!rect.height) {
            out.height = backdropRect.height - out.top - out.bottom;
            delete out.bottom;
        }
        if (out.width / out.height > FrameComponent_1.videoRatio) {
            const newWidth = out.height * FrameComponent_1.videoRatio;
            out.left = out.left + (out.width - newWidth) / 2;
            out.width = newWidth;
        }
        else {
            const newHeight = out.width / FrameComponent_1.videoRatio;
            out.top = out.top + (out.height - newHeight) / 2;
            out.height = newHeight;
        }
        out.right = backdropRect.width - backdropRect.left;
        out.bottom = backdropRect.height - backdropRect.top;
        return out;
    }
};
/**
 * Padding in all directions within the frame.
 */
FrameComponent.padding = 32;
/**
 * Aspect ratio of the fitted, virtual video.
 */
FrameComponent.videoRatio = 16 / 9;
FrameComponent = FrameComponent_1 = __decorate([
    core_1.Component({
        selector: 'editor-frame',
        templateUrl: './frame.component.html',
        styleUrls: ['./frame.component.scss'],
        changeDetection: core_1.ChangeDetectionStrategy.OnPush,
        providers: [control_state_sync_service_1.ControlStateSyncService],
    }),
    __metadata("design:paramtypes", [core_1.ElementRef,
        core_1.ChangeDetectorRef,
        project_1.ProjectService,
        store_1.Store,
        platform_browser_1.DomSanitizer,
        control_state_sync_service_1.ControlStateSyncService])
], FrameComponent);
exports.FrameComponent = FrameComponent;
var FrameComponent_1;
