"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 store_1 = require("@ngrx/store");
const Code = require("./code");
const Connect = require("./connect");
const Console = require("./console");
const Frame = require("./frame");
const Sync = require("./sync");
const storedKeys = ['frame', 'code', 'sync', 'console'];
var MetaActions;
(function (MetaActions) {
    MetaActions["ReplaceState"] = "META_REPLACE_STATE";
})(MetaActions = exports.MetaActions || (exports.MetaActions = {}));
/**
 * ProjectService provides notation on the IProject state.
 */
let ProjectService = class ProjectService {
    constructor(store) {
        this.store = store;
    }
    /**
     * Applies a direct partial update to the state.
     */
    replaceState(data, omitSave = false) {
        this.store.dispatch({ type: MetaActions.ReplaceState, data, omitSave });
    }
    // Frame actions ------------------------------------------------------------
    /**
     * Change whether the controls are ready.
     */
    setControlsReady(isReady) {
        this.store.dispatch({ type: "FRAME_SET_READY" /* SetReady */, isReady });
    }
    /**
     * Change the selected device.
     */
    chooseDevice(deviceIndex) {
        this.store.dispatch({ type: "FRAME_SELECT" /* Select */, index: deviceIndex });
    }
    /**
     * Rotate the device.
     */
    rotateDevice() {
        this.store.dispatch({ type: "FRAME_ROTATE" /* Rotate */ });
    }
    /**
     * Manually override the device dimensions, called by the user.
     */
    resizeDevice(width, height) {
        this.store.dispatch({ type: "FRAME_SET_DIMENSIONS" /* SetDimensions */, width, height, isManual: true });
    }
    /**
     * Sets the displayed dimensions of the device. Called automatically when
     * the device is changed or the window is resized.
     */
    setDeviceDisplayedSize(width, height) {
        this.store.dispatch({ type: "FRAME_SET_DIMENSIONS" /* SetDimensions */, width, height, isManual: false });
    }
    /**
     * Sets whether the frame is masked (covered by a transparent overlay).
     * Useful when dragging thing.
     */
    setFrameMasked(isMasked) {
        this.store.dispatch({ type: "FRAME_MASK" /* Mask */, isMasked });
    }
    // Code actions -------------------------------------------------------------
    /**
     * Updates the controls tab/state.
     */
    setCodeState(state) {
        this.store.dispatch({ type: "CODE_SET_STATE" /* SetState */, state });
    }
    /**
     * Updates the width of the code block, in pixels.
     */
    setCodeWidth(width) {
        this.store.dispatch({ type: "CODE_RESIZE" /* Resize */, width });
    }
    // Connect actions ---------------------------------------------------------
    /**
     * Updates the active controls state.
     */
    connectControls(data) {
        this.store.dispatch({ type: "CONNECT_CONNECT" /* Connect */, data });
    }
    /**
     * Disconnects the active interactive controls.
     */
    disconnectControls() {
        this.store.dispatch({ type: "CONNECT_DISCONNECT" /* Disconnect */ });
    }
    /**
     * Updates the connected state.
     */
    setControlsState(controlsState) {
        this.store.dispatch({ type: "CONNECT_UPDATE_STATE" /* UpdateState */, controlsState });
    }
    /**
     * Updates the channel the controls will connect to..
     */
    setConnectionChannel(channelID) {
        this.store.dispatch({ type: "CONNECT_SET_CHANNEL" /* SetChannel */, channelID });
    }
    // Sync actions -------------------------------------------------------------
    syncUnlink() {
        this.store.dispatch({ type: "SYNC_UNLINK" /* Unlink */ });
    }
    syncLink(interactiveVersion) {
        this.store.dispatch({ type: "SYNC_LINK" /* Link */, version: interactiveVersion });
    }
    syncDontConfirmSchema() {
        this.store.dispatch({ type: "SYNC_DONT_CONFIRM_SCHEMA" /* DontConfirmSchema */ });
    }
    // Console actions ----------------------------------------------------------
    setConsoleFilter(filter) {
        this.store.dispatch({ type: "CONSOLE_FILTER" /* SetFilter */, filter });
    }
};
ProjectService = __decorate([
    core_1.Injectable(),
    __metadata("design:paramtypes", [store_1.Store])
], ProjectService);
exports.ProjectService = ProjectService;
/**
 * Initial state of the project.
 */
const initialState = {
    frame: Frame.initialState,
    code: Code.initialState,
    connect: Connect.initialState,
    sync: Sync.initialState,
    console: Console.initialState,
};
/**
 * localStorageReduxer is a metareducer that saves changes to localstorage.
 */
function setInitialState(reducer) {
    return (project, action) => reducer(project || initialState, action);
}
exports.setInitialState = setInitialState;
/**
 * localStorageReduxer is a metareducer that saves changes to localstorage.
 */
function replaceStateReducer(reducer) {
    return (project, action) => {
        const next = reducer(project, action);
        if (action.type === MetaActions.ReplaceState) {
            return Object.assign({}, next, action.data, { frame: Object.assign({}, next.frame, action.data.frame, { width: next.frame.width, height: next.frame.height }), code: Object.assign({}, next.code, action.data.code, { state: next.code.state }) });
        }
        return next;
    };
}
exports.replaceStateReducer = replaceStateReducer;
/**
 * ngrx store reducers.
 */
exports.reducers = {
    frame: Frame.reducer,
    code: Code.reducer,
    connect: Connect.reducer,
    sync: Sync.reducer,
    console: Console.reducer,
};
/**
 * ngrx metareducers
 */
exports.metaReducers = [setInitialState, replaceStateReducer];
/**
 * Returns the partial part of the project which should be saved.
 */
function getStoredData(project) {
    const plucked = {};
    storedKeys.forEach(key => {
        plucked[key] = Object.assign({}, project[key]);
    });
    return plucked;
}
exports.getStoredData = getStoredData;
