Skip to main content
Version: v5.0

Model File Reader

The ModelFileReader provides the APIs to download, unzip and stream a model file. It also supports file uploads that are related to the model import process.

ModelFileReader methods

The ModelFileReader provides the following methods for handling model files:

downloadAndUnzipModelFile

This method downloads the model file and unzips its content. This method requires the parameters of file ID, file version ID, file name, extension, orchestrator run ID, and context.

On execution, this method will download and unzip the model file. It will then return the file path and manifest details of the model.

getModelBatchlet

This method provides the model information in streams. It expects an occurrence file path and orchestrator run ID. If this method is called with a new path it will start streaming it. If the method is called with an existing file path then it will resume the stream from where it has left off.

uploadSmallFile

UploadSmallFile is used for uploading files where the file size does not exceed 25 MB.

This method expects a file path and context details.

uploadLargeFile

UploadLargeFile is used for uploading files where the file size exceeds 25 MB.

This method expects a file path and context details.

How to use the ModelFileReader

Importing a model file

To import a model file, do the following:

  1. First upload a zip file of the model into the system.

  2. Now you need to set up an orchestrator in the DataSources Service. In version 4.3, the orchestrator only requires one step to import the model into the system. To do this, refer to the sample code below.

{
"_name": "BIMPK Model Import",
"_description": "BIMPK Model Import",
"_namespaces": ["namespace”],
"_userType": "bimpk_importer",
"_params": {
"tasks": [
{
"name": "default_script_target",
"_actualparams": {
"userType": "iaf_import_model",
"_scriptName": "importModel"
},
"_sequenceno": 1
}
]
}
}

  1. The target script was modified as the model file download, extraction, streaming and processing were all bundled together into a single script. In the orchestrator, check that a record has been created like the sample one below.
{
"id": "ffff8a53-2a59-4625-9bfb-7be9ab2ed05e",
"_name": "BIMPK Model Import",
"_description": "BIMPK Model Import",
"_namespaces": ["namespace”]",
"_userType": "bimpk_importer",
"_class": "NORMAL",
"_createdby": "8c086a82-f9d5-4f23-b4b3-503e21b6c6cf",
"_createdat": "1717684358331",
"_updatedby": "8c086a82-f9d5-4f23-b4b3-503e21b6c6cf",
"_updatedat": "1717684358331",
"_timeout": "2 * *",
"_permissionprofileid": null,
"orchsteps": [
{
"id": "fc3ce160-0878-41e3-b9e4-336f5d61528b",
"_compid": "ee4dc2bd-af76-41fe-9596-c286a14558b0",
"_orchid": "ffff8a53-2a59-4625-9bfb-7be9ab2ed05e",
"_actualparams": "{\"userType\":\"iaf_import_model\",\"_scriptName\":\"importModel\"}",
"_sequenceno": 1,
"_name": "default_script_target",
"_orchcomp": "default_script_target"
}
]
}
  1. The orchestrator ID can now be used. Create an orchestrator run to trigger the import process. The orchestrator run will have the orchestrator ID, model file ID, and file version ID. See sample code below.

Note that the sequence ID in the required code body shown below should be the ID of the default_script_target

{
"orchestratorId": "ffff8a53-2a59-4625-9bfb-7be9ab2ed05e",
"_actualparams": [
{
"sequence_type_id": "ee4dc2bd-af76-41fe-9596-c286a14558b0",
"params": {
"_fileId": "3b93fb21-f4b6-4da9-9f6b-e354d6288631",
"_fileVersionId": "53d0d1ff-2663-4ecf-805a-f36458dbbc3d"
}
}
]
}
  1. Once you trigger the orchestrator run, it will be queued and picked up by the DataSources Service. Once you create an orchestrator run, the response should be similar to the output shown below.
{
"id": "3dc8f2f0-d65a-41d5-838a-bf5bb54ba20d",
"_orchid": "ffff8a53-2a59-4625-9bfb-7be9ab2ed05e",
"_name": "BIMPK Importer",
"_description": "BIMPK Importer",
"_namespaces": ["namespace"],
"_usertype": "bimpk_importer",
"_createdby": "8c086a82-f9d5-4f23-b4b3-503e21b6c6cf",
"_createdat": "1718360339788",
"_updatedat": "1718360339788",
"_timeoutdat": null,
"_status": "QUEUED",
"_result": "",
"orchrunsteps": [
{
"id": "319a0db7-393a-49bf-922e-146399be34a0",
"_name": "default_script_target",
"orchstepid": "fc3ce160-0878-41e3-b9e4-336f5d61528b",
"_compid": "ee4dc2bd-af76-41fe-9596-c286a14558b0",
"_orchrunid": "3dc8f2f0-d65a-41d5-838a-bf5bb54ba20d",
"_actualparams": "{\"userType\":\"iaf_import_model\",\"_scriptName\":\"importModel\",\"_fileId\":\"3b93fb21-f4b6-4da9-9f6b-e354d6288631\",\"_fileVersionId\":\"53d0d1ff-2663-4ecf-805a-f36458dbbc3d\"}",
"_sequenceno": 1,
"_runparams": "{}",
"_status": "QUEUED",
"_statusmsg": ""
}
]
}

Detailed example of import script

Refer to the listing of a sample import script below.

class InputValidation {
constructor(params, libraries, ctx) {
this.params = params
this.libraries = libraries
this.ctx = ctx
}

async validate() {
return new Promise(async (resolve, reject) => {
try {
console.log(`Executing validate method, orchrun_id: ${this.params.orchRunId}`)
this.#validateFileDetails()

if (await this.#modelExists()) {
console.log(`Model Imported already, Please remove existing import and try again, orch_run_id: ${this.params.orchRunId}`)

throw new Error('Model Imported already, Please remove existing import and try again')
}

console.log(`Basic input validation completed, orchrun_id: ${this.params.orchRunId}`)

resolve(true)
} catch (error) {
console.log(`Error at validate method, orchrun_id: ${this.params.orchRunId}`, error)

reject(error)
}
})
}

#validateFileDetails() {
if (!this.params.actualParams._fileId)
throw new Error('Invalid Parameters - _fileId is Invalid')
if (!this.params.actualParams._fileVersionId)
throw new Error('Invalid Parameters - _fileVersionId is Invalid')
if(this.params.ext != 'bimpk' && this.params.ext != 'sgpk')
throw new Error('Invalid model file extension')
}

async #modelExists() {
return new Promise(async (resolve, reject) => {
try {
const { PlatformApi } = this.libraries
const fileIdAttribute = `_versions._userAttributes.${this.params.ext}.fileId`
const fileVersionIdAttribute = `_versions._userAttributes.${this.params.ext}.fileVersionId`
const criteria = {
query: {
[fileIdAttribute]: this.params.actualParams._fileId,
[fileVersionIdAttribute]: this.params.actualParams._fileVersionId,
'_versions.all': true,
}
}
const project = { _namespaces: this.ctx._namespaces }

const models = await PlatformApi.IafProj.getModels(project, criteria, this.ctx)
const doesExist = models ? models.length > 0 : false

resolve(doesExist)
} catch (error) {
console.log(`Error at modelExists method, orchrun_id: ${this.params.orchRunId}`, error)

reject(error)
}
})
}
}

