import { defineProps } from './types.js';

class JSONProp {
    parent;
    name;
    constructor(data){
        this.parent = data;
        if (this.parent && !(this.parent instanceof JSONArray)) {
            for(let i = 1;; i++){
                const name = `field${i}`;
                if (!this.parent.value.find((p)=>p?.name === name)) {
                    this.name = name;
                    break;
                }
            }
        } else {
            this.name = '';
        }
    }
}
class JSONString extends JSONProp {
    value;
    constructor(data, value = ''){
        super(data);
        this.value = value;
    }
}
class JSONNumber extends JSONProp {
    value;
    constructor(data, value = 0){
        super(data);
        this.value = value;
    }
}
class JSONBool extends JSONProp {
    value;
    constructor(data, value = false){
        super(data);
        this.value = value;
    }
}
class JSONData extends JSONProp {
    value;
    data;
    isnull;
    isundefined;
    constructor(parent, data = {}){
        super(parent);
        this.updateObject(data);
    }
    updateObject(data) {
        this.value = [];
        this.data = data;
        this.isnull = this.data === null;
        if (this.data) {
            this.parseObject();
        }
    }
    parseObject() {
        for (const key of Object.keys(this.data)){
            const val = this.data[key];
            let prop;
            if (typeof val === 'string') {
                prop = new JSONString(this, val);
            } else if (typeof val === 'number') {
                prop = new JSONNumber(this, val);
            } else if (typeof val === 'boolean') {
                prop = new JSONBool(this, val);
            } else if (typeof val === 'object') {
                prop = Array.isArray(val) ? new JSONArray(this, val) : new JSONData(this, val);
            } else {
                continue;
            }
            prop.name = key;
            this.value.push(prop);
        }
    }
    updateProps() {
        for (const key of Object.keys(this.data)){
            if (!this.value.find((p)=>p?.name === key)) {
                delete this.data[key];
            }
        }
        for (const prop of this.value){
            if (prop instanceof JSONData) {
                this.data[prop.name] = prop.data;
            } else if (prop) {
                this.data[prop.name] = prop.value;
            }
        }
        return this.data;
    }
}
class JSONArray extends JSONData {
    constructor(parent, data = []){
        super(parent);
        this.updateObject(data);
    }
    updateObject(data) {
        this.value = [];
        this.data = data;
        this.isnull = this.data === null;
        if (this.data) {
            this.parseObject();
        }
    }
    parseObject() {
        const data = this.data;
        if (data?.length > 0) {
            for(let i = 0; i < data.length; i++){
                const val = data[i];
                let prop;
                if (typeof val === 'string') {
                    prop = new JSONString(this, val);
                } else if (typeof val === 'number') {
                    prop = new JSONNumber(this, val);
                } else if (typeof val === 'boolean') {
                    prop = new JSONBool(this, val);
                } else if (typeof val === 'object') {
                    prop = !val ? null : Array.isArray(val) ? new JSONArray(this, val) : new JSONData(this, val);
                } else {
                    continue;
                }
                this.value.push(prop);
            }
        }
    }
    updateProps() {
        const data = this.data;
        data.splice(0, data.length);
        for(let i = 0; i < this.value.length; i++){
            const prop = this.value[i];
            if (prop instanceof JSONArray) {
                this.data[i] = prop.data;
            } else if (prop instanceof JSONData) {
                this.data[i] = prop.data;
            } else {
                this.data[i] = prop?.value ?? null;
            }
        }
        return this.data;
    }
}
function normalizeSpecialJSONNumber(prop, value) {
    if ((prop.name === 'offset' || prop.name === 'endOffset') && prop.parent && !(prop.parent instanceof JSONArray) && prop.parent.data?.type === 'capsule') {
        return Math.max(0.0001, Math.abs(value));
    }
    if (prop.name === 'normal' && prop.parent && !(prop.parent instanceof JSONArray) && prop.parent.data?.type === 'plane') {
        return value < 0 ? -1 : 1;
    }
    return value;
}
function getJSONPropClass() {
    return {
        ctor: JSONProp,
        name: 'JSONProp',
        noTitle: true,
        createFunc (ctx) {
            return {
                obj: new JSONProp(ctx)
            };
        },
        getProps () {
            return defineProps([
                {
                    name: 'name',
                    type: 'string',
                    default: '',
                    isHidden () {
                        return !this.parent || this.parent instanceof JSONArray;
                    },
                    get (value) {
                        value.str[0] = this.name;
                    },
                    set (value) {
                        const data = this.parent;
                        if (data && value.str[0] && !data.value.find((p)=>p !== this && p.name === value.str[0])) {
                            this.name = value.str[0];
                            this.parent.updateProps();
                        }
                    }
                }
            ]);
        }
    };
}
function getJSONStringClass() {
    return {
        ctor: JSONString,
        parent: JSONProp,
        name: 'JSONString',
        noTitle: true,
        createFunc (ctx) {
            return {
                obj: new JSONString(ctx)
            };
        },
        getProps () {
            return defineProps([
                {
                    name: 'value',
                    type: 'string',
                    isHidden () {
                        return this.name.startsWith('.');
                    },
                    get (value) {
                        value.str[0] = this.value;
                    },
                    set (value) {
                        if (this.value !== value.str[0]) {
                            this.value = value.str[0];
                            this.parent.updateProps();
                        }
                    }
                }
            ]);
        }
    };
}
function getJSONNumberClass() {
    return {
        ctor: JSONNumber,
        parent: JSONProp,
        name: 'JSONNumber',
        noTitle: true,
        createFunc (ctx) {
            return {
                obj: new JSONString(ctx)
            };
        },
        getProps () {
            return defineProps([
                {
                    name: 'value',
                    type: 'float',
                    isHidden () {
                        return this.name.startsWith('.');
                    },
                    get (value) {
                        value.num[0] = this.value;
                    },
                    set (value) {
                        const nextValue = normalizeSpecialJSONNumber(this, value.num[0]);
                        if (this.value !== nextValue) {
                            this.value = nextValue;
                            this.parent.updateProps();
                        }
                    }
                }
            ]);
        }
    };
}
function getJSONBoolClass() {
    return {
        ctor: JSONBool,
        parent: JSONProp,
        name: 'JSONBool',
        noTitle: true,
        createFunc (ctx) {
            return {
                obj: new JSONBool(ctx)
            };
        },
        getProps () {
            return defineProps([
                {
                    name: 'value',
                    type: 'bool',
                    isHidden () {
                        return this.name.startsWith('.');
                    },
                    get (value) {
                        value.bool[0] = this.value;
                    },
                    set (value) {
                        if (this.value !== value.bool[0]) {
                            this.value = value.bool[0];
                            this.parent.updateProps();
                        }
                    }
                }
            ]);
        }
    };
}
function getJSONObjectClass() {
    return {
        ctor: JSONData,
        parent: JSONProp,
        name: 'JSONData',
        noTitle: true,
        createFunc (ctx) {
            return {
                obj: new JSONData(ctx instanceof JSONData ? ctx : null)
            };
        },
        getProps () {
            return defineProps([
                {
                    name: 'JSONData',
                    type: 'object_array',
                    options: {
                        objectTypes: [
                            JSONString,
                            JSONNumber,
                            JSONBool,
                            JSONData,
                            JSONArray
                        ]
                    },
                    default: [],
                    isNullable () {
                        return false;
                    },
                    isHidden () {
                        return this.name.startsWith('.');
                    },
                    get (value) {
                        value.object = this.value.slice();
                    },
                    set (value, index) {
                        if (value === null) {
                            this.isnull = true;
                        } else if (typeof index === 'number' && index >= 0) {
                            this.value[index] = value.object[0];
                            this.updateProps();
                        } else {
                            this.value = value.object.slice();
                            this.updateProps();
                        }
                    },
                    create (ctor) {
                        const c = ctor;
                        return c ? new c(this) : null;
                    },
                    add (value, index) {
                        this.value.splice(index, 0, value.object[0]);
                        this.updateProps();
                    },
                    delete (index) {
                        this.value.splice(index, 1);
                        this.updateProps();
                    }
                }
            ]);
        }
    };
}
function getJSONArrayClass() {
    return {
        ctor: JSONArray,
        parent: JSONProp,
        name: 'JSONArray',
        noTitle: true,
        createFunc (ctx) {
            return {
                obj: new JSONArray(ctx instanceof JSONData || ctx instanceof JSONArray ? ctx : null)
            };
        },
        getProps () {
            return defineProps([
                {
                    name: 'JSONArray',
                    type: 'object_array',
                    options: {
                        objectTypes: [
                            JSONString,
                            JSONNumber,
                            JSONBool,
                            JSONData,
                            JSONArray
                        ]
                    },
                    default: [],
                    isNullable () {
                        return true;
                    },
                    get (value) {
                        value.object = this.value.slice();
                    },
                    set (value, index) {
                        if (value === null) {
                            this.isnull = true;
                        } else if (index >= 0) {
                            this.value[index] = value.object[0];
                            this.updateProps();
                        } else {
                            this.value = value.object.slice();
                            this.updateProps();
                        }
                    },
                    create (ctor, index) {
                        const c = ctor;
                        const prop = c ? new c(this) : null;
                        if (prop) {
                            prop.name = String(index);
                        }
                        return prop;
                    },
                    add (value, index) {
                        this.value.splice(index, 0, value.object[0]);
                        this.updateProps();
                    },
                    delete (index) {
                        this.value.splice(index, 1);
                        this.updateProps();
                    }
                }
            ]);
        }
    };
}

export { JSONArray, JSONBool, JSONData, JSONNumber, JSONProp, JSONString, getJSONArrayClass, getJSONBoolClass, getJSONNumberClass, getJSONObjectClass, getJSONPropClass, getJSONStringClass };
//# sourceMappingURL=json.js.map
