import { HEADER_VARIABLES } from '../database';
import { Dwg_Object_Type } from '../types';
import { LibreEntityConverter } from './entityConverter';
import { idToString, isModelSpace, isPaperSpace } from './utils';
/**
 * Class used to convert Dwg_Data instance to DwgDatabase instance.
 */
export class LibreDwgConverter {
    libredwg;
    entityConverter;
    constructor(instance) {
        this.libredwg = instance;
        this.entityConverter = new LibreEntityConverter(instance);
    }
    convert(data) {
        this.entityConverter.clear();
        const db = {
            tables: {
                APPID: {
                    entries: []
                },
                BLOCK_RECORD: {
                    entries: []
                },
                DIMSTYLE: {
                    entries: []
                },
                LAYER: {
                    entries: []
                },
                LTYPE: {
                    entries: []
                },
                STYLE: {
                    entries: []
                },
                VPORT: {
                    entries: []
                }
            },
            objects: {
                DICTIONARY: [],
                IMAGEDEF: [],
                LAYOUT: [],
                SPATIAL_FILTER: []
            },
            header: {},
            entities: [],
            classes: []
        };
        const libredwg = this.libredwg;
        this.convertHeader(data, db.header);
        this.convertClasses(data, db.classes);
        const num_objects = libredwg.dwg_get_num_objects(data);
        for (let i = 0; i < num_objects; i++) {
            const obj = libredwg.dwg_get_object(data, i);
            if (obj) {
                const tio = libredwg.dwg_object_to_object_tio(obj);
                if (tio) {
                    const fixedtype = libredwg.dwg_object_get_fixedtype(obj);
                    switch (fixedtype) {
                        case Dwg_Object_Type.DWG_TYPE_LAYER:
                            {
                                const layer = this.convertLayer(tio, obj);
                                db.tables.LAYER.entries.push(layer);
                                this.entityConverter.layers.set(layer.handle, layer.name);
                            }
                            break;
                        case Dwg_Object_Type.DWG_TYPE_LTYPE:
                            {
                                const ltype = this.convertLineType(tio, obj);
                                db.tables.LTYPE.entries.push(ltype);
                                this.entityConverter.ltypes.set(ltype.handle, ltype.name);
                            }
                            break;
                        default:
                            break;
                    }
                }
            }
        }
        for (let i = 0; i < num_objects; i++) {
            const obj = libredwg.dwg_get_object(data, i);
            if (obj) {
                const tio = libredwg.dwg_object_to_object_tio(obj);
                if (tio) {
                    const fixedtype = libredwg.dwg_object_get_fixedtype(obj);
                    switch (fixedtype) {
                        case Dwg_Object_Type.DWG_TYPE_APPID:
                            db.tables.APPID.entries.push(this.convertAppId(tio));
                            break;
                        case Dwg_Object_Type.DWG_TYPE_BLOCK_HEADER:
                            {
                                const btr = this.convertBlockRecord(tio, obj);
                                db.tables.BLOCK_RECORD.entries.push(btr);
                                // Store entities in model space and paper space to db.entities to keep the
                                // the consistent data structure as DXF file
                                if (isModelSpace(btr.name) || isPaperSpace(btr.name)) {
                                    btr.entities.forEach(entity => {
                                        db.entities.push(entity);
                                        // Store ATTRIB entity in db.entities to keep the the consistent data
                                        // structure as DXF file
                                        if (entity.type === 'INSERT') {
                                            entity.attribs.forEach(attrib => {
                                                db.entities.push(attrib);
                                            });
                                        }
                                    });
                                }
                            }
                            break;
                        case Dwg_Object_Type.DWG_TYPE_DIMSTYLE:
                            db.tables.DIMSTYLE.entries.push(this.convertDimStyle(tio, obj));
                            break;
                        case Dwg_Object_Type.DWG_TYPE_STYLE:
                            db.tables.STYLE.entries.push(this.convertStyle(tio, obj));
                            break;
                        case Dwg_Object_Type.DWG_TYPE_VPORT:
                            db.tables.VPORT.entries.push(this.convertViewport(tio, obj));
                            break;
                        case Dwg_Object_Type.DWG_TYPE_DICTIONARY:
                            db.objects.DICTIONARY.push(this.convertDictionary(tio, obj));
                            break;
                        case Dwg_Object_Type.DWG_TYPE_IMAGEDEF:
                            db.objects.IMAGEDEF.push(this.convertImageDef(tio, obj));
                            break;
                        case Dwg_Object_Type.DWG_TYPE_LAYOUT:
                            db.objects.LAYOUT.push(this.convertLayout(tio, obj));
                            break;
                        case Dwg_Object_Type.DWG_TYPE_SPATIAL_FILTER:
                            db.objects.SPATIAL_FILTER.push(this.convertSpatialFilter(tio, obj));
                            break;
                        default:
                            break;
                    }
                }
            }
        }
        // Process viewport entities: sort by objectId (handle) and assign viewportId
        const viewportEntities = db.entities.filter(entity => entity.type === 'VIEWPORT');
        viewportEntities.sort((a, b) => {
            // Convert handle to hex number for sorting
            const handleA = parseInt(a.handle, 16);
            const handleB = parseInt(b.handle, 16);
            return handleA - handleB;
        });
        // Assign viewportId starting from 1
        viewportEntities.forEach((viewport, index) => {
            viewport.viewportId = index + 1;
        });
        return db;
    }
    getConversionStats() {
        return {
            unknownEntityCount: this.entityConverter.unknownEntityCount
        };
    }
    convertHeader(data, header) {
        const libredwg = this.libredwg;
        HEADER_VARIABLES.forEach(name => {
            let var_name = name;
            if (name == 'DIMBLK' || name == 'DIMBLK1' || name == 'DIMBLK2') {
                var_name = var_name + '_T';
            }
            let value = libredwg.dwg_dynapi_header_value(data, var_name).data;
            // Get object name if the 'value' is one Dwg_Object_Ref instance.
            // TODO: handle 'CMLSTYLE' correctly
            if (name == 'CELTYPE' ||
                name == 'CLAYER' ||
                name == 'CLAYER' ||
                name == 'DIMSTYLE' ||
                name == 'DIMTXSTY' ||
                name == 'TEXTSTYLE') {
                value = !!value ? libredwg.dwg_ref_get_object_name(value) : '';
            }
            else if (name == 'DRAGVS') {
                value = !!value ? libredwg.dwg_ref_get_absref(value) : 2;
            }
            // @ts-expect-error header variable name
            header[name] = value;
        });
    }
    convertClasses(data, classes) {
        const libredwg = this.libredwg;
        const count = libredwg.dwg_get_num_classes(data);
        for (let index = 0; index < count; index++) {
            const cls = libredwg.dwg_get_class(data, index);
            classes.push({
                dxfName: cls.dxfname,
                cppName: cls.cppname,
                appName: cls.appname,
                capabilitiesFlag: cls.proxyflag,
                instanceCount: cls.num_instances,
                wasAProxyFlag: cls.s_zombie,
                // DWG_TYPE_PROXY_ENTITY = 0x1F2 /* 498 */,
                // DWG_TYPE_PROXY_OBJECT = 0x1F3 /* 499 */,
                isAnEntityFlag: cls.item_class_id === 0x1f2
            });
        }
    }
    convertAppId(item) {
        const libredwg = this.libredwg;
        const name = libredwg.dwg_dynapi_entity_value(item, 'name').data;
        const flag = libredwg.dwg_dynapi_entity_value(item, 'flag').data;
        return {
            name: name,
            standardFlag: flag
        };
    }
    convertBlockRecord(item, obj) {
        const libredwg = this.libredwg;
        const commonAttrs = this.getCommonTableEntryAttrs(item, obj);
        // The BLOCK_HEADER has only the abbrevated name, but we want "*D30" instead of "*D".
        // So get full name from BLOCK entity.
        const block = libredwg.dwg_entity_block_header_get_block(item);
        if (block.name) {
            commonAttrs.name = block.name;
        }
        // The number of entities
        const num_owned = libredwg.dwg_dynapi_entity_value(item, 'num_owned')
            .data;
        const flags = libredwg.dwg_dynapi_entity_value(item, 'flag').data;
        const description = libredwg.dwg_dynapi_entity_value(item, 'description')
            .data;
        const basePoint = libredwg.dwg_dynapi_entity_value(item, 'base_pt')
            .data;
        const insertionUnits = libredwg.dwg_dynapi_entity_value(item, 'insert_units').data;
        const explodability = libredwg.dwg_dynapi_entity_value(item, 'explodable')
            .data;
        const scalability = libredwg.dwg_dynapi_entity_value(item, 'block_scaling')
            .data;
        const layout_ptr = libredwg.dwg_dynapi_entity_value(item, 'layout')
            .data;
        const layout = idToString(libredwg.dwg_ref_get_absref(layout_ptr));
        let bmpPreview = '';
        const uint8ArrayToHexString = (bytes) => {
            const hexChars = new Array(bytes.length);
            for (let i = 0; i < bytes.length; i++) {
                hexChars[i] = bytes[i].toString(16).toUpperCase();
            }
            return hexChars.join('');
        };
        const bmpPreviewBinaryData = libredwg.dwg_entity_block_header_get_preview(item);
        if (bmpPreviewBinaryData && bmpPreviewBinaryData.length > 0) {
            bmpPreview = uint8ArrayToHexString(bmpPreviewBinaryData);
        }
        // Sometimes function get_first_owned_entity returns 0 when trying to iterate entities in one block.
        // I guess it is one bug on libredwg. I logged [one bug](https://github.com/LibreDWG/libredwg/issues/1199)
        // on libredwg too. In this time, I try to use property 'entities' of block header to iterate entities.
        let entities = this.convertEntities(obj, commonAttrs.handle);
        if (!entities || entities.length == 0) {
            entities = [];
            const entities_ptr = libredwg.dwg_dynapi_entity_value(item, 'entities')
                .data;
            if (entities_ptr) {
                const object_ref_ptr_array = libredwg.dwg_ptr_to_object_ref_ptr_array(entities_ptr, num_owned);
                const converter = this.entityConverter;
                for (let index = 0; index < num_owned; index++) {
                    const object = libredwg.dwg_ref_get_object(object_ref_ptr_array[index]);
                    const entity = converter.convert(object);
                    if (entity) {
                        entity.ownerBlockRecordSoftId = commonAttrs.handle;
                        entities.push(entity);
                    }
                }
            }
        }
        return {
            ...commonAttrs,
            flags: flags,
            description: description,
            basePoint: basePoint,
            layout: layout,
            insertionUnits: insertionUnits,
            explodability: explodability,
            scalability: scalability,
            bmpPreview: bmpPreview,
            entities: entities
        };
    }
    convertEntities(obj, ownerHandle) {
        const libredwg = this.libredwg;
        const converter = this.entityConverter;
        const entities = [];
        let next = libredwg.get_first_owned_entity(obj);
        while (next) {
            const entity = converter.convert(next);
            if (entity) {
                entity.ownerBlockRecordSoftId = ownerHandle;
                entities.push(entity);
            }
            next = libredwg.get_next_owned_entity(obj, next);
        }
        return entities;
    }
    convertDimStyle(item, obj) {
        const libredwg = this.libredwg;
        const commonAttrs = this.getCommonTableEntryAttrs(item, obj);
        const DIMTOL = libredwg.dwg_dynapi_entity_value(item, 'DIMTOL')
            .data;
        const DIMLIM = libredwg.dwg_dynapi_entity_value(item, 'DIMLIM')
            .data;
        const DIMTIH = libredwg.dwg_dynapi_entity_value(item, 'DIMTIH')
            .data;
        const DIMTOH = libredwg.dwg_dynapi_entity_value(item, 'DIMTOH')
            .data;
        const DIMSE1 = libredwg.dwg_dynapi_entity_value(item, 'DIMSE1')
            .data;
        const DIMSE2 = libredwg.dwg_dynapi_entity_value(item, 'DIMSE2')
            .data;
        const DIMALT = libredwg.dwg_dynapi_entity_value(item, 'DIMALT')
            .data;
        const DIMTOFL = libredwg.dwg_dynapi_entity_value(item, 'DIMTOFL')
            .data;
        const DIMSAH = libredwg.dwg_dynapi_entity_value(item, 'DIMSAH')
            .data;
        const DIMTIX = libredwg.dwg_dynapi_entity_value(item, 'DIMTIX')
            .data;
        const DIMSOXD = libredwg.dwg_dynapi_entity_value(item, 'DIMSOXD')
            .data;
        const DIMALTD = libredwg.dwg_dynapi_entity_value(item, 'DIMALTD')
            .data;
        const DIMZIN = libredwg.dwg_dynapi_entity_value(item, 'DIMZIN')
            .data;
        const DIMSD1 = libredwg.dwg_dynapi_entity_value(item, 'DIMSD1')
            .data;
        const DIMSD2 = libredwg.dwg_dynapi_entity_value(item, 'DIMSD2')
            .data;
        const DIMTOLJ = libredwg.dwg_dynapi_entity_value(item, 'DIMTOLJ')
            .data;
        const DIMJUST = libredwg.dwg_dynapi_entity_value(item, 'DIMJUST')
            .data;
        const DIMFIT = libredwg.dwg_dynapi_entity_value(item, 'DIMFIT')
            .data;
        const DIMUPT = libredwg.dwg_dynapi_entity_value(item, 'DIMUPT')
            .data;
        const DIMTZIN = libredwg.dwg_dynapi_entity_value(item, 'DIMTZIN')
            .data;
        const DIMALTZ = libredwg.dwg_dynapi_entity_value(item, 'DIMALTZ')
            .data;
        const DIMALTTZ = libredwg.dwg_dynapi_entity_value(item, 'DIMALTTZ')
            .data;
        const DIMTAD = libredwg.dwg_dynapi_entity_value(item, 'DIMTAD')
            .data;
        const DIMUNIT = libredwg.dwg_dynapi_entity_value(item, 'DIMUNIT')
            .data;
        const DIMAUNIT = libredwg.dwg_dynapi_entity_value(item, 'DIMAUNIT')
            .data;
        const DIMDEC = libredwg.dwg_dynapi_entity_value(item, 'DIMDEC')
            .data;
        const DIMTDEC = libredwg.dwg_dynapi_entity_value(item, 'DIMTDEC')
            .data;
        const DIMALTU = libredwg.dwg_dynapi_entity_value(item, 'DIMALTU')
            .data;
        const DIMALTTD = libredwg.dwg_dynapi_entity_value(item, 'DIMALTTD')
            .data;
        const DIMSCALE = libredwg.dwg_dynapi_entity_value(item, 'DIMSCALE')
            .data;
        const DIMASZ = libredwg.dwg_dynapi_entity_value(item, 'DIMASZ')
            .data;
        const DIMEXO = libredwg.dwg_dynapi_entity_value(item, 'DIMEXO')
            .data;
        const DIMDLI = libredwg.dwg_dynapi_entity_value(item, 'DIMDLI')
            .data;
        const DIMEXE = libredwg.dwg_dynapi_entity_value(item, 'DIMEXE')
            .data;
        const DIMRND = libredwg.dwg_dynapi_entity_value(item, 'DIMRND')
            .data;
        const DIMDLE = libredwg.dwg_dynapi_entity_value(item, 'DIMDLE')
            .data;
        const DIMTP = libredwg.dwg_dynapi_entity_value(item, 'DIMTP').data;
        const DIMTM = libredwg.dwg_dynapi_entity_value(item, 'DIMTM').data;
        const DIMFXL = libredwg.dwg_dynapi_entity_value(item, 'DIMFXL')
            .data;
        const DIMJOGANG = libredwg.dwg_dynapi_entity_value(item, 'DIMJOGANG')
            .data;
        const DIMTFILL = libredwg.dwg_dynapi_entity_value(item, 'DIMTFILL')
            .data;
        const DIMTFILLCLR = libredwg.dwg_dynapi_entity_value(item, 'DIMTFILLCLR')
            .data;
        const DIMAZIN = libredwg.dwg_dynapi_entity_value(item, 'DIMAZIN')
            .data;
        const DIMARCSYM = libredwg.dwg_dynapi_entity_value(item, 'DIMARCSYM')
            .data;
        const DIMTXT = libredwg.dwg_dynapi_entity_value(item, 'DIMTXT')
            .data;
        const DIMCEN = libredwg.dwg_dynapi_entity_value(item, 'DIMCEN')
            .data;
        const DIMTSZ = libredwg.dwg_dynapi_entity_value(item, 'DIMTSZ')
            .data;
        const DIMALTF = libredwg.dwg_dynapi_entity_value(item, 'DIMALTF')
            .data;
        const DIMLFAC = libredwg.dwg_dynapi_entity_value(item, 'DIMLFAC')
            .data;
        const DIMTVP = libredwg.dwg_dynapi_entity_value(item, 'DIMTVP')
            .data;
        const DIMTFAC = libredwg.dwg_dynapi_entity_value(item, 'DIMTFAC')
            .data;
        const DIMGAP = libredwg.dwg_dynapi_entity_value(item, 'DIMGAP')
            .data;
        const DIMPOST = libredwg.dwg_dynapi_entity_value(item, 'DIMPOST')
            .data;
        const DIMAPOST = libredwg.dwg_dynapi_entity_value(item, 'DIMAPOST')
            .data;
        const DIMBLK_T = libredwg.dwg_dynapi_entity_value(item, 'DIMBLK_T')
            .data;
        const DIMBLK1_T = libredwg.dwg_dynapi_entity_value(item, 'DIMBLK1_T')
            .data;
        const DIMBLK2_T = libredwg.dwg_dynapi_entity_value(item, 'DIMBLK2_T')
            .data;
        const DIMALTRND = libredwg.dwg_dynapi_entity_value(item, 'DIMALTRND')
            .data;
        const DIMCLRD_N = libredwg.dwg_dynapi_entity_value(item, 'DIMCLRD_N')
            .data;
        const DIMCLRE_N = libredwg.dwg_dynapi_entity_value(item, 'DIMCLRE_N')
            .data;
        const DIMCLRT_N = libredwg.dwg_dynapi_entity_value(item, 'DIMCLRT_N')
            .data;
        const DIMCLRD = libredwg.dwg_dynapi_entity_value(item, 'DIMCLRD')
            .data;
        const DIMCLRE = libredwg.dwg_dynapi_entity_value(item, 'DIMCLRE')
            .data;
        const DIMCLRT = libredwg.dwg_dynapi_entity_value(item, 'DIMCLRT')
            .data;
        const DIMADEC = libredwg.dwg_dynapi_entity_value(item, 'DIMADEC')
            .data;
        const DIMFRAC = libredwg.dwg_dynapi_entity_value(item, 'DIMFRAC')
            .data;
        const DIMLUNIT = libredwg.dwg_dynapi_entity_value(item, 'DIMLUNIT')
            .data;
        const DIMDSEP = libredwg.dwg_dynapi_entity_value(item, 'DIMDSEP')
            .data;
        const DIMTMOVE = libredwg.dwg_dynapi_entity_value(item, 'DIMTMOVE')
            .data;
        const DIMATFIT = libredwg.dwg_dynapi_entity_value(item, 'DIMATFIT')
            .data;
        const DIMFXLON = libredwg.dwg_dynapi_entity_value(item, 'DIMFXLON')
            .data;
        const DIMTXTDIRECTION = libredwg.dwg_dynapi_entity_value(item, 'DIMTXTDIRECTION').data;
        const DIMALTMZF = libredwg.dwg_dynapi_entity_value(item, 'DIMALTMZF')
            .data;
        const DIMALTMZS = libredwg.dwg_dynapi_entity_value(item, 'DIMALTMZS')
            .data;
        const DIMMZF = libredwg.dwg_dynapi_entity_value(item, 'DIMMZF')
            .data;
        const DIMMZS = libredwg.dwg_dynapi_entity_value(item, 'DIMMZS')
            .data;
        const DIMLWD = libredwg.dwg_dynapi_entity_value(item, 'DIMLWD')
            .data;
        const DIMLWE = libredwg.dwg_dynapi_entity_value(item, 'DIMLWE')
            .data;
        const DIMTXSTY_Ptr = libredwg.dwg_dynapi_entity_value(item, 'DIMTXSTY')
            .data;
        const DIMTXSTY = libredwg.dwg_ref_get_absref(DIMTXSTY_Ptr);
        const DIMLDRBLK_Ptr = libredwg.dwg_dynapi_entity_value(item, 'DIMLDRBLK')
            .data;
        const DIMLDRBLK = libredwg.dwg_ref_get_absref(DIMLDRBLK_Ptr);
        return {
            ...commonAttrs,
            DIMPOST: DIMPOST,
            DIMAPOST: DIMAPOST,
            DIMBLK: DIMBLK_T,
            DIMBLK1: DIMBLK1_T,
            DIMBLK2: DIMBLK2_T,
            DIMSCALE: DIMSCALE,
            DIMASZ: DIMASZ,
            DIMEXO: DIMEXO,
            DIMDLI: DIMDLI,
            DIMEXE: DIMEXE,
            DIMRND: DIMRND,
            DIMDLE: DIMDLE,
            DIMTP: DIMTP,
            DIMTM: DIMTM,
            DIMTXT: DIMTXT,
            DIMCEN: DIMCEN,
            DIMTSZ: DIMTSZ,
            DIMALTF: DIMALTF,
            DIMLFAC: DIMLFAC,
            DIMTVP: DIMTVP,
            DIMTFAC: DIMTFAC,
            DIMGAP: DIMGAP,
            DIMALTRND: DIMALTRND,
            DIMTOL: DIMTOL,
            DIMLIM: DIMLIM,
            DIMTIH: DIMTIH,
            DIMTOH: DIMTOH,
            DIMSE1: DIMSE1,
            DIMSE2: DIMSE2,
            DIMTAD: DIMTAD,
            DIMZIN: DIMZIN,
            DIMAZIN: DIMAZIN,
            DIMALT: DIMALT,
            DIMALTD: DIMALTD,
            DIMTOFL: DIMTOFL,
            DIMSAH: DIMSAH,
            DIMTIX: DIMTIX,
            DIMSOXD: DIMSOXD,
            DIMCLRD: DIMCLRD,
            DIMCLRE: DIMCLRE,
            DIMCLRT: DIMCLRT,
            DIMADEC: DIMADEC,
            DIMUNIT: DIMUNIT,
            DIMDEC: DIMDEC,
            DIMTDEC: DIMTDEC,
            DIMALTU: DIMALTU,
            DIMALTTD: DIMALTTD,
            DIMAUNIT: DIMAUNIT,
            DIMFRAC: DIMFRAC,
            DIMLUNIT: DIMLUNIT,
            DIMDSEP: String.fromCharCode(DIMDSEP),
            DIMTMOVE: DIMTMOVE,
            DIMJUST: DIMJUST,
            DIMSD1: DIMSD1,
            DIMSD2: DIMSD2,
            DIMTOLJ: DIMTOLJ,
            DIMTZIN: DIMTZIN,
            DIMALTZ: DIMALTZ,
            DIMALTTZ: DIMALTTZ,
            DIMFIT: DIMFIT,
            DIMUPT: DIMUPT,
            DIMATFIT: DIMATFIT,
            DIMTXSTY: DIMTXSTY,
            DIMLDRBLK: DIMLDRBLK,
            DIMLWD: DIMLWD,
            DIMLWE: DIMLWE,
            DIMFXL: DIMFXL,
            DIMJOGANG: DIMJOGANG,
            DIMTFILL: DIMTFILL,
            DIMTFILLCLR: DIMTFILLCLR,
            DIMARCSYM: DIMARCSYM,
            DIMCLRD_N: DIMCLRD_N,
            DIMCLRE_N: DIMCLRE_N,
            DIMCLRT_N: DIMCLRT_N,
            DIMFXLON: DIMFXLON,
            DIMTXTDIRECTION: DIMTXTDIRECTION,
            DIMALTMZF: DIMALTMZF,
            DIMALTMZS: DIMALTMZS,
            DIMMZF: DIMMZF,
            DIMMZS: DIMMZS
        };
    }
    convertLayer(item, obj) {
        const libredwg = this.libredwg;
        const commonAttrs = this.getCommonTableEntryAttrs(item, obj);
        const flag = libredwg.dwg_dynapi_entity_value(item, 'flag').data;
        const frozen = libredwg.dwg_dynapi_entity_value(item, 'frozen')
            .data;
        const off = libredwg.dwg_dynapi_entity_value(item, 'off').data;
        const frozenInNew = libredwg.dwg_dynapi_entity_value(item, 'frozen_in_new')
            .data;
        const locked = libredwg.dwg_dynapi_entity_value(item, 'plotflockedlag')
            .data;
        const plotFlag = libredwg.dwg_dynapi_entity_value(item, 'plotflag')
            .data;
        const linewt = libredwg.dwg_dynapi_entity_value(item, 'linewt')
            .data;
        const color = libredwg.dwg_dynapi_entity_value(item, 'color')
            .data;
        // - 0xc0 for ByLayer (also c3 and rgb of 0x100)
        // - 0xc1 for ByBlock (also c3 and rgb of 0)
        // - 0xc2 for entities (default), with names with an additional name flag RC
        // - 0xc3 for truecolor
        // - 0xc5 for foreground color
        // - 0xc8 for none (also c3 and rgb of 0x101)
        const method = color.method;
        let colorIndex = 256;
        let rgbColor = 0xffffff;
        // NOTE: Some older DWG formats use method=0x0 and provide the ACI index via color.index.
        if (method === 0xc3 || ((color.rgb >>> 24) & 0xff) === 0xc3) {
            colorIndex = color.rgb & 0x000000ff;
        }
        else if (method == 0xc2 || ((color.rgb >>> 24) & 0xff) === 0xc2) {
            rgbColor = color.rgb & 0x00ffffff;
        }
        else if (color.index >= 1 && color.index <= 255) {
            // Older DWG format: ACI index is directly available in color.index.
            colorIndex = color.index;
        }
        return {
            ...commonAttrs,
            standardFlag: flag,
            colorIndex: colorIndex,
            color: rgbColor,
            colorName: color.name,
            transparency: color.alpha,
            lineType: '',
            frozen: frozen != 0,
            off: off != 0,
            frozenInNew: frozenInNew != 0,
            locked: locked != 0,
            plotFlag: plotFlag,
            lineweight: linewt,
            plotStyleNameObjectId: '',
            materialObjectId: ''
        };
    }
    convertLineType(item, obj) {
        const libredwg = this.libredwg;
        const commonAttrs = this.getCommonTableEntryAttrs(item, obj);
        const flag = libredwg.dwg_dynapi_entity_value(item, 'flag').data;
        const description = libredwg.dwg_dynapi_entity_value(item, 'description')
            .data;
        const numDashes = libredwg.dwg_dynapi_entity_value(item, 'numdashes')
            .data;
        const patternLen = libredwg.dwg_dynapi_entity_value(item, 'pattern_len')
            .data;
        const dashes = libredwg.dwg_dynapi_entity_value(item, 'dashes')
            .data;
        const dashArray = dashes
            ? libredwg.dwg_ptr_to_ltype_dash_array(dashes, numDashes)
            : [];
        return {
            ...commonAttrs,
            description: description,
            standardFlag: flag,
            numberOfLineTypes: numDashes,
            totalPatternLength: patternLen,
            pattern: this.convertLineTypePattern(dashArray)
        };
    }
    convertLineTypePattern(dashes) {
        const patterns = [];
        dashes.forEach(dash => {
            patterns.push({
                elementLength: dash.length || 0,
                elementTypeFlag: dash.complex_shapecode,
                shapeNumber: dash.shape_flag,
                // TODO: convert style handle to style object id
                // styleObjectId: dash.style,
                scale: dash.scale,
                rotation: dash.rotation,
                offsetX: dash.x_offset,
                offsetY: dash.y_offset,
                text: dash.text
            });
        });
        return patterns;
    }
    convertStyle(item, obj) {
        const libredwg = this.libredwg;
        const commonAttrs = this.getCommonTableEntryAttrs(item, obj);
        const standardFlag = libredwg.dwg_dynapi_entity_value(item, 'flag')
            .data;
        const widthFactor = libredwg.dwg_dynapi_entity_value(item, 'width_factor')
            .data;
        const obliqueAngle = libredwg.dwg_dynapi_entity_value(item, 'oblique_angle')
            .data;
        const textGenerationFlag = libredwg.dwg_dynapi_entity_value(item, 'generation').data;
        const lastHeight = libredwg.dwg_dynapi_entity_value(item, 'last_height')
            .data;
        const font = libredwg.dwg_dynapi_entity_value(item, 'font_file')
            .data;
        const bigFont = libredwg.dwg_dynapi_entity_value(item, 'bigfont_file')
            .data;
        return {
            ...commonAttrs,
            standardFlag: standardFlag,
            fixedTextHeight: 0, // TODO: Set the correct value
            widthFactor: widthFactor,
            obliqueAngle: obliqueAngle,
            textGenerationFlag: textGenerationFlag,
            lastHeight: lastHeight,
            font: font,
            bigFont: bigFont
        };
    }
    convertViewport(item, obj) {
        const libredwg = this.libredwg;
        const commonAttrs = this.getCommonTableEntryAttrs(item, obj);
        const standardFlag = libredwg.dwg_dynapi_entity_value(item, 'flag')
            .data;
        const viewHeight = libredwg.dwg_dynapi_entity_value(item, 'VIEWSIZE')
            .data;
        // BITCODE_BD view_width;   // in DWG r13+, needed to calc. aspect_ratio
        // BITCODE_BD aspect_ratio; // DXF 41 = view_width / VIEWSIZE
        const center = libredwg.dwg_dynapi_entity_value(item, 'VIEWCTR')
            .data;
        const viewTarget = libredwg.dwg_dynapi_entity_value(item, 'view_target')
            .data;
        const viewDirectionFromTarget = libredwg.dwg_dynapi_entity_value(item, 'VIEWDIR').data;
        const viewTwistAngle = libredwg.dwg_dynapi_entity_value(item, 'view_twist')
            .data;
        const lensLength = libredwg.dwg_dynapi_entity_value(item, 'lens_length')
            .data;
        const frontClippingPlane = libredwg.dwg_dynapi_entity_value(item, 'front_clip_z').data;
        const backClippingPlane = libredwg.dwg_dynapi_entity_value(item, 'back_clip_z').data;
        const viewMode = libredwg.dwg_dynapi_entity_value(item, 'VIEWMODE')
            .data;
        const renderMode = libredwg.dwg_dynapi_entity_value(item, 'render_mode')
            .data;
        const isDefaultLightingOn = libredwg.dwg_dynapi_entity_value(item, 'use_default_lights')
            .data != 0;
        const defaultLightningType = libredwg.dwg_dynapi_entity_value(item, 'default_lightning_type').data;
        const brightness = libredwg.dwg_dynapi_entity_value(item, 'brightness')
            .data;
        const contrast = libredwg.dwg_dynapi_entity_value(item, 'contrast')
            .data;
        const ambient_color = libredwg.dwg_dynapi_entity_value(item, 'ambient_color').data;
        // ViewportTableRecord
        const lowerLeftCorner = libredwg.dwg_dynapi_entity_value(item, 'lower_left')
            .data;
        const upperRightCorner = libredwg.dwg_dynapi_entity_value(item, 'upper_right').data;
        // TODO: Not sure whether 'circleSides' is equal to 'circle_zoom'
        const circleSides = libredwg.dwg_dynapi_entity_value(item, 'circle_zoom')
            .data;
        const ucsIconSetting = libredwg.dwg_dynapi_entity_value(item, 'UCSICON')
            .data;
        // TODO: Not sure whether 'gridSpacing' is equal to 'GRIDUNIT'
        const gridSpacing = libredwg.dwg_dynapi_entity_value(item, 'GRIDUNIT')
            .data;
        const snapRotationAngle = libredwg.dwg_dynapi_entity_value(item, 'SNAPANG')
            .data;
        const snapBasePoint = libredwg.dwg_dynapi_entity_value(item, 'SNAPBASE')
            .data;
        // TODO: Not sure whether 'snapSpacing' is equal to 'SNAPUNIT'
        const snapSpacing = libredwg.dwg_dynapi_entity_value(item, 'SNAPUNIT')
            .data;
        const ucsOrigin = libredwg.dwg_dynapi_entity_value(item, 'ucsorg')
            .data;
        const ucsXAxis = libredwg.dwg_dynapi_entity_value(item, 'ucsxdir')
            .data;
        const ucsYAxis = libredwg.dwg_dynapi_entity_value(item, 'ucsydir')
            .data;
        const elevation = libredwg.dwg_dynapi_entity_value(item, 'ucs_elevation')
            .data;
        const majorGridLines = libredwg.dwg_dynapi_entity_value(item, 'grid_major')
            .data;
        const background = libredwg.dwg_dynapi_entity_value(item, 'background')
            .data;
        const backgroundObjectId = background
            ? idToString(libredwg.dwg_ref_get_absref(background))
            : undefined;
        const visualstyle = libredwg.dwg_dynapi_entity_value(item, 'visualstyle')
            .data;
        const visualStyleObjectId = visualstyle
            ? idToString(libredwg.dwg_ref_get_absref(visualstyle))
            : undefined;
        // BITCODE_B UCSFOLLOW;
        // BITCODE_B FASTZOOM;
        // BITCODE_B GRIDMODE;     /* DXF 76: on or off */
        // BITCODE_B SNAPMODE;     /* DXF 75: on or off */
        // BITCODE_B SNAPSTYLE;
        // BITCODE_BS SNAPISOPAIR;
        // BITCODE_B ucs_at_origin;
        // BITCODE_B UCSVP;
        // BITCODE_BS UCSORTHOVIEW;
        // BITCODE_BS grid_flags; /* bit 1: bound to limits, bit 2: adaptive */
        // BITCODE_H sun;
        // BITCODE_H named_ucs;
        // BITCODE_H base_ucs;
        return {
            ...commonAttrs,
            standardFlag: standardFlag,
            lowerLeftCorner: lowerLeftCorner,
            upperRightCorner: upperRightCorner,
            center: center,
            snapBasePoint: snapBasePoint,
            snapSpacing: snapSpacing,
            gridSpacing: gridSpacing,
            viewDirectionFromTarget: viewDirectionFromTarget,
            viewTarget: viewTarget,
            lensLength: lensLength,
            frontClippingPlane: frontClippingPlane,
            backClippingPlane: backClippingPlane,
            viewHeight: viewHeight,
            snapRotationAngle: snapRotationAngle,
            viewTwistAngle: viewTwistAngle,
            circleSides: circleSides,
            frozenLayers: [], // TODO: Set the correct value
            styleSheet: '', // TODO: Set the correct value
            renderMode: renderMode,
            viewMode: viewMode,
            ucsIconSetting: ucsIconSetting,
            ucsOrigin: ucsOrigin,
            ucsXAxis: ucsXAxis,
            ucsYAxis: ucsYAxis,
            orthographicType: 0, // TODO: Set the correct value
            elevation: elevation,
            shadePlotSetting: 0, // TODO: Set the correct value
            majorGridLines: majorGridLines,
            backgroundObjectId: backgroundObjectId,
            // shadePlotObjectId: undefined,
            visualStyleObjectId: visualStyleObjectId,
            isDefaultLightingOn: isDefaultLightingOn,
            defaultLightingType: defaultLightningType,
            brightness: brightness,
            contrast: contrast,
            // TODO: Not sure whether 'index' or 'rgb' should be used
            ambientColor: ambient_color.index
        };
    }
    getCommonTableEntryAttrs(tio, obj) {
        const libredwg = this.libredwg;
        const object_tio = libredwg.dwg_object_get_tio(obj);
        const ownerhandle = libredwg.dwg_object_object_get_ownerhandle_object(object_tio);
        const handle = libredwg.dwg_object_get_handle_object(obj);
        return {
            handle: idToString(handle.value),
            ownerHandle: idToString(ownerhandle.absolute_ref),
            name: libredwg.dwg_dynapi_entity_value(tio, 'name').data
        };
    }
    convertDictionary(item, obj) {
        const libredwg = this.libredwg;
        const commonAttrs = this.getCommonObjectAttrs(obj);
        const isHardOwner = libredwg.dwg_dynapi_entity_value(item, 'is_hardowner')
            .data;
        const cloningFlag = libredwg.dwg_dynapi_entity_value(item, 'cloning')
            .data;
        const numitems = libredwg.dwg_dynapi_entity_value(item, 'numitems')
            .data;
        const itemhandles_ptr = libredwg.dwg_dynapi_entity_value(item, 'itemhandles').data;
        const itemhandles = libredwg.dwg_ptr_to_object_ref_array(itemhandles_ptr, numitems);
        const texts = libredwg.dwg_object_dictionary_get_texts(obj);
        const entries = {};
        itemhandles.forEach((handle, index) => (entries[texts[index]] = idToString(handle.absolute_ref)));
        return {
            ...commonAttrs,
            isHardOwner: !!isHardOwner,
            cloningFlag: cloningFlag,
            entries: entries
        };
    }
    convertImageDef(item, obj) {
        const libredwg = this.libredwg;
        const commonAttrs = this.getCommonObjectAttrs(obj);
        // const classVersion = libredwg.dwg_dynapi_entity_value(item, 'class_version').data as number
        const size = libredwg.dwg_dynapi_entity_value(item, 'image_size')
            .data;
        const fileName = libredwg.dwg_dynapi_entity_value(item, 'file_path')
            .data;
        const isLoaded = libredwg.dwg_dynapi_entity_value(item, 'is_loaded')
            .data;
        const sizeOfOnePixel = libredwg.dwg_dynapi_entity_value(item, 'pixel_size')
            .data;
        const resolutionUnits = libredwg.dwg_dynapi_entity_value(item, 'resunits')
            .data;
        return {
            ...commonAttrs,
            fileName: fileName,
            size: size,
            sizeOfOnePixel: sizeOfOnePixel,
            isLoaded: isLoaded,
            resolutionUnits: resolutionUnits
        };
    }
    convertLayout(item, obj) {
        const libredwg = this.libredwg;
        const commonAttrs = this.getCommonObjectAttrs(obj);
        // AcDbLayout
        const layoutName = libredwg.dwg_dynapi_entity_value(item, 'layout_name')
            .data;
        const tabOrder = libredwg.dwg_dynapi_entity_value(item, 'tab_order')
            .data;
        const controlFlag = libredwg.dwg_dynapi_entity_value(item, 'layout_flags')
            .data;
        const insertionPoint = libredwg.dwg_dynapi_entity_value(item, 'INSBASE')
            .data;
        const minLimit = libredwg.dwg_dynapi_entity_value(item, 'LIMMIN')
            .data;
        const maxLimit = libredwg.dwg_dynapi_entity_value(item, 'LIMMAX')
            .data;
        const ucsOrigin = libredwg.dwg_dynapi_entity_value(item, 'UCSORG')
            .data;
        const ucsXAxis = libredwg.dwg_dynapi_entity_value(item, 'UCSXDIR')
            .data;
        const ucsYAxis = libredwg.dwg_dynapi_entity_value(item, 'UCSYDIR')
            .data;
        const orthographicType = libredwg.dwg_dynapi_entity_value(item, 'UCSORTHOVIEW').data;
        const minExtent = libredwg.dwg_dynapi_entity_value(item, 'EXTMIN')
            .data;
        const maxExtent = libredwg.dwg_dynapi_entity_value(item, 'EXTMAX')
            .data;
        const elevation = libredwg.dwg_dynapi_entity_value(item, 'ucs_elevation')
            .data;
        const block_header_ref = libredwg.dwg_dynapi_entity_value(item, 'block_header').data;
        const paperSpaceTableId = idToString(libredwg.dwg_ref_get_absref(block_header_ref));
        const active_viewport_ref = libredwg.dwg_dynapi_entity_value(item, 'active_viewport').data;
        const viewportId = idToString(libredwg.dwg_ref_get_absref(active_viewport_ref));
        const named_ucs_ref = libredwg.dwg_dynapi_entity_value(item, 'named_ucs')
            .data;
        const namedUcsId = !!named_ucs_ref
            ? idToString(libredwg.dwg_ref_get_absref(named_ucs_ref))
            : undefined;
        // BITCODE_H base_ucs;
        // BITCODE_BL num_viewports; // r2004+
        // BITCODE_H *viewports;     // r2004+
        return {
            ...commonAttrs,
            layoutName: layoutName,
            controlFlag: controlFlag,
            tabOrder: tabOrder,
            minLimit: minLimit,
            maxLimit: maxLimit,
            insertionPoint: insertionPoint,
            minExtent: minExtent,
            maxExtent: maxExtent,
            elevation: elevation,
            ucsOrigin: ucsOrigin,
            ucsXAxis: ucsXAxis,
            ucsYAxis: ucsYAxis,
            orthographicType: orthographicType,
            paperSpaceTableId: paperSpaceTableId,
            viewportId: viewportId,
            namedUcsId: namedUcsId,
            // orthographicUcsId?: string;
            shadePlotId: '' // TODO: Set the correct value
        };
    }
    convertSpatialFilter(item, obj) {
        const libredwg = this.libredwg;
        const commonAttrs = this.getCommonObjectAttrs(obj);
        const origin = libredwg.dwg_dynapi_entity_value(item, 'origin')
            .data;
        const numberOfPointsOnClipBoundary = libredwg.dwg_dynapi_entity_value(item, 'num_clip_verts').data;
        const clip_verts_ptr = libredwg.dwg_dynapi_entity_value(item, 'clip_verts')
            .data;
        const vertices = libredwg.dwg_ptr_to_point2d_array(clip_verts_ptr, numberOfPointsOnClipBoundary);
        const extrusionDirection = libredwg.dwg_dynapi_entity_value(item, 'extrusion').data;
        const clipBoundaryVisible = libredwg.dwg_dynapi_entity_value(item, 'display_boundary_on').data;
        const frontClippingPlaneFlag = libredwg.dwg_dynapi_entity_value(item, 'front_clip_on').data;
        const frontClippingPlaneDistance = libredwg.dwg_dynapi_entity_value(item, 'front_clip_z').data;
        const backClippingPlaneFlag = libredwg.dwg_dynapi_entity_value(item, 'back_clip_on').data;
        const backClippingPlaneDistance = libredwg.dwg_dynapi_entity_value(item, 'back_clip_z').data;
        const transform_ptr = libredwg.dwg_dynapi_entity_value(item, 'transform')
            .data;
        const matrix = libredwg.dwg_ptr_to_double_array(transform_ptr, 12);
        const inverse_transform_ptr = libredwg.dwg_dynapi_entity_value(item, 'inverse_transform').data;
        const invertBlockMatrix = libredwg.dwg_ptr_to_double_array(inverse_transform_ptr, 12);
        return {
            ...commonAttrs,
            origin: origin,
            numberOfPointsOnClipBoundary: numberOfPointsOnClipBoundary,
            vertices: vertices,
            extrusionDirection: extrusionDirection,
            clipBoundaryVisible: !!clipBoundaryVisible,
            frontClippingPlaneFlag: !!frontClippingPlaneFlag,
            frontClippingPlaneDistance: frontClippingPlaneDistance,
            backClippingPlaneFlag: !!backClippingPlaneFlag,
            backClippingPlaneDistance: backClippingPlaneDistance,
            matrix: matrix,
            invertBlockMatrix: invertBlockMatrix
        };
    }
    getCommonObjectAttrs(obj) {
        const libredwg = this.libredwg;
        const object_tio = libredwg.dwg_object_get_tio(obj);
        const ownerhandle = libredwg.dwg_object_object_get_ownerhandle_object(object_tio);
        const handle = libredwg.dwg_object_get_handle_object(obj);
        return {
            handle: idToString(handle.value),
            ownerHandle: idToString(ownerhandle.absolute_ref)
        };
    }
}
//# sourceMappingURL=converter.js.map