class BimpkImport {
#assetTypeMap = null;
#propMap;
#typeMap;

constructor(params, libraries, ctx) {
this.params = params
this.libraries = libraries
this.ctx = ctx
}

async initialize() {
return new Promise(async (resolve, reject) => {
try {
console.log(`Bimpk import initialized, orch_run_id: ${this.params.orchRunId}`)
const { PlatformApi, IafScriptEngine, ModelFileReader } = this.libraries;
const { IafItemSvc } = PlatformApi
let param = { ...this.params.actualParams, filename: this.params.filename, ext: this.params.ext, orchRunId: this.params.orchRunId }

// set global variables first
await Promise.all([
IafScriptEngine.setVar("namespaces", this.ctx._namespaces),
IafScriptEngine.setVar("package_name", param.filename),
IafScriptEngine.setVar("package_name_short", param.filename.substring(0, 11)),
IafScriptEngine.setVar("bimpk_fileid", param._fileId),
IafScriptEngine.setVar("bimpk_fileVersionId", param._fileVersionId)
])

const { _list = [] } = await IafItemSvc.getNamedUserItems(
{
"query": {
"_userType": "bim_model_version",
"_versions._userAttributes.bimpk.fileId": param._fileId,
"_itemClass":"NamedCompositeItem"
}
},
this.ctx,
{}
) || {};
const bim_model = _list[0];

if (bim_model) {
await IafScriptEngine.setVar("bim_model", bim_model);
}

console.log(`bim_model, orch_run_id: ${this.params.orchRunId}`, bim_model)

const { bimFilePath, manifest } = await ModelFileReader.downloadAndUnzipModelFile(param, ctx)
const { files, occurrences } = manifest
const fileLength = files.length - 1;
let index = -1;

if (bim_model) {
console.time(`${this.params.orchRunId}: createBIMCollectionVersion`)
await this.#createBIMCollectionVersion();
console.timeEnd(`${this.params.orchRunId}: createBIMCollectionVersion`)
} else {
console.time(`${this.params.orchRunId}: createBIMCollections`)
await this.#createBIMCollections();
console.timeEnd(`${this.params.orchRunId}: createBIMCollections`)
}

const [
{ _id: bimModelId },
model_els_coll,
model_els_props_coll,
model_type_el_coll,
data_cache_coll,
model_geom_file_coll,
model_geom_views_coll
] = await Promise.all([
IafScriptEngine.getVar("bim_model"),
IafScriptEngine.getVar("model_els_coll"),
IafScriptEngine.getVar("model_els_props_coll"),
IafScriptEngine.getVar("model_type_el_coll"),
IafScriptEngine.getVar("data_cache_coll"),
IafScriptEngine.getVar("model_geom_file_coll"),
IafScriptEngine.getVar("model_geom_views_coll")
])

const relatedCollections = [
model_els_coll._userItemId,
model_els_props_coll._userItemId,
model_type_el_coll._userItemId,
data_cache_coll._userItemId,
model_geom_file_coll._userItemId,
model_geom_views_coll._userItemId
]

console.log(`RelatedCollections, orch_run_id: ${this.params.orchRunId}`, relatedCollections)

await IafScriptEngine.addRelatedCollections({
"namedCompositeItemId": bimModelId,
"relatedCollections": relatedCollections
}, ctx);

const myCols = {
model_els_coll,
model_els_props_coll,
model_type_el_coll,
data_cache_coll,
model_geom_file_coll,
model_geom_views_coll
}

try {
this.#assetTypeMap = await IafScriptEngine.getItems({
collectionDesc: {
_userType: 'iaf_dt_type_map_defs_coll',
_namespaces: this.ctx._namespaces
},
options: {
page: { getAllItems: true }
}
}, this.ctx)
console.log(`Asset map type received, orch_run_id: ${this.params.orchRunId} `, typeof this.#assetTypeMap)
} catch (err) {
console.log(`Type Map collection does not exist, orch_run_id: ${this.params.orchRunId}`)
}

for (const model of files) {
index += 1;
// find occurances
let occs = occurrences.filter(d => d.source === model.id)

if(!occs?.length) {
console.warn(`Warning: Occurrences missing for model: ${model.id}, orch_run_id: ${this.params.orchRunId}`)
occs = []
}

for (const occ of occs) {
const filePath = bimFilePath + '/' + occ.data.objects
let newOccurrence = true
let letsLoop = true

while(letsLoop) {
console.log(`Requesting bimpk batchlet, orch_run_id: ${this.params.orchRunId}`)

console.time(`${this.params.orchRunId}: getModelBatchlet`)
const { bimBatch, endOfFile } = await ModelFileReader.getModelBatchlet(filePath, this.params.orchRunId)
console.log(`Bim batchlet received: ${bimBatch?.objects?.length}, orch_run_id: ${this.params.orchRunId}`)
console.timeEnd(`${this.params.orchRunId}: getModelBatchlet`)

console.time(`${this.params.orchRunId}: extractBimpk`)
await this.#extractBimpk(model.name, bimBatch, newOccurrence)
console.timeEnd(`${this.params.orchRunId}: extractBimpk`)

console.time(`${this.params.orchRunId}: createRelatedItemsAndRelationships`)
await this.#createRelatedItemsAndRelationships(newOccurrence, myCols)
console.timeEnd(`${this.params.orchRunId}: createRelatedItemsAndRelationships`)

newOccurrence = false

if(endOfFile) break
}
}

if(fileLength === index) {
const result = {
filecolid: myCols.model_geom_file_coll._userItemId,
viewcolid: myCols.model_geom_views_coll._userItemId,
compositeitemid: bimModelId,
myCollections: myCols,
filename: param.filename,
_fileId: param._fileId,
_fileVersionId: param._fileVersionId,
bimFilePath,
manifest
}

await IafScriptEngine.clearVars();

return resolve(result)
}
}
} catch (error) {
reject(error)
}
})
}

