import { Map as ImmutableMap, Collection, fromJS } from 'immutable';
import EventManager from './EventManager';

const StoreEvents = {
    CHANGE: 'CHANGE'
};

function toPath(path) {
    return Array.isArray(path) ? path : (typeof path === 'string' ? path.split('.') : [ path ]);
}

function toPlain(value) {
    return value instanceof Collection ? value.toJS() : value;
}

class Store {
    constructor() {
        this._state = new ImmutableMap();
        this._eventManager = new EventManager();
    }

    onChange(handler) {
        return this._eventManager.addListener(StoreEvents.CHANGE, handler);
    }

    getState() {
        return toPlain(this._state);
    }

    getImmutableState() {
        return this._state;
    }

    get(path) {
        return toPlain(this.getImmutable(path));
    }

    getImmutable(path) {
        return this._state.getIn(toPath(path));
    }

    setState(plainObject) {
        this._state = fromJS(plainObject);
        this._eventManager.dispatchEvent(StoreEvents.CHANGE);
    }

    set(path, plainValue) {
        this._state = this._state.setIn(toPath(path), fromJS(plainValue));
        this._eventManager.dispatchEvent(StoreEvents.CHANGE);
    }

    mergeState(plainObject) {
        this._state = this._state.merge(fromJS(plainObject));
        this._eventManager.dispatchEvent(StoreEvents.CHANGE);
    }

    merge(path, plainObject) {
        this._state = this._state.mergeIn(toPath(path), fromJS(plainObject));
        this._eventManager.dispatchEvent(StoreEvents.CHANGE);
    }

    removeState() {
        return this.setState({});
    }

    remove(path) {
        this._state = this._state.removeIn(toPath(path));
        this._eventManager.dispatchEvent(StoreEvents.CHANGE);
    }
}

export default Store;
