import { find } from 'lodash';
import { of, Subject } from 'rxjs';
import { map } from 'rxjs/operators';
import { Graph, GraphResult, GraphType } from '../../../config';
import { StringifyingMap } from '../../../core/stringifying-map';
export class RemoteGraphStore {
    constructor(remoteGraphProtocol) {
        this.remoteGraphProtocol = remoteGraphProtocol;
        this.graphStateCache = new StringifyingMap(k => JSON.stringify(k));
    }
    getGraph(graphId, stateId, extendedStyle) {
        const graphStateKey = { graphId, stateId, extendedStyle };
        if (this.graphStateCache.has(graphStateKey)) {
            return of(this.graphStateCache.get(graphStateKey));
        }
        const version = this.remoteGraphProtocol.version;
        if (version >= 1) {
            return this.getReleasedGraphState(graphStateKey);
        }
        else {
            return this.getSystemGraph(graphStateKey);
        }
    }
    getSystemGraph(graphStateKey) {
        const graphId = String(graphStateKey.graphId);
        return this.remoteGraphProtocol.getSystemGraphConfig(graphId).pipe(map((graphConfig) => {
            let result;
            const stateConfig = find(graphConfig.states, s => s.id === graphStateKey.stateId);
            if (stateConfig) {
                const graphType = stateConfig.type === 'svg' ? GraphType.SVG : GraphType.Image;
                const graph = new Graph(graphType, this.remoteGraphProtocol.getAbsoluteStateUrl(graphId, stateConfig.url));
                result = GraphResult.success(graph);
            }
            else {
                result = GraphResult.failed();
            }
            this.graphStateCache.set(graphStateKey, result);
            return result;
        }));
    }
    getImageUrl(url) {
        if (!url) {
            return url;
        }
        if (url.indexOf('http://') === 0 || url.indexOf('https://') === 0) {
            return url;
        }
        return this.remoteGraphProtocol.remoteServiceBaseUrl + url;
    }
    getReleasedGraphState(graphStateKey) {
        if (graphStateKey.extendedStyle) {
            return this.getReleaseGraphStateWithExtendedStyle(graphStateKey);
        }
        if (!this.graphStateToBeResolved) {
            this.graphStateToBeResolved =
                new StringifyingMap(k => JSON.stringify(k));
            setTimeout(() => { this.resolvePendingStates(); });
        }
        if (!this.graphStateToBeResolved.has(graphStateKey)) {
            this.graphStateToBeResolved.set(graphStateKey, new Subject());
        }
        return this.graphStateToBeResolved.get(graphStateKey);
    }
    getReleaseGraphStateWithExtendedStyle(graphStateKey) {
        const graphId = Number(graphStateKey.graphId);
        const fill = encodeURIComponent(graphStateKey.extendedStyle.fill);
        const stroke = encodeURIComponent(graphStateKey.extendedStyle.stroke);
        const url = this.remoteGraphProtocol.getGraphStateUrl(graphId, graphStateKey.stateId, fill, stroke);
        const graph = new Graph(GraphType.SVG, url);
        return of(GraphResult.success(graph));
    }
    resolvePendingStates() {
        const graphStateToBeResolved = this.graphStateToBeResolved;
        const states = [];
        graphStateToBeResolved.forEach((__, key) => {
            const graphState = JSON.parse(key);
            states.push({ graphId: graphState.graphId, stateIndex: graphState.stateId });
        });
        const dto = { states: states };
        this.remoteGraphProtocol.getReleasedGraphStates(dto).subscribe(result => {
            result.forEach(value => {
                const key = { graphId: value.graphId, stateId: value.stateIndex };
                let graphResult;
                if (value.result) {
                    const url = this.getImageUrl(value.result.url);
                    graphResult = GraphResult.success(new Graph(value.result.type, url));
                }
                else {
                    graphResult = GraphResult.failed();
                }
                this.graphStateCache.set(key, graphResult);
                const subject = graphStateToBeResolved.get(key);
                if (subject) {
                    subject.next(graphResult);
                    subject.complete();
                }
            });
        });
        delete this.graphStateToBeResolved;
    }
}