async #createBIMCollectionVersion() {
return new Promise(async (resolve, reject) => {
try {
console.log(`Found Previous Model Creating Versions, orch_run_id: ${this.params.orchRunId}`);
const { IafScriptEngine } = this.libraries;
const [ bimModel, bimpkFileId, bimpkFileVersionId, packagename, packagenameShort ] = await Promise.all([
IafScriptEngine.getVar("bim_model"),
IafScriptEngine.getVar("bimpk_fileid"),
IafScriptEngine.getVar("bimpk_fileVersionId"),
IafScriptEngine.getVar('package_name'),
IafScriptEngine.getVar('package_name_short')
])
const newModelVer = {
namedUserItemId: bimModel._id,
_userAttributes: {
bimpk: {
fileId: bimpkFileId,
fileVersionId: bimpkFileVersionId
}
}
}
console.log(`Getting collections in composite, bim-model-id: ${bimModel._id}, orch_run_id: ${this.params.orchRunId}`, newModelVer);

const [modelRelatedCollection] = await Promise.all([
IafScriptEngine.getCollectionsInComposite(bimModel._id, null, this.ctx),
IafScriptEngine.createNamedUserItemVersion(newModelVer, this.ctx)
])

console.log(`modelRelatedCollection, orch_run_id: ${this.params.orchRunId}`, modelRelatedCollection)
console.log(`Created BIM Collection Version bim_model version, orch_run_id: ${this.params.orchRunId}`);

let model_els_coll, model_els_props_coll, model_type_el_coll, model_geom_file_coll, model_geom_views_coll, data_cache_coll;

for (const obj of modelRelatedCollection) {
if(obj._userType === 'rvt_elements' && !model_els_coll) {
model_els_coll = obj
}else if(obj._userType === 'rvt_element_props' && !model_els_props_coll) {
model_els_props_coll = obj
}else if(obj._userType === 'rvt_type_elements' && !model_type_el_coll) {
model_type_el_coll = obj
}else if(obj._userType === 'bim_model_geomresources' && !model_geom_file_coll) {
model_geom_file_coll = obj
}else if(obj._userType === 'bim_model_geomviews' && !model_geom_views_coll) {
model_geom_views_coll = obj
}else if(obj._userType === 'data_cache' && !data_cache_coll) {
data_cache_coll = obj
}
}

if (!data_cache_coll) {
const data_cache_coll_def = {
_name: packagename + '_data_cache',
_shortName: packagenameShort + '_data_cache',
_description: 'Data cached about imported model',
_userType: 'data_cache',
_namespaces: this.ctx._namespaces
}

data_cache_coll = await IafScriptEngine.createCollection(data_cache_coll_def, this.ctx);

console.log(`Created Model Data Cache, orch_run_id: ${this.params.orchRunId}`);
}

console.log(`Created Model versions, orch_run_id: ${this.params.orchRunId}`);
// create the versions
await Promise.all([
IafScriptEngine.createNamedUserItemVersion({ "namedUserItemId": model_els_coll._userItemId }, this.ctx),
IafScriptEngine.createNamedUserItemVersion({ "namedUserItemId": model_els_props_coll._userItemId }, this.ctx),
IafScriptEngine.createNamedUserItemVersion({ "namedUserItemId": model_type_el_coll._userItemId }, this.ctx),
IafScriptEngine.createNamedUserItemVersion({ "namedUserItemId": data_cache_coll._userItemId }, this.ctx),
IafScriptEngine.createNamedUserItemVersion({ "namedUserItemId": model_geom_file_coll._userItemId }, this.ctx),
IafScriptEngine.createNamedUserItemVersion({ "namedUserItemId": model_geom_views_coll._userItemId }, this.ctx)
])

// set them in global variables
await Promise.all([
IafScriptEngine.setVar("model_els_coll", model_els_coll),
IafScriptEngine.setVar("model_els_props_coll", model_els_props_coll),
IafScriptEngine.setVar("model_type_el_coll", model_type_el_coll),
IafScriptEngine.setVar("data_cache_coll", data_cache_coll),
IafScriptEngine.setVar("model_geom_file_coll", model_geom_file_coll),
IafScriptEngine.setVar("model_geom_views_coll", model_geom_views_coll)
])

const elemCollIndex = {
"_id": model_els_coll._userItemId,
indexDefs: [
{
key: { "id": 1 },
options: {
name: "model_els_coll_id",
default_language: "english"
}
},
{
key: { "source_id": 1 },
options: {
name: "model_els_coll_source_id",
default_language: "english"
}
}
]
};

const typeElemCollIndex = {
"_id": model_type_el_coll._userItemId,
indexDefs: [
{
key: { "id": 1 },
options: {
name: "typeElemsCol_id",
default_language: "english"
}
},
{
key: { "source_id": 1},
options: {
name: "typeElemsCol_source_id",
default_language: "english"
}
}
]
}

await Promise.all([
IafScriptEngine.createOrRecreateIndex(elemCollIndex, this.ctx),
IafScriptEngine.createOrRecreateIndex(typeElemCollIndex, this.ctx)
])

resolve(true)
}catch(error) {
console.log('Error at createBIMCollectionVersion')
console.error(error)

reject(error)
}
})
}

async #createBIMCollections () {
return new Promise(async (resolve, reject) => {
try {
const { IafScriptEngine } = this.libraries;

console.log(`Creating Model Collections, orch_run_id: ${this.params.orchRunId}`);
const [ packagename, packagenameShort, bimpkFileId, bimpkFileVersionId ] = await Promise.all([
IafScriptEngine.getVar("package_name"),
IafScriptEngine.getVar("package_name_short"),
IafScriptEngine.getVar("bimpk_fileid"),
IafScriptEngine.getVar("bimpk_fileVersionId")
])

console.log(`packagename: ${packagename}, packagenameShort: ${packagenameShort} orch_run_id: ${this.params.orchRunId}`)
//create Elements Collection
const elementsCol = {
"_name": packagename + "_elements",
"_shortName": packagenameShort + "_ba_elem",
"_description": "Elements in BA model",
"_userType": "rvt_elements",
"_namespaces": this.ctx._namespaces
}

//create Element Properties Collection
const modelElemPropsCol = {
_name: packagename + '_elem_props',
_shortName: packagenameShort + '_elprops',
_description: 'Element Props in BA model',
_userType: 'rvt_element_props',
_namespaces: this.ctx._namespaces
}

//create Type Elements Collection
const typeElemsCol = {
_name: packagename + '_type_el',
_shortName: packagenameShort + '_type_el',
_description: 'Type Elements in BA Check model',
_userType: 'rvt_type_elements',
_namespaces: this.ctx._namespaces
}

//create Geometry File Collection
const geometryFilesCol = {
"_name": packagename + "_geom_file",
"_shortName": packagenameShort + "_geom_file",
"_description": "File Collection for Geometry Files",
"_userType": "bim_model_geomresources",
"_namespaces": this.ctx._namespaces
}

//create Geometry View Collection
const geometryViewsCol = {
"_name": packagename + "_geom_view",
"_shortName": packagenameShort + "_geom_view",
"_description": "Geometry Views in Model",
"_userType": "bim_model_geomviews",
"_namespaces": this.ctx._namespaces
}

//create Model Data Cache Collection
const dataCacheCol = {
"_name": packagename + "_data_cache",
"_shortName": packagenameShort + "_data_cache",
"_description": "Data cached about imported model",
"_userType": "data_cache",
"_namespaces": this.ctx._namespaces
}

//create Model Composite Item
const modelCompItem = {
"_name": packagename,
"_shortName": packagenameShort + "_modelver",
"_description": "BIM model version by transform",
"_userType": "bim_model_version",
"_namespaces": this.ctx._namespaces,
"_version": {
"_userAttributes": {
"bimpk": {
"fileId": bimpkFileId,
"fileVersionId": bimpkFileVersionId
}
}
}
}
console.log(`modelCompItem, orch_run_id: ${this.params.orchRunId}`, modelCompItem)

const [
model_els_coll, model_els_props_coll, model_type_el_coll, model_geom_file_coll, model_geom_views_coll, data_cache_coll, model
] = await Promise.all([
IafScriptEngine.createCollection(elementsCol, this.ctx),
IafScriptEngine.createCollection(modelElemPropsCol, this.ctx),
IafScriptEngine.createCollection(typeElemsCol, this.ctx),
IafScriptEngine.createCollection(geometryFilesCol, this.ctx),
IafScriptEngine.createCollection(geometryViewsCol, this.ctx),
IafScriptEngine.createCollection(dataCacheCol, this.ctx),
IafScriptEngine.createNamedCompositeItem(modelCompItem, this.ctx)

])

// set them in global variables
await Promise.all([
IafScriptEngine.setVar("model_els_coll", model_els_coll),
IafScriptEngine.setVar("model_els_props_coll", model_els_props_coll),
IafScriptEngine.setVar("model_type_el_coll", model_type_el_coll),
IafScriptEngine.setVar("model_geom_file_coll", model_geom_file_coll),
IafScriptEngine.setVar("model_geom_views_coll", model_geom_views_coll),
IafScriptEngine.setVar("data_cache_coll", data_cache_coll),
IafScriptEngine.setVar("bim_model", model)
])

const elemCollIndex = {
"_id": model_els_coll._userItemId,
indexDefs: [
{
key: { "id": 1 },
options: {
name: "model_els_coll_id",
default_language: "english"
}
},
{
key: { "source_id": 1 },
options: {
name: "model_els_coll_source_id",
default_language: "english"
}
}
]
};
const typeElemCollIndex = {
"_id": model_type_el_coll._userItemId,
indexDefs: [
{
key: { "id": 1 },
options: {
name: "typeElemsCol_id",
default_language: "english"
}
},
{
key: { "source_id": 1 },
options: {
name: "typeElemsCol_source_id",
default_language: "english"
}
}
]
}
console.log(`Create or recreate index, orch_run_id: ${this.params.orchRunId}`);

await Promise.all([
await IafScriptEngine.createOrRecreateIndex(elemCollIndex, this.ctx),
await IafScriptEngine.createOrRecreateIndex(typeElemCollIndex, this.ctx)
])

resolve(true)
}catch(error) {
console.log(`Error at createBIMCollections, orch_run_id: ${this.params.orchRunId}`)
console.error(error)

reject(error)
}
})
}

