import { DataUtilities } from "../../DataUtilities";
import { XDataDefinition } from "../XDataDefinition";
import { NumberDataDefinition } from "./NumberDataDefinition";
import { DateDataDefinition } from "./DateDataDefinition";
import { StringDataDefinition } from "./StringDataDefinition";
import { BooleanDataDefinition } from "./BooleanDataDefinition";
import { BaseDataDefinition } from "./BaseDataDefinition";
import { FileDataDefinition } from "./FileDataDefinition";
import { XDataType } from "../XDataType";
import { ConfigStorageUtility } from "../../ConfigStorageUtility";
import { ValidationIssue } from "../../IDesignValidationProvider";
export class ObjectDataDefinition extends BaseDataDefinition {
    constructor() {
        super(...arguments);
        this.type = XDataType.OBJECT;
        this.fields = [];
    }
    getValueObject() {
        if (this.owner && this.name) {
            let valObj = this.owner.getValueObject()[this.name];
            if (!valObj) {
                valObj = {};
                this.owner.getValueObject()[this.name] = valObj;
            }
            // check array
            if (Array.isArray(valObj) !== this.list) {
                if (this.list) {
                    // set array
                    valObj = [];
                    this.owner.getValueObject()[this.name] = valObj;
                }
                else {
                    // set object
                    valObj = {};
                    this.owner.getValueObject()[this.name] = valObj;
                }
            }
            return valObj;
        }
        // this should not happen
        return this.list ? [] : {};
    }
    static parseObject(owner, checkVal, data, isList, name, currentDefinition, removeItemsNotInSchema, reorderElementsToMatch) {
        var _a, _b, _c;
        // check if date
        if (DataUtilities.isValidDate(checkVal)) {
            let dateDef = (_a = currentDefinition) !== null && _a !== void 0 ? _a : new DateDataDefinition();
            dateDef.name = name;
            dateDef.owner = owner;
            dateDef.list = isList;
            if (isList) {
                dateDef.setListValue(data);
            }
            else {
                dateDef.setValue(data);
            }
            return dateDef;
        }
        // check if file
        if (DataUtilities.isValidFile(checkVal)) {
            let dateDef = (_b = currentDefinition) !== null && _b !== void 0 ? _b : new FileDataDefinition();
            dateDef.name = name;
            dateDef.owner = owner;
            dateDef.list = isList;
            if (isList) {
                dateDef.setListValue(data);
            }
            else {
                dateDef.setValue(data);
            }
            return dateDef;
        }
        // default parse as object
        let objectDef = (_c = currentDefinition) !== null && _c !== void 0 ? _c : new ObjectDataDefinition();
        objectDef.name = name;
        objectDef.owner = owner;
        objectDef.list = isList;
        if (isList) {
            objectDef.setListValue(data);
        }
        else {
            objectDef.setValue(data);
        }
        objectDef.fields = this.parseFieldsForObject(objectDef, checkVal, objectDef.fields, removeItemsNotInSchema, reorderElementsToMatch);
        return objectDef;
    }
    static parseFieldsForObject(owner, data, existingFields, removeItemsNotInSchema, reorderElementsToMatch) {
        var _a, _b, _c, _d;
        let newFieldsMap = {};
        let newFieldList = [];
        let oldFieldsMap = {};
        for (let oField of existingFields) {
            if (oField.name) {
                oldFieldsMap[oField.name] = oField;
            }
        }
        for (let name in data) {
            let val = Reflect.get(data, name);
            let checkVal = val;
            let isArray = false;
            if (Array.isArray(val)) {
                isArray = true;
                checkVal = val[0];
            }
            let def = null;
            if (typeof checkVal === "string") {
                // see if it is a date string
                if (DataUtilities.isDateString(checkVal)) {
                    let sdef = (_a = oldFieldsMap[name]) !== null && _a !== void 0 ? _a : new DateDataDefinition();
                    sdef.name = name;
                    sdef.owner = owner;
                    if (isArray) {
                        //todo: handle date array
                        let dateArray = [];
                        for (let dString of val) {
                            dateArray.push(DataUtilities.getDateFromString(dString));
                        }
                        sdef.setListValue(dateArray);
                    }
                    else {
                        sdef.setValue(DataUtilities.getDateFromString(val));
                    }
                    sdef.list = isArray;
                    def = sdef;
                }
                else {
                    let sdef = (_b = oldFieldsMap[name]) !== null && _b !== void 0 ? _b : new StringDataDefinition();
                    sdef.name = name;
                    sdef.owner = owner;
                    if (isArray) {
                        sdef.setListValue(val);
                    }
                    else {
                        sdef.setValue(val);
                    }
                    sdef.list = isArray;
                    def = sdef;
                }
            }
            else if (typeof checkVal === "number") {
                let sdef = (_c = oldFieldsMap[name]) !== null && _c !== void 0 ? _c : new NumberDataDefinition();
                sdef.name = name;
                sdef.owner = owner;
                if (isArray) {
                    sdef.setListValue(val);
                }
                else {
                    sdef.setValue(val);
                }
                sdef.list = isArray;
                def = sdef;
            }
            else if (typeof checkVal === "boolean") {
                let sdef = (_d = oldFieldsMap[name]) !== null && _d !== void 0 ? _d : new BooleanDataDefinition();
                sdef.name = name;
                sdef.owner = owner;
                if (isArray) {
                    sdef.setListValue(val);
                }
                else {
                    sdef.setValue(val);
                }
                sdef.list = isArray;
                def = sdef;
            }
            else {
                def = ObjectDataDefinition.parseObject(owner, checkVal, val, isArray, name, oldFieldsMap[name], removeItemsNotInSchema, reorderElementsToMatch);
            }
            if (def && def.name) {
                newFieldsMap[def.name] = def;
                newFieldList.push(def);
            }
        }
        return XDataDefinition.reconcileFieldList(removeItemsNotInSchema, reorderElementsToMatch, newFieldList, newFieldsMap, existingFields);
    }
    getValue() {
        return this.getValueObject();
    }
    setValue(value) {
        if (this.owner && this.name) {
            this.owner.getValueObject()[this.name] = value;
        }
    }
    getListValue() {
        return this.getValueObject();
    }
    setListValue(value) {
        if (this.owner && this.name) {
            this.owner.getValueObject()[this.name] = value;
        }
    }
    getStorageData() {
        let object = super.getStorageData();
        Reflect.set(object, "keyField", this.keyField);
        let fieldData = [];
        for (let f of this.fields) {
            fieldData.push(f.getStorageData());
        }
        Reflect.set(object, "fields", fieldData);
        return object;
    }
    setStorageData(data) {
        super.setStorageData(data);
        this.keyField = Reflect.get(data, "keyField");
        let fieldData = Reflect.get(data, "fields");
        for (let f of fieldData) {
            let val = ConfigStorageUtility.getDataDefinitionFromData(f);
            this.fields.push(val);
        }
    }
    convert(value) {
        // do not convert these
        return value;
    }
    verifyValueType(value) {
        if (value === undefined)
            return new ValidationIssue("value is undefined");
        if (value === null)
            return new ValidationIssue("value is unset");
        if (typeof value !== "object")
            return new ValidationIssue("value is not an object");
        let issues = [];
        for (let f of this.fields) {
            let val = Reflect.get(value, f.name);
            if (f === undefined)
                continue;
            // try conversion
            val = f.convert(val);
            let issue = f.verifyValueType(val);
            if (issue) {
                issues.push(`${f.name}: [${issue.issue}]`);
            }
        }
        if (issues.length === 0)
            return undefined;
        return new ValidationIssue(issues.join(", "));
    }
}
//# sourceMappingURL=ObjectDataDefinition.js.map