aboutsummaryrefslogtreecommitdiffstats
path: root/js/KeyValueStore.ts
blob: fd8f39efc30551327258e06dfeb248bd34521562 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
type KeyValueStoreCallback<T> = (value: T) => void;

interface IKeyValueStoreParam<T> {
    value: T;
    valueRange?: T[];
    callbacks?: KeyValueStoreCallback<T>[];
}

type KeyValueStoreData<T> = { [K in keyof T]: IKeyValueStoreParam<T[K]> };

class KeyValueStore<T> {
    constructor(private data: KeyValueStoreData<T>) {
        for (const id of Object.keys(data)) {
            const props = data[id as keyof typeof data];

            if (props.valueRange && props.valueRange.indexOf(props.value) === -1) {
                throw new Error(`Invalid value "${props.value}" for ID "${id}"`);
            }
        }
    }

    public getValue(id: keyof T) {
        return this.data[id].value;
    }

    public setValue<K extends keyof T>(id: K, value: T[K]) {
        const props = this.data[id];

        if (props.valueRange) {
            const valueIndex = props.valueRange.indexOf(value);
            if (valueIndex === -1) {
                throw new Error(`Invalid value "${value}" for ID "${id}"`);
            }
        }

        props.value = value;

        if (props.callbacks) {
            props.callbacks.forEach(callback => {
                callback(value);
            });
        }
    }

    public cycleValue<K extends keyof T>(id: K, dir: -1 | 1 = 1) {
        const props = this.data[id];

        if (!props) {
            throw new Error(`Invalid ID "${id}"`);
        }

        let value = props.value;

        if (props.valueRange) {
            let valueIndex = props.valueRange.indexOf(value) + dir;

            if (valueIndex >= props.valueRange.length) {
                valueIndex = 0;
            } else if (valueIndex < 0) {
                valueIndex = props.valueRange.length - 1;
            }

            value = props.value = props.valueRange[valueIndex];
        } else if (typeof value === "number") {
            (value as number) += dir;
            props.value = value;
        } else {
            throw new Error(`Can't cycle "${id}"`);
        }

        if (props.callbacks) {
            props.callbacks.forEach(callback => {
                callback(value);
            });
        }

        return value;
    }

    public addCallback<K extends keyof T>(id: K, callback: KeyValueStoreCallback<T[K]>) {
        const props = this.data[id];

        if (!props.callbacks) {
            props.callbacks = [];
        }

        props.callbacks.push(callback);
    }
}