async #extractBimpk (fileName, bimBatch, newOccurrence) {
return new Promise(async (resolve, reject) => {
try {
console.log(`Executing extract Bimpk function, orch_run_id: ${this.params.orchRunId}`);
const { IafScriptEngine } = this.libraries;

// Extract data
const objects = []
let types = []

for(const obj of bimBatch.objects) {
if(objects.length === 0) {
console.log(obj)
console.log(obj, this.params.orchRunId)
console.log(`Bimbatch: typeof package_id: ${typeof obj.id}, typeof type_id: ${typeof obj.type}, orch_run_id: ${this.params.orchRunId}`);

}
objects.push({
"package_id": obj.id,
"type_id": obj.type,
"relationships": obj.relationships,
"source_id": obj.sourceId,
"properties": obj.properties,
"source_filename": fileName
})
if(objects.length === 1) {
console.log(objects[0])
console.log(objects[0], this.params.orchRunId)
console.log(`Objects-array: typeof package_id: ${typeof objects[0].package_id}, typeof type_id: ${typeof objects[0].type_id}, orch_run_id: ${this.params.orchRunId}`);
}
}

if(newOccurrence) {
this.#propMap = new Map()
bimBatch.properties.forEach(prop => this.#propMap.set(prop.id, prop))

this.#typeMap = new Map()

console.log(`New occurrence file detected, orch_run_id: ${this.params.orchRunId}`)
for(const { id, name, sourceId, properties } of bimBatch.types) {
types.push({ id, name, "source_id": sourceId, properties })
}

console.log(`About to process type extraction, typesLen: ${types?.length}, orch_run_id: ${this.params.orchRunId}`)

for (let type of types) {
for (let prop of type.properties) {
//const _myProp = bimBatch.properties.find(x => x.id == prop.id);
const _myProp = this.#propMap.get(prop.id)

prop.dName = _myProp.dName;
if (_myProp.hasOwnProperty("Asset Category")) {
prop.baType = _myProp["Asset Category"]
}
}

type._id = await IafScriptEngine.newID("mongo", { "format": "hex" });
//console.log(JSON.stringify({"message":"Received new ID from mongo: type._id: " + type?._id}));

type.properties = this.#groupBy(type.properties, "dName");

if (this.#assetTypeMap && type.properties.hasOwnProperty("Revit Family") && type.properties.hasOwnProperty("Revit Type")) {
const _myRow = this.#assetTypeMap.find(x => x["Revit Family"] == type.properties["Revit Family"].val && x["Revit Type"] == type.properties["Revit Type"].val);

if (_myRow) {
type.dtCategory = _myRow.dtCategory;
type.dtType = _myRow.dtType;
}
}

this.#typeMap.set(type.id, type)
}

console.log(`Type Extraction is complete, orch_run_id: ${this.params.orchRunId}`);
}else {
console.log(`Old occurrence file detected. Using existing manage_type_els, orch_run_id: ${this.params.orchRunId}`)

types = await IafScriptEngine.getVar("manage_type_els")
}


let _myProperties = [];
console.log(`About to process objects, objectsLen: ${objects?.length}`);

// do the same for properties in the object
for (let obj of objects) {
obj._id = await IafScriptEngine.newID("mongo", { "format": "hex" });

//const _myVal = types.find(x => x.id == obj.type_id);

const _myVal = this.#typeMap.get(obj.type_id)

obj.dtCategory = _myVal.dtCategory;
obj.dtType = _myVal.dtType;

if (_myVal.hasOwnProperty("baType")) {
obj.baType = _myVal.baType;
}

if(obj.properties?.length > 0) {
obj.properties.forEach(prop => {
//let _myProp = bimBatch.properties.find(x => x.id == prop.id);
const _myProp = this.#propMap.get(prop.id)

prop.dName = _myProp.dName;
});

obj.properties = this.#groupBy(obj.properties, "dName");
}else {
obj.properties = {}
}
_myProperties.push({ _id: obj._id, properties: obj.properties })

delete obj.properties
};

console.log(`Property Extraction is complete, orch_run_id: ${this.params.orchRunId}`);
const setVars = [
IafScriptEngine.setVar("properties", _myProperties),
IafScriptEngine.setVar("manage_els", objects)
]

if(newOccurrence){
setVars.push(IafScriptEngine.setVar("manage_type_els", types))
}
await Promise.all(setVars)
await IafScriptEngine.setVar(
"manage_el_to_type_relations",
this.#mapItemsAsRelated(objects, types, 'type_id', 'id')
)

resolve(true)
} catch (err) {
console.log(`Error at extractBimpk, orch_run_id: ${this.params.orchRunId}`)
console.error(err)

reject(err)
}
})
}

