import { Inject, Injectable } from '@angular/core';
import { isBlank, isPresent } from '@jscrpt/common';
import { Subject } from 'rxjs';
import { METADATA_STATE_MANAGER } from '../../misc/tokens';
import * as i0 from "@angular/core";
/**
 * Maximum number of items in history
 */
const MAX_ITEMS = 200;
//TODO: maybe store state as string and compare with it to correctly display saved, discuss with vinci
/**
 * Service used for managing state of metadata
 */
export class MetadataHistoryManager {
    //######################### public properties #########################
    /**
     * Information whether user can undo
     */
    get canUndo() {
        if (isBlank(this.activeIndex)) {
            return false;
        }
        return this.activeIndex > 0;
    }
    /**
     * Information whether user can redo
     */
    get canRedo() {
        if (isBlank(this.activeIndex)) {
            return false;
        }
        return this.activeIndex + 1 < this.states.length;
    }
    /**
     * Indication whether current state is saved state
     */
    get saved() {
        return this.activeIndex === this.saveIndex;
    }
    /**
     * Occurs when user pops new state, using undo, or redo
     */
    get pop() {
        return this.popSubject.asObservable();
    }
    /**
     * Occurs when new state appears in history
     */
    get historyChange() {
        return this.historyChangeSubject.asObservable();
    }
    /**
     * Current state of metadata
     */
    get state() {
        if (isBlank(this.activeIndex)) {
            return null;
        }
        return JSON.parse(this.states[this.activeIndex]);
    }
    //######################### constructor #########################
    constructor(metadataState) {
        this.metadataState = metadataState;
        //######################### protected properties #########################
        /**
         * Current index which is active currently
         */
        this.activeIndex = null;
        /**
         * Index of state which is saved
         */
        this.saveIndex = null;
        /**
         * All stored states
         */
        this.states = [];
        /**
         * Indication whether is manager enabled
         */
        this.enabled = true;
        /**
         * Used for emitting pop event
         */
        this.popSubject = new Subject();
        /**
         * Used for emitting history change event
         */
        this.historyChangeSubject = new Subject();
    }
    //######################### public methods #########################
    /**
     * Undo last change in metadata
     */
    undo() {
        if (!this.canUndo || isBlank(this.activeIndex)) {
            return;
        }
        this.activeIndex--;
        this.popSubject.next(JSON.parse(this.states[this.activeIndex]));
    }
    /**
     * Redo last change in metadata
     */
    redo() {
        if (!this.canRedo || isBlank(this.activeIndex)) {
            return;
        }
        this.activeIndex++;
        this.popSubject.next(JSON.parse(this.states[this.activeIndex]));
    }
    /**
     * Indicates that new change in state has been done and should be retrieved
     */
    getNewState() {
        if (!this.enabled) {
            return;
        }
        //max number of states reached
        if (this.states.length >= MAX_ITEMS) {
            this.states.shift();
        }
        //getting new state, where current index is not at the end, rewriting history for redo
        if (isPresent(this.activeIndex) && this.activeIndex + 1 < this.states.length) {
            this.states.splice(this.activeIndex + 1, this.states.length - (this.activeIndex + 1));
        }
        const state = this.metadataState.getMetadata();
        //only for existing state
        if (state) {
            this.states.push(JSON.stringify(state));
            this.activeIndex = this.states.length - 1;
            this.historyChangeSubject.next();
        }
    }
    /**
     * Sets current state as saved state
     */
    save() {
        this.saveIndex = this.activeIndex;
    }
    setInitialState(metadata) {
        this.states.push(JSON.stringify(metadata));
        this.activeIndex = this.states.length - 1;
        this.save();
    }
    /**
     * Cleans history of metadata states
     */
    clean() {
        this.activeIndex = null;
        this.saveIndex = null;
        this.states = [];
    }
    /**
     * Enable metadata history manager, changes in metadata are stored
     */
    enable() {
        this.enabled = true;
    }
    /**
     * Disables metadata history manager, changes in metadata history are not stored
     */
    disable() {
        this.enabled = false;
    }
}
MetadataHistoryManager.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.4", ngImport: i0, type: MetadataHistoryManager, deps: [{ token: METADATA_STATE_MANAGER }], target: i0.ɵɵFactoryTarget.Injectable });
MetadataHistoryManager.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.4", ngImport: i0, type: MetadataHistoryManager });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.4", ngImport: i0, type: MetadataHistoryManager, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: undefined, decorators: [{
                    type: Inject,
                    args: [METADATA_STATE_MANAGER]
                }] }] });
//# sourceMappingURL=metadataHistoryManager.service.js.map