async #createRelatedItemsAndRelationships (newOccurrence, _colls) {
return new Promise(async (resolve, reject) => {
try {
const { IafScriptEngine } = this.libraries

console.log(`Creating Model Relations and Related Items, orch_run_id: ${this.params.orchRunId}`);
const getVarCalls = [
await IafScriptEngine.getVar("manage_els"),
await IafScriptEngine.getVar("properties"),
await IafScriptEngine.getVar("manage_el_to_type_relations")
]
if(newOccurrence) {
getVarCalls.push(await IafScriptEngine.getVar("manage_type_els"))
}
const [ manage_els, properties, relations, manage_type_els ] = await Promise.all(getVarCalls)

const callList = [
IafScriptEngine.createItemsBulk({
"_userItemId": _colls.model_els_coll._userItemId,
"_namespaces": this.ctx._namespaces,
"items": manage_els
}, this.ctx)
]
console.log(`Create Related Collection manage_els, orch_run_id: ${this.params.orchRunId}`);

if(newOccurrence) {
callList.push(
IafScriptEngine.createItemsBulk({
"_userItemId": _colls.model_type_el_coll._userItemId,
"_namespaces": this.ctx._namespaces,
"items": manage_type_els
}, this.ctx)
)
console.log(`Create Related Collection manage_type_els, orch_run_id: ${this.params.orchRunId}`);
}

await Promise.all(callList)

console.log(`Create Related Collection properties, orch_run_id: ${this.params.orchRunId}`);
console.log(`Create Related Collection Relations, relations: ${relations?.length} orch_run_id: ${this.params.orchRunId}`);

await Promise.all([
IafScriptEngine.createItemsAsRelatedBulk({
"parentUserItemId": _colls.model_els_coll._userItemId,
"_userItemId": _colls.model_els_props_coll._userItemId,
"_namespaces": this.ctx._namespaces,
"items": properties
}, this.ctx),

IafScriptEngine.createRelations({
"parentUserItemId": _colls.model_els_coll._userItemId,
"_userItemId": _colls.model_type_el_coll._userItemId,
"_namespaces": this.ctx._namespaces,
relations
}, this.ctx)
])

resolve(true);
} catch (error) {
console.log(`Error at createRelatedItemsAndRelationships, orch_run_id: ${this.params.orchRunId}`)
console.error(error)

reject(error)
}
})
}

#groupBy(objectArray, property) {
return objectArray.reduce((acc, obj) => {
let key = obj[property];

key = key.replace(/[\.]+/g, "");
if (!acc[key]) {
acc[key] = {};
}
// Add object to list for given key's value
acc[key] = obj;

return acc;
}, {});
}

#mapItemsAsRelated (parentItems, relatedItems, fromField, relatedField) {
let res = [];

for (let i = 0, l = parentItems.length; i < l; i++) {
let relatedRecs = [];
let parentItem = parentItems[i];
let fromValues = [];

if (!(parentItem[fromField]) && fromField.indexOf(".") > 1) {
fromValues = fromField.split(".").reduce((o, i) => o[i] || [], parentItem);
} else {
fromValues = Array.isArray(parentItem[fromField]) ? parentItem[fromField] : [parentItem[fromField]];
}

if (fromValues && fromValues.length > 0)
relatedRecs = relatedItems.filter(r => fromValues.includes(r[relatedField]));

if (relatedRecs.length > 0) {
res.push({
parentItem: parentItems[i],
relatedItems: relatedRecs
});
}
}
console.log('mapItemsAsRelated length ', res?.length)
return res;
}
}

class SgpkImport {
constructor(params, libraries, ctx) {
this.params = params
this.libraries = libraries
this.ctx = ctx
}

initialize() {
return new Promise(async (resolve, reject) => {
try {
console.log(`Sgpk import begins, orch_run_id: ${this.params.orchRunId}`)
const { IafScriptEngine, ModelFileReader, } = this.libraries
const param = {
...this.params.actualParams,
filename: this.params.filename,
orchRunId: this.params.orchRunId,
ext: this.params.ext
}

// set global variables first
await IafScriptEngine.setVar("namespaces", this.ctx._namespaces);
await IafScriptEngine.setVar("package_name", param.filename);
await IafScriptEngine.setVar("package_name_short", param.filename.substring(0, 11));

const bim_model = await IafScriptEngine.getCompositeCollection(
{
"_userType": "bim_model_version",
"_versions._userAttributes.sgpk.fileId": param._fileId
},
ctx,
{}
);

if (bim_model) {
await IafScriptEngine.setVar("bim_model", bim_model);

await this.#createBIMCollectionVersion();
} else {
await this.#createBIMCollections();
}

const { bimFilePath, manifest } = await ModelFileReader.downloadAndUnzipModelFile(param, ctx)
const result = await IafScriptEngine.getVar("outparams")

result.bimFilePath = bimFilePath
result.manifest = manifest
result.filename = param.filename
result._fileId = param._fileId
result._fileVersionId = param._fileVersionId

resolve(result)
} catch (error) {
console.error(`Error at importSgpk, orch_run_id: ${orchRunId}`, error)

reject(error)
}
})
}

async #createBIMCollections() {
return new Promise(async (resolve, reject) => {
try {
const { IafScriptEngine } = this.libraries

console.log(`Creating Model Collections, orch_run_id: ${this.params.orchRunId}`)

const packagename = await IafScriptEngine.getVar("package_name")
const packagenameShort = await IafScriptEngine.getVar("package_name_short")

//create Geometry File Collection
const geometryFilesCol = {
_name: packagename + '_geom_file',
_shortName: packagenameShort + '_geom_file',
_description: 'File Collection for Geometry Files',
_userType: 'bim_model_geomresources',
_namespaces: this.ctx._namespaces
}

console.log(`Create BIM Collection - Geometry File Collection, orch_run_id: ${this.params.orchRunId}`)
const model_geom_file_coll = await IafScriptEngine.createCollection(geometryFilesCol, this.ctx)

//create Geometry View Collection
const geometryViewsCol = {
_name: packagename + '_geom_view',
_shortName: packagenameShort + '_geom_view',
_description: 'Geometry Views in Model',
_userType: 'bim_model_geomviews',
_namespaces: this.ctx._namespaces
}

console.log(`Create BIM Collection - Geometry View Collection, orch_run_id: ${this.params.orchRunId}`)
const model_geom_views_coll = await IafScriptEngine.createCollection(geometryViewsCol, this.ctx)

//create Model Composite Item
const modelCompItem = {
_name: packagename,
_shortName: packagenameShort + '_modelver',
_description: 'BIM model version by transform',
_userType: 'bim_model_version',
_namespaces: this.ctx._namespaces
}
const bim_model = await IafScriptEngine.createNamedCompositeItem(modelCompItem, this.ctx)

await IafScriptEngine.setVar("bim_model", bim_model)

const _myCollections = {
model_geom_file_coll,
model_geom_views_coll
};

await this.#addRelatedCollections(_myCollections)

resolve(true)
} catch (error) {
console.error(`Error at createBIMCollections, orch_run_id: ${this.params.orchRunId}`, error)

reject(error)
}
})
}

async #createBIMCollectionVersion() {
return new Promise(async (resolve, reject) => {
try {
const { IafScriptEngine } = this.libraries
console.log(`Found Previous Model Creating Versions, orch_run_id: ${this.params.orchRunId}`)

const { _id: bim_model_id } = await IafScriptEngine.getVar("bim_model")
const modelRelatedCollection = await IafScriptEngine.getCollectionsInComposite(
bim_model_id,
null,
this.ctx
)

console.log(`Create BIM Collection Version - bim_model, orch_run_id: ${this.params.orchRunId}`)
await IafScriptEngine.createNamedUserItemVersion({ "namedUserItemId": bim_model_id }, this.ctx)

const model_geom_file_coll = modelRelatedCollection.find(x => x._userType === 'bim_model_geomresources')
const model_geom_views_coll = modelRelatedCollection.find(x => x._userType === 'bim_model_geomviews')

console.log(`Create BIM Collection Version model_geom_file_coll, orch_run_id: ${this.params.orchRunId}`)
await IafScriptEngine.createNamedUserItemVersion({ "namedUserItemId": model_geom_file_coll._userItemId }, this.ctx)

console.log(`Create BIM Collection Version model_geom_views_coll, orch_run_id: ${this.params.orchRunId}`)
await IafScriptEngine.createNamedUserItemVersion({ "namedUserItemId": model_geom_views_coll._userItemId }, this.ctx)

const _myCollections = {
model_geom_file_coll,
model_geom_views_coll
}

this.#addRelatedCollections(_myCollections)

resolve(true)
}catch(error) {
console.error(`Error at createBIMCollectionVersion, orch_run_id: ${orchRunId}`, error)

reject(error)
}
})
}

async #addRelatedCollections (_colls) {
return new Promise(async (resolve, reject) => {
try {
const { IafScriptEngine } = this.libraries

console.log(`Creating Model Relations and Related Items, orch_run_id: ${this.params.orchRunId}`)
const { _id: bim_model_id } = await IafScriptEngine.getVar("bim_model")

await IafScriptEngine.addRelatedCollections({
namedCompositeItemId: bim_model_id,
relatedCollections: [
_colls.model_geom_file_coll._userItemId,
_colls.model_geom_views_coll._userItemId
]
}, ctx)

await IafScriptEngine.setVar(
'outparams',
{
filecolid: _colls.model_geom_file_coll._userItemId,
viewcolid: _colls.model_geom_views_coll._userItemId,
compositeitemid: bim_model_id
}
)

resolve(true)
} catch (error) {
console.error(`Error at addRelatedCollections, orch_run_id: ${this.params.orchRunId}`, error)

reject(error)
}
})
}

}

class Helper {
constructor(params, libraries) {
this.params = params
this.libraries = libraries
}

async getFileMetaData(fileId) {
return new Promise(async (resolve, reject) => {
try {
if(!fileId) throw new Error('_fileId is mandatory')

const { PlatformApi } = this.libraries
const { _name } = await PlatformApi.IafFileSvc.getFile(fileId, this.params.context) || {};

if (!_name) {
throw new Error(`Couldn't retrieve file information for _fileId: ${fileId}`);
}
const fileMeta = {
filename : _name.slice(0, _name.lastIndexOf('.')),
ext: _name.split('.')?.pop(),
}

resolve(fileMeta)
} catch (error) {
console.log(`Error at getFileMetaData method, orch_run_id: ${this.params.orchRunId}`, error)

reject(error)
}
})
}
}

class SczImport {
constructor(params, libraries, ctx) {
this.params = params
this.libraries = libraries
this.ctx = ctx
}

async intialize() {
return new Promise(async (resolve, reject) => {
try {
const resources = await this.#processScz()

await this.#updateViewableResources(resources)

resolve(true)
} catch (err) {
reject(err)
}
})
}

async #processScz() {
return new Promise(async (resolve, reject) => {
try {
console.log(`Executing processScz method in SczTarget, orch_run_id: ${this.params.orchRunId}`)
let viewItems = []
viewItems = await this.#processGraphics()

let viewItems2d = []
viewItems2d = await this.#processGraphics2d()

viewItems = viewItems.concat(viewItems2d)

resolve(viewItems)
}catch(error) {
reject(error)
}
})
}

async #processGraphics() {
return new Promise(async (resolve, reject) => {
try {
console.log(`Executing processGraphics method in SczTarget, orch_run_id: ${this.params.orchRunId}`)
const { manifest } = this.params.result
const { files: manifestFiles, occurrences } = manifest
let folderName
let viewItems = []

for (const maniFile of manifestFiles) {
const layers = maniFile.layers;
// find occurances
const occs = occurrences.filter(d => d.source === maniFile.id)
const graphicsFileTitle = this.#removeFileExtension(maniFile.name);

for (const occ of occs) {
const graphicsFilePath = occ.data.graphics;
const graphics2dFilePath = occ.data.graphics2d;
const modelBounding = occ.modelBounding;
// folderName = 'geometryData_' + params.context.id + "_" + occ.id;

const viewItemsOcc = await this.#addViewItems(
graphicsFilePath,
graphics2dFilePath,
folderName,
graphicsFileTitle,
layers,
modelBounding
);

viewItems = viewItems.concat(viewItemsOcc);
}
//maniFile.occurences = occs
}

resolve(viewItems)
} catch (error) {
reject(error)
}
})
}

async #addViewItems(graphicsFilePath, graphics2dFilePath, folderName, graphicsFileTitle, layers, modelBounding) {
return new Promise(async (resolve, reject) => {
try {
const { PlatformApi } = this.libraries
let folder
let viewItems = []

if (graphicsFilePath || graphics2dFilePath) {
folderName = 'geometryData_' + this.params.context.id
folder = await PlatformApi.IafFileSvc.addFolder(folderName, this.params.context._namespaces[0], undefined, this.params.context)

await this.#updateFileDetailsInModel(folder._id)
}

if(graphicsFilePath) {
const viewItems3d = await this.#process3D(
graphicsFilePath,
folder,
graphicsFileTitle,
layers,
modelBounding
)

if (viewItems3d && viewItems3d.length > 0) {
viewItems = viewItems.concat(viewItems3d)
}
}

if(graphics2dFilePath) {
const viewItems2d = await this.#process2D(graphics2dFilePath, folder, graphicsFileTitle)

if (viewItems2d && viewItems2d.length > 0) {
viewItems = viewItems.concat(viewItems2d)
}
}

resolve(viewItems)
} catch (error) {
console.error(error)
reject(error)
}
})
}

async #processGraphics2d() {
return new Promise(async (resolve, reject) => {
try {
console.log(`Executing processGraphics2d method, orch_run_id: ${this.params.orchRunId}`)
const { view2ds } = this.params.result.manifest

if (!view2ds) {
console.warn (`In processGraphics2d, view2ds is found empty, skipping, orch_run_id: ${this.params.orchRunId}`);
return resolve([])
}
let folderName
let viewItems = []

for (const { name: graphicsFileTitle, graphics2d: graphics2dFilePath } of view2ds) {
const viewItemsOcc = await this.#addViewItems2d(graphics2dFilePath, folderName, graphicsFileTitle);

viewItems = viewItems.concat(viewItemsOcc);
}

resolve(viewItems)
} catch (error) {
reject(error)
}
})
}

async #addViewItems2d(graphics2dFilePath, folderName, graphicsFileTitle) {
return new Promise(async (resolve, reject) => {
try {
const { PlatformApi } = this.libraries
let folder
let viewItems = []

if (graphics2dFilePath) {
folderName = 'geometryData_' + this.params.context.id
folder = await PlatformApi.IafFileSvc.addFolder(
folderName,
this.params.context._namespaces[0],
undefined,
this.params.context
)
await this.#updateFileDetailsInModel(folder._id)
}

if(graphics2dFilePath) {
const viewItems2d = await this.#process2DChopped(graphics2dFilePath, folder, graphicsFileTitle)

if (viewItems2d && viewItems2d.length > 0) {
viewItems = viewItems.concat(viewItems2d)
}
}

resolve(viewItems)
} catch (error) {
reject(error)
}
})
}

async #process2D(graphics2dFilePath, folder, title) {
return new Promise(async (resolve, reject) => {
try {
console.log(`Executing process2D method, orch_run_id: ${this.params.orchRunId}`);
if (!graphics2dFilePath) return resolve([])

const { ModelFileReader } = this.libraries
//Upload Scz
const filePath = this.params.result.bimFilePath + '/' + graphics2dFilePath;
const filename = this.params.result.filename + '_2d.scz'
const opts = { filename }
const tags = ['#invgraphicsfile#']

const uploadParams = { filePath, opts, tags, folder, context: this.params.context }
const uploadRes = await ModelFileReader.uploadLargeFile(uploadParams)
let sczFileItem = {}

if(uploadRes?.isFileuploaded) {
await this.#cacheFile(uploadRes.file?._id)
sczFileItem = await this.#createFileItem(uploadRes.file);
}
let viewItems = [];
//Upload mapping file
const hoops_node_mapping_file = 'hoops_node_mapping2d.json';
const mappingFilePath = this.#updatePath(filePath, hoops_node_mapping_file)
const mapFileUploadParams = { filePath: mappingFilePath, opts: { filename: hoops_node_mapping_file }, tags: [], folder, readFile: true, context: this.params.context }
const mappingFile = await ModelFileReader.uploadLargeFile(mapFileUploadParams);

if(mappingFile?.isFileuploaded) {
const mappingFileItem = await this.#createFileItem(mappingFile.file)
const mapping2D = JSON.parse(mappingFile.rawFile)

Object.keys(mapping2D).forEach(key => {
viewItems.push({
title: key,
aspect: 'View2d',
viewableResources: [sczFileItem._id],
resources: [mappingFileItem._id]
})
})
}

resolve(viewItems)
} catch (error) {
console.log(`Error at process2D method, orch_run_id: ${this.params.orchRunId}`, error)

reject(error)
}
})
}

async #process2DChopped(graphicsFilePath, folder, title) {
return new Promise(async(resolve, reject) => {
try {
console.log(`Executing process2DChopped method arguments, orch_run_id: ${this.params.orchRunId}`);
const { path, ModelFileReader } = this.libraries
let viewItem = {
title: title ? title : '2dGraphics',
aspect: 'View2d'
}
// Upload Scz
const filePath = this.params.result.bimFilePath + '/' + graphicsFilePath
const filePathParts = graphicsFilePath.split('/');
const filename = this.params.result.filename + '_' + filePathParts[1] + '.scz';
const opts = { filename }
const tags = ['#invgraphicsfile#']

const uploadParams = { filePath, opts, tags, folder, context: this.params.context }
const uploadRes = await ModelFileReader.uploadLargeFile(uploadParams)
let sczFileItem = {}

if(uploadRes?.isFileuploaded) {
await this.#cacheFile(uploadRes.file?._id)
sczFileItem = await this.#createFileItem(uploadRes.file);
viewItem.viewableResources = [sczFileItem._id]
}
//const dir = path.dirname(filePath)
const hoops_node_mapping_file = 'hoops_node_mapping2d.json'
//const mappingFilePath = dir + '/' + hoops_node_mapping_file

const mappingFilePath = this.#updatePath(filePath, hoops_node_mapping_file)
const mapFileUploadParams = { filePath: mappingFilePath, opts: { filename: hoops_node_mapping_file }, tags: [], folder, context: this.params.context }
const mappingFile = await ModelFileReader.uploadLargeFile(mapFileUploadParams);

if(mappingFile?.isFileuploaded) {
const mappingFileItem = await this.#createFileItem(mappingFile.file)

viewItem.resources = [mappingFileItem._id]
}

resolve([viewItem])
} catch (error) {
reject(error)
}
})
}

async #process3D(graphicsFilePath, folder, title, layers, modelBounding) {
return new Promise(async(resolve, reject) => {
try {
console.log(`Executing process3D method, orch_run_id: ${this.params.orchRunId}`)
const { path, ModelFileReader } = this.libraries
let viewItem = {
title: title ? title : '3dGraphics',
aspect: 'View3d'
}
//Upload Scz
const filePath = this.params.result.bimFilePath + '/' + graphicsFilePath;
const filePathParts = graphicsFilePath.split('/');
const filename = this.params.result.filename + '_' + filePathParts[1] + '.scz';
const opts = { filename }
const tags = ['#invgraphicsfile#']

//Scz file upload
const uploadParams = { filePath, opts, tags, folder, context: this.params.context }
const uploadRes = await ModelFileReader.uploadLargeFile(uploadParams)

if(uploadRes?.isFileuploaded) {
await this.#cacheFile(uploadRes.file?._id)
const sczFileItem = await this.#createFileItem(uploadRes.file);

viewItem.viewableResources = [sczFileItem._id];
layers && (viewItem.layers = layers);
modelBounding && (viewItem.modelBounding = modelBounding);
}

//Upload mapping file
const hoops_node_mapping_file = 'hoops_node_mapping.json';
const mappingFilePath = this.#updatePath(filePath, hoops_node_mapping_file)
const mapFileUploadParams = { filePath: mappingFilePath, opts: { filename: hoops_node_mapping_file }, tags: [], folder, context: this.params.context }

const mapFile = await ModelFileReader.uploadLargeFile(mapFileUploadParams);

if(mapFile?.isFileuploaded) {
const mappingFileItem = await this.#createFileItem(mapFile.file);

viewItem.resources = [mappingFileItem._id];
}

resolve([viewItem]);
} catch (error) {
reject(error)
}
})
}


async #updateViewableResources(viewItems) {
return new Promise(async(resolve, reject) => {
try {
console.log(`Executing updateViewableResources method, orch_run_id: ${this.params.orchRunId}`);
console.log(`viewItems count: ${viewItems?.length}`)
if (!viewItems || viewItems.length <= 0) return resolve(true)

const { PlatformApi } = this.libraries

for (let viewItem of viewItems) {
let resViewItem = await PlatformApi.IafItemSvc.createRelatedItems(this.params.result.viewcolid, [viewItem], this.params.context)

resViewItem = resViewItem?._list[0]
let relationShips = []
let relatedToIds = viewItem.viewableResources ? viewItem.viewableResources : []

relatedToIds = relatedToIds
? relatedToIds.concat(
viewItem.resources ? viewItem.resources : []
)
: []
if (relatedToIds.length > 0) {
const relations = {
_relatedFromId: resViewItem._id,
_relatedUserItemId: this.params.result.filecolid,
_relatedToIds: relatedToIds
}

relationShips.push(relations)
await PlatformApi.IafItemSvc.addRelationsBulk(this.params.result.viewcolid, relationShips, this.params.context)
}
}

resolve(true)
} catch (error) {
reject(error)
}
})
}

async #updateFileDetailsInModel(folderId) {
return new Promise(async(resolve, reject) => {
try {
console.log(`Executing updateFileDetailsInModel method, orch_run_id: ${this.params.orchRunId}`);
const { _, ModelFileReader, PlatformApi } = this.libraries
//let userAttributes = {}
let thumbnailPath = _.get(
_.find(this.params.result.manifest.occurrences, oc => oc.data),
'data.thumbnail'
) || 'thumbnail.png';

thumbnailPath = this.params.result.bimFilePath + '/' + thumbnailPath
const uploadParams = {
filePath: thumbnailPath,
_namespaces: this.params.context._namespaces[0],
folderId,
tags: undefined,
ctx: this.params.context,
opts: {}
}
const fileUpload = await ModelFileReader.uploadSmallFile(uploadParams)

if (fileUpload?.isFileuploaded) {
const { fileInfo } = fileUpload
const userAttributes = {
thumbnail: {
fileId: fileInfo[0]._id,
fileVersionId: fileInfo[0]._tipId
},
[this.params.ext]: {
fileId: this.params.result._fileId,
fileVersionId: this.params.result._fileVersionId
}
};

const compItem = await PlatformApi.IafItemSvc.getNamedUserItem(this.params.result.compositeitemid, this.params.context);
const version = compItem._versions[0];

if (version.hasOwnProperty('_userAttributes')) {
Object.assign(version._userAttributes, userAttributes);
}else {
version._userAttributes = userAttributes;
}

await PlatformApi.IafItemSvc.updateNamedUserItemVersion(compItem._id, version._id, version, this.params.context);
}

resolve(true)
} catch (error) {
console.log(`Error at updateFileDetailsInModel method, orch_run_id: ${this.params.orchRunId}`, error)

reject(error)
}
})
}

async #cacheFile(_fileId) {
return new Promise(async (resolve, reject) => {
try {
const { PlatformApi } = this.libraries

await PlatformApi.IafGraphicsSvc.cacheGraphicsFiles([{ _fileId }], this.params.context)
console.log(`Successfully cached file_id: ${_fileId} in graphics service, orch_run_id: ${this.params.orchRunId}`)

resolve(true)
} catch (error) {
reject(error)
}
})
}

async #createFileItem(fileObj) {
return new Promise(async (resolve, reject) => {
try {
const { PlatformApi } = this.libraries
const fileAttr = {
_fileId: fileObj._id,
_fileVersionId: fileObj._tipId,
filename: fileObj._name
};

const { _list = [] } = await PlatformApi.IafItemSvc.createRelatedItems(this.params.result.filecolid, [fileAttr], this.params.context) || {};

resolve(_list[0])
} catch (error) {
console.log(`Error at createFileItem method, orch_run_id: ${this.params.orchRunId}`, error)

reject(error)
}
})
}

#updatePath(filePath, fileName) {
try {
let splitPaths = filePath.split('/')

splitPaths[splitPaths.length - 1] = fileName
const modifiedFilePath = splitPaths.join('/')

return modifiedFilePath
} catch (error) {
console.log(`Error at #updatePath, orch_run_id: ${this.params.orchRunId}`, error)

throw error
}

}

#removeFileExtension (fileName) {
const split = fileName.split('.');
const extension = split.pop();
const exists = extension && (extension.length === 3);

return exists ? split.join(".") : fileName;
}
}

async function importModel(params, libraries, ctx) {
return new Promise(async (resolve, reject) => {
try {
console.log(`Executing importModel method, orch_run_id: ${params.orchRunId}`)
console.time(`${params.orchRunId}: validation`)
const helper = new Helper(params, libraries)
const { filename, ext } = await helper.getFileMetaData(params?.actualParams?._fileId)

params.filename = filename
params.ext = ext?.toLowerCase()

const validateInput = new InputValidation(params, libraries, ctx)
await validateInput.validate()
console.timeEnd(`${params.orchRunId}: validation`)

let result = {}

if(params.ext == 'bimpk') {
console.time(`${params.orchRunId}: BimpkImport`)
const bimpkImport = new BimpkImport(params, libraries, ctx)

result = await bimpkImport.initialize()
console.timeEnd(`${params.orchRunId}: BimpkImport`)
}else {
const sgpkImport = new SgpkImport(params, libraries, ctx)
result = await sgpkImport.initialize()
}

params.result = result

console.time(`${params.orchRunId}: SczImport`)
const sczImport = new SczImport(params, libraries, ctx)
await sczImport.intialize()
console.timeEnd(`${params.orchRunId}: SczImport`)

const res = {
filecolid: result.filecolid,
viewcolid: result.viewcolid,
compositeitemid: result.compositeitemid
}
if(result.myCollections) {
res.myCollections = result.myCollections
}
console.log(`Model import is complete, ${params.orchRunId}`)

resolve(res)
}catch(error) {
reject(error)
}
})
}

const cacheSourceFileGraphicsIds = async (params, libraries, ctx)=> {
return new Promise(async (resolve, reject)=> {
try{
const { IafScriptEngine} = libraries;
const { model_els_coll, data_cache_coll } = params.inparams.myCollections

console.log('--> cache elems: ' + model_els_coll._name)
console.log('--> cache data: ' + data_cache_coll._name)

const { _list: sourcefileList = [] } = await IafScriptEngine.getDistinct({
collectionDesc: { _userType: model_els_coll._userType, _userItemId: model_els_coll._userItemId },
field: 'source_filename',
options: { getCollInfo: true }
}, ctx) || {}
const sourcefileNames = sourcefileList[0]?._versions[0]?._relatedItems?.source_filename
let cacheDataItems = []

for (let i = 0; i < sourcefileNames.length; i++) {
const { _list: packageIdList = [] } = await IafScriptEngine.getDistinct({
collectionDesc: { _userType: model_els_coll._userType, _userItemId: model_els_coll._userItemId },
query: { source_filename: sourcefileNames[i] },
field: 'package_id',
options: { getCollInfo: true }
}, ctx) || {}

cacheDataItems.push({
dataType: 'sourcefileToPkgIds',
data: {
source_filename: sourcefileNames[i],
package_id: packageIdList[0]?._versions[0]?._relatedItems?.package_id
}
})
}
const bim_els = await IafScriptEngine.createItemsBulk({
"_userItemId": data_cache_coll._userItemId,
"_namespaces": ctx._namespaces,
"items": cacheDataItems
}, ctx);

await IafScriptEngine.setVar("outparams", { cacheDataItems: bim_els })

console.log("Create Cache Data: source filenames to package_ids");

resolve(true)
} catch (err) {
console.log('Error at cacheSourceFileGraphicsIds')
console.error(err)

reject(err)
}
})
}

async function createModelDataCache(params, libraries, ctx) {
return new Promise(async (resolve, reject) => {
try {
const { IafScriptEngine } = libraries;

await cacheSourceFileGraphicsIds(params, libraries, ctx)
const outParams = await IafScriptEngine.getVar("outparams");

resolve(outParams)
} catch (error) {
console.log('Error at createModelDataCache')
console.error(error)

reject(error)
}
})
}