# IGD.ProductData

Everything in ProductData revolves around the concept of sessions.
A session stores the state of articles and the connections to the services. It can either be created for each planning process or created once. It's also possible to use multiple sessions at the same time.

## Creating a session

This module exposes two methods that can be used to create a session. A newly created session through either of these methods does not have any knowledge
of catalogs or their data source.

**createSession**

Creates a basic session

```ts
import { createSession } from "@intelligentgraphics/igd.productdata";

const session = createSession({
	language: "de",
});
```

**createSingleArticleSession**

Creates a session where only one main article can exist at a time. The main article may have child articles.

## Adding catalogs and backends to a session

In order to register a catalog to a session so that it can be used for configuration, you can either:

**Create services manually**

You can manually create a ProductDataManager or a ConfigurationService and optionally a CatalogManager and register them to the session using a common sourceId.

```ts
import {
	createSession,
	IConfigurationService,
} from "@intelligentgraphics/igd.productdata";

const session = createSession();

const mySourceId = "MySource";
const configurationService: IConfigurationService = {
	// ...
};

session.registerConfigurationService(mySourceId, configurationService);
```

**Create services using backends and an igxr loader**

The igxr format can be used to specify a list of servers, manufacturers and catalogs. By registering backends either directly on the session or on the static BackendRegistry export for these servers,
the catalogs can automatically registered according to their specified settings.

```ts
import {
	IGXR,
	IGXRLoader,
	Backend,
	BackendRegistry
	createSession
} from "@intelligentgraphics/igd.productdata";
import * as ICOM from "@intelligentgraphics/igd.backend.icom";
import { Http } from "@intelligentgraphics/ig.utilities";

const igxr = await Http.getJSON("https://icom.intelligentgraphics.biz/icom/configurator/getRegistry/xxxl");
const igxrLoader = new IGXRLoader([
	igxr
]);

// the string here equals the type property for the server inside of the igxr file
BackendRegistry.registerBackend("ICOM", () => new ICOM.Backend());

const session = createSession();
await igxrLoader.addAllCatalogsToSession(session);
```

The sourceId of the registered services equals a concatenation of the manufacturer's key and the catalog's key inside the igxr in the format `manufacturerId + "." + catalogId`.

## Source

Source refers to the interface between a data source and productdata apis. Services for a source are registered to the session under a common sourceId. This sourceId
is used to identify the correct services for an article creation and for other article operations.

Every source has to provide either a ProductDataManager or a ConfigurationService. These services are used to managed the lifetimes and configurations of articles.
They also asynchronously provide commercial informations, which can be retrieved using the session api. Additionally they are responsible for retrieving the graphical representations of articles.

Optionally each source can provide a catalog manager and multi article data.

## Articles

The ProductData Article represent the locally available current informations for an article instance. It consists of the following properties:

**comId**

The globally unique identifier of an article. Can be used to retrieve informations for the article or execute operations using the session api

**gfxId**

Represents the main graphical id of article. Can be used with an \_API from "ig.gfx.core" to move, rotate or manipulate an article.

**configuration**

Contains the current values for the properties of the article.

**properties**

Contains the properties and their values for an article.

**articleNumber**

Represents the original informations that were used to create an article.

**articleId**

Contains the current articleId of an article.

**source**

The id of the source that is responsible for an article. This id can be used to retrieve the services assoicated with the article (ProductDataManager/CatalogManager/ConfigurationService)

**data**

Contains custom informations for an article instance. Can be used to store application specific data.

**children**

Contains the direct child comIds of an article.

**parent**

Contains the direct parent comId of an article.

**categories**

Contains source settings for an article.

**info**

Contains texts, images and prices.

**sourceData**

Contains custom data thats managed by the article's source

**sourcePlacement**

Contains the placement of an article inside the source

## Working with articles

Everything required to interact with articles is located directly inside the session object.

**Create an article**

An article can be created using session.createArticleFromArticleNumber or session.createArticleFromCatalogItem.

CreateArticleFromCatalogItem can only be used when a backend and a catalog manager have been registered for the source. Internally it creates an articleNumber using Backend.createArticleNumber.

```ts
const comId = await session.createArticleFromArticleNumber({
	// id of the registered services  (see "Adding catalogs and backends to a session")
	source,
	articleNumber: {
		// article id inside the data source
		baseArticleNumber: "",
	},
	// Can either be a map of property key to value or the comId of another article instance
	// Will be merged with the scene configuration (if available and enabled)
	initialConfiguration: "someComId",
	/*
	  When this option is enabled, a newly created article will receive the configuration of the first matching article instance in the following order:
	 
	  1. article with the same article id inside the application state's selection
	  2. article inside the application state's selection
	  3. article of the target source with the same article id
	  4. article of the target source
	 */
	applySceneConfiguration: false,
});
```

**Changing article configurations**

```ts
await session.changeArticleProperty(comId, "color", "green");
```

```ts
await session.changeArticleProperties(comId, {
	color: "green",
	material: "leather",
});
```

```ts
await session.changeProperties([comId], {
	color: "green",
	material: "leather",
});
```

**Retrieving informations for an article**

```ts
const article = session.getArticleByComId(comId);
```

The session api also exposes methods which can be used to retrieve a single property of an article. While the methods that retrieve a complete article object will return undefined in the case of an unknown article, these methods will throw an error instead.

**Deleting an article**

```ts
await session.deleteArticle(comId);
```

## Notifications

There are events for common article operations, which can be subscribed to.
Subscriptions will automatically be cleaned up on session destruction.
Multiple notifications, which occur as an result of a single operation (f.e. changeProperties), will be emitted
synchronously in a row.

**Subscribe to one event**

```ts
const subscription = session.on("ItemCreated", article => console.log(article));
```

**Subscribe to multiple events**

```ts
const subscription = session.subscribe({
	ItemCreated: article => console.log(article),
	ItemConfigured: article => console.log(article),
});
```

**Subscribing to all events**

```ts
const subscription = session.onAnyEvent(payload => {
	switch (payload.event) {
		case "ItemCreated":
			console.log(payload.data);
			break;
	}
});
```

**Delete a subscription**

```ts
const subscription = session.subscribe({
	ItemCreated: article => console.log(article),
	ItemConfigured: article => console.log(article),
});
subscription.destroy();
```

## Internal services

**Hooks**

-   contains all hook implementations

**ArticleState**

-   basic storage for article instances

**ArticleQuery**

-   readonly operations for querying an article state

**ArticleRegistry**

-   registers and updates articles in all services

**ConnectionManager**

-   manages connections to services
-   registered connections may implement ICloseableConnection to automatically be killed on session destruction

**BackendManager**

-   contains backend creators and loaded backends for data source types

**ServiceManager**

-   contains services for all sources

**SourceRegistry**

-   registers new sources
-   creates internal manager represenation for services

**ArticleManager**

-   contains asynchronous article operations and information retrieval methods

**NotificationCenter**

-   stores listeners for session events
-   emits data for events

**LocalizationManager**

-   storage for localization informations

**ApplicationState**

-   contains a service to interact with the state of an application (can be provided on session creation, will be a noop implementation otherwise)

**ProjectManager**

-   contains methods to persist and restore the state of articles inside a session

**Scheduler**

-   handles the ordering of operations

**OperationResultHandler**

-   processes operations results, updates articles and emits the resulting events

## Implementing a custom data source

As stated in the source section, every data source has to implement services, so the productdata services can interact with it.

### Article Instance Service

**ProductDataManager**

ProductDataManager is the original concept for managing article instances.
It consists of methods that can change the state of the source (f.e. addArticle or setPropValues) and methods that retrieve informations for an article. It can contain an internal cache used to store internal data for an article.

The state changing operations are assumed to have no side effects on other articles in the source (expect for sub articles).

**ConfigurationService**

ConfigurationService is the newer, smaller replacement for the ProductDataManager. The state changing operations should return results, which reflect what happened as the result of the operation.

F.e. as a result for an createArticle operation, it should return at least one ConfigurationServiceCreateResult describing the new article.

A ConfigurationService should not contain an internal cache for articles and instead use the injected articleQuery aswell as the sourceData property to retrieve informations for its articles.

### CatalogManager

A data source may optionally provide a catalog manager. This catalog manager should retrieve a catalog structure with articles and sets (optionally sorted into folders).

## Handling of custom article instance service operations

When an article instance service (configuration service or productdatamanager) has methods or operations which don't directly map to a default operation, their execution and result handling has to be done manually.

F.e. an article instance service could have a method to delete every second article. To use it and handle the results, the following methods have to be used:

**ProductDataManager**

```ts
ProductDataManager.deleteEverySecondArticle = () => {
	...

	return [
		{
			type: "delete",
			comId: "1"
		},
		{
			type: "delete",
			comId: "3"
		}
	]
}

...

const operator = session.getOperatorForSourceId(sourceId) as PDMOperator;

const pdmResults = await operator.executeArticlesOperation(
	() => productDataManager.deleteEverySecondArticle()
);

await session.processOperationResults(pdmResults);
```

## Creating a session with custom behaviour and additional methods

The public methods of the session api are required to be bound to their execution context,
which allows the session api to easily be extended and overwritten by spreading it onto a new object.

F.e. to add loading state tracking inside the application:

```ts
import { createSession, Session } from "@intelligentgraphics/igd.productdata";

const createAppSession = (): Session => {
	const baseSession = createSession();

	return {
		...baseSession,
		createArticleFromArticleNumber: async params => {
			triggerLoading(true);
			const comId = await baseSession.createArticleFromArticleNumber(
				params,
			);
			triggerLoading(false);
			return comId;
		},
	};
};
```

## Overwrite of internal session services

A session consist of several internal services, which are responsible for creating, updating or storing articles, managing of connections to configuration services, ...

In order to overwrite a service, the complete session creation has to be reimplemented. An example for this can be found inside the SingleArticleSession file.

## Migrating from <4

The Compat export can be initialized with a session and used to somewhat recreate the global api of previous productdata versions.

```ts
import { createSession, Compat } from "@intelligentgraphics/igd.productdata";

const session = createSession({});
Compat.fromSession(session);

Compat.Dispatcher.addArticle();
```

## History

### 4.8.0

-   added tests for source registration on restore
-   fixed restoreFromIGXB not loading catalogs
-   extracted session notification center api into seperate type
-   added animationPosition property to GfxRepresentationOptions
-   added ConfigurationServiceOperator.executeArticlesOperation
-   ProjectManager: added emptySession parameter for restoreFromIGXB

### 4.8.0-alpha.1

-   extracted session notification center api into seperate type

### 4.8.0-alpha.0

-   added animationPosition property to GfxRepresentationOptions
-   added ConfigurationServiceOperator.executeArticlesOperation
-   ProjectManager: added emptySession parameter for restoreFromIGXB

### 4.7.1

-   fixed restoreFromIGXB not registering catalogs

### 4.7.0

-   added ArticleList module
-   Scheduler: added merging of pending configuration requests
-   fixed issues with service restoring
-   added createSessionWithLoadingReasons

### 4.7.0-alpha.2

-   Scheduler: added merging of pending configuration requests

### 4.7.0-alpha.1

-   fixed issues with service restoring

### 4.7.0-alpha.0

-   added createSessionWithLoadingReasons
-   fixed productdata version

### 4.6.0

-   added queryCatalogs function
-   added ArticleUtil.getPropertyValue

### 4.5.0

-   fixed typo in GfxRepresentationHashes

### 4.4.0

-   Session: removed language and locale change methods for now
-   added support for locale additionally to language
-   added gfxId to article creation parameters for room element creation
-   added getArticleSourceData

### 4.4.0-alpha.1

-   disabled language and locale change methods
-   added support for locale additionally to language

### 4.4.0-alpha.0

-   added gfxId to article creation parameters for room element creation
-   added getArticleSourceData

### 4.3.0

-   added iso comments for LocalizationManager options
-   removed no longer used constructs and types

### 4.3.0-alpha.0

-   removed no longer used constructs and types

### 4.2.0

-   fixed ordered configuration changes not being processed properly in scheduler
-   removed IGXCFactory references
-   added esnext building

### 4.2.0-alpha.1

-   removed IGXCFactory references

### 4.2.0-alpha.0

-   fixed ordered configuration changes not being processed properly in scheduler
-   added esnext building

### 4.1.2

### 4.1.1

-   fixed ordered configuration changes not being processed properly

### 4.1.0

-   integrated ordered property changes
-   GfxRepresentation: added support for pbrHash
-   added ItemGfxRemoved notification
-   added test for deletion of unknown articles
-   added new hooks for session
-   ArticleManager.deleteArticles: fixed unkown articles not being handled correcty
-   Session: added reset method
-   ConfigResolver: added resolving of initial configuration from attachTarget comId
-   IGXBWriter: added appending of articleNumber
-   added support for price ranges
-   added operation scheduling
-   added applicationState parameter for session creation
-   added application state selection to resolving of initial configuration
-   OperationResultHandler: added optimization for empty results
-   added afterOperationResultProcessing hook

### 4.1.0-alpha.7

-   integrated ordered property changes

### 4.1.0-alpha.6

-   GfxRepresentation: added support for pbrHash

### 4.1.0-alpha.5

-   added ItemGfxRemoved notification

### 4.1.0-alpha.4

-   added test for deletion of unknown articles
-   added new hooks for session

### 4.1.0-alpha.3

-   ArticleManager.deleteArticles: fixed unkown articles not being handled correcty

### 4.1.0-alpha.2

-   replaced own linked list with ig.utilities version
-   OperationResultHandler: added default implementation of update batching
-   Session: added reset

### 4.1.0-alpha.1

-   ConfigResolver: added resolving of initial configuration from attachTarget comId
-   IGXBWriter: added appending of articleNumber
-   added support for price ranges

### 4.1.0-alpha.0

-   changed delete operation cancel error to be a proper cancel error
-   added operation scheduling
-   added application state selection to resolving of initial configuration
-   OperationResultHandler: added optimization for empty results
-   added applicationState parameter for session creation
-   added afterOperationResultProcessing hook

### 4.0.1

-   fixed apply targets being found for values on deep properties
-   added ArticleUtil.getArticleOrThrow
-   added getGfxRepresentation to session
-   fixed ArticleQuery test

### 4.0.0-alpha.19

-   added localizationManager argument to Backend.initializeManagers

### 4.0.0-alpha.18

-   changed apply target search to look at root property configuration
-   removed PDM.getArticleSubProperties

### 4.0.0-alpha.17

-   added LocalizationChanged notification
-   added basic localization manager
-   changed NotificationCenter to be generic

### 4.0.0-alpha.16

-   added support for catalog and manufacturer hidden setting
-   IGXRLoader: added getWizard
-   added lazy payloads to notification sending
-   added test for pdm restoring
-   added tests for configuration operation in PDMOperator

### 4.0.0-alpha.15

-   fixed newly created sub articles not being assigned to the correct parent after parent configuration
-   refactored IGXRLoader and added some comments
-   removed ArticleManager.createArticleFromCatalogItem dependency on createArticleFromArticleNumber
-   changed PDM.getArticlePropertyList to throw an error for unknown articles

### 4.0.0-alpha.14

-   added price formatter

### 4.0.0-alpha.13

-   added optional catalogRegistrator argument to ProjectManager restore methods
-   rewrite source registration
-   changed backends to take a connectionManager instead of session
-   fixed articleType being written into article object

### 4.0.0-alpha.12

-   fixed sub article restoring
-   removed Configure Notification
-   added emitting of ItemChanged
-   added multi result support to operationresulthandler
-   added ItemChanged notification
-   [*] updated version logs
-   fixed tests

### 4.0.0-alpha.11

-   added export of article name to igxb writer
-   added name to article info

### 4.0.0-alpha.10

-   added compatibility with 2.x gfx version
-   added some usage informations

### 4.0.0-alpha.9

-   added comments
-   added missing methods to single article session

### 4.0.0

-   complete rewrite of internals and public api
-   replaced the global Dispatcher instance with instanciable sessions (The compat module can be used to somewhat replicate the old Dispatcher by initializing it with a session object)

### 4.0.0-alpha.8

-   changed ArticleManager.setArticlePlacement to opt out of updates when placement is the same

### 4.0.0-alpha.7

-   updated ig.gfx dependencies
-   changes for igx 3.0

### 4.0.0-alpha.6

-   added setting attachTo to undefined in articleRegistry
-   added attachTo to articleNumber

### 4.0.0-alpha.5

-   added implementation for getSubArticleIds in IGXEProductDataManager
-   added optional executeBatch to articleState and articleRegistry

### 4.0.0-alpha.4

-   fixed restoring of non gfx articles

### 4.0.0-alpha.3

-   added missing hooks export
-   added hooks
-   added getRegisteredSourceIdsForServerType
-   added PDMOperator interface
-   added executeArticlesOperation to PDMOperator

### 4.0.0-alpha.0

-   rewrite

### 3.3.1

-   added actionConfig to GfxRepresentation

### 3.3.0

-   updated dependencies
-   cleaned up gfxRepresentation and igxb article rotation

### 3.3.0-alpha.0

-   updated dependencies
-   cleaned up gfxRepresentation and igxb article rotation

### 3.2.1

-   added PriceType to property values
-   updated dependencies

### 3.2.0

-   added support for custom source data

### 3.1.5

-   removed material image property

### 3.1.4

-   added optional material image property to property

### 3.1.3

-   updated version logs

### 3.1.2

-   fixed basket articles not being updated after creation when baskeitem exists

### 3.1.1

-   fixed set basket issue

### 3.1.0

### 3.0.3

-   added ItemConfigure notification

### 3.0.1

-   added price property to IPropertyValue

### 3.0.0

-   added itemType property to IArticleNumber
-   added server type parameter to Dispatcher.registerCatalogManager and Dispatcher.registerProductDataManager
-   removed Dispatcher.changeSetProperty and Dispatcher.changeSetProperties
-   replaced Dispatcher.addArticlesFromSet with Set-Support for Dispatcher.addArticle (the itemType of IArticleNumber has to be set properly for this to work)
-   added IGXRLoader.addAllCatalogsToDispatcher
-   added new NotificationCenter
-   added ArticleState.getAllItems ArticleState.getAllSets
-   fixed ArticleState gfx id handling
-   fixed ArticleState set dynamic child behaviour
-   added BackendLoader.getBackendOfCatalog (can be used to retrieve the registered backend of a catalog)
-   added CatalogManager.getSet
-   removed overloads from ConnectionManager.getConnectionIds
-   added optional visualHash and geometricHash to GfxRepresenation
-   fixed set prices in IGXBManager
-   changed ProductDataManager.getGfxRepresenation
-   replaced type parameter with options
-   added "UNCHANGED" as a possible return type to indicate that nothing has changed
-   removed obsolte properties from IArticle
-   added PropertyUtil
-   remove backend specific SessionInfo types
-   changed SetRules.hasRule to be exported
-   added support for head planning

### 2.14.1

-   removed backend specific types
-   added proper return type for Backend.initializeManager

### 2.13.1

-   removed set property from article instances
-   Dispatcher configuration and restoration refactor
-   added set restoring

### 2.13.0

-   extracted XcR and EAIWS backends into seperate packages
-   added getInitialArticlePlacement to ProductDataManagers

### 2.12.2

-   renamed getPrimaryArticleOfSet to getPrimaryArticlesOfSet

### 2.12.1

-   added options for Session.save
-   changed Dispatcher gfx handling

### 2.12.0

-   added sets to article state
-   added addArticlesFromSet method to Dispatcher and ProductDataManagers
-   removed unused inter product methods from ProductDataManagers
-   replaced BackendLoaderInstance with Dispatcher.backendManager

### 2.11.0

-   added ensureConnection method to Dispatcher
-   extracted connection logic from Dispatcher into new connectionManager

### 2.10.11

**EAIWSProductDataManager**

-   fixed ignoring of dimension propertys
-   fixed editable check for property changes

### 2.10.10

-   added skipping of hidden items to IGXBManager for position string calculation

### 2.10.9

**EAIWSProductDataManager**

-   removed article change history
-   added cloning of actual configuration from other items

### 2.9.0

-   added info to ArticleState
-   added impression handling to basket managers

### 2.7.0

-   replaced backend specific connection storage and methods with generic ones
-   added IImpressionProvider interface

### 2.4.0

-   refactored IGXEProductDataManager
-   introduced CatalogCache
-   removed non promise versions of methods

### 2.3.0

-   added code for sub item removing

### 2.0.0

-   applyImpressionSnapshot() returns snapshot-id
-   supports impression snapshots

### 2.0.0

-   fixed package.json
-   supports impressions

### 2.0.0

-   new JS module system

### 1.2.0

-   \*ProductDataManager, Dispatcher.addArticle(): initialConfiguration now may be the comId of an existing article, whose configuration should be applied to the new article.
-   Dispatcher += cloneArticle()
-   EAIWSProductDataManager += cloneArticle()
-   BasketManager += copyItem()
-   EAIWSProductDataManager: fix configuration field in getGfxRepresentation
-   read sub articles from EAIWS and sync with IGXB-Subpositions
-   EAIWSProductDataManager: new config-setting "nonCommercial". When true, method "isCommercial" returns false for all articles
-   IGXRLoader: passes IGXR flag "NonCommercial" to EAIWSProductDataManager
-   Dispatcher: tag EAIWS-SubArticles with "dontRestore" in IGXB, since they will be regenerated anyway

### 1.2.0

-   Reimplementation of EAIWSCatalogManager and EAIWSProductDataManager using IGD.EAIWS 2.0

### 1.1.1

-   don't fail on empty [Manufacturer|Program][id|name]

### 1.1.0

-   IGXBManager: support of EPriceType.None
-   BasketManager +getItemsBySource()
-   IGXEProductDataManager: +assignMaterialPropertyValues()
-   IGXBManager: supports article flag "IsCommercial"
-   IGXELoader: support of boolean values in conditions
-   += EAIWSCatalogManager.getFolderOfArticle()
-   IGXRLoader supports multiple IGXR files
-   += XcRCatalogManager
-   += XcRProductDataManager
-   IGXRLoader supports IGXE sources
-   += Dispatcher.updateArticle()
-   += IGXRLoader.getCatalogInfo()
-   IGXBManager.getPositionString() works with ItemGroups
-   IGXBManager: new API method "moveItem"
-   MultiArticle support
-   ProductDataManager: new API method "getArticleProgramName"
-   ProductDataManager: new API method "getArticleManufacturerName"
-   ProductDataManager: new API method "getGfxRepresentation"
-   ProductDataManager: new API method "getArticleVariantText"
-   IGXBManager: Fix the initially inserted article couldn't be removed
-   Dispatcher: += removeArticles(), making removeArticle() deprecated
-   Dispatcher: store article selection
-   EAIWSProductDataManager: fix syncing state

### 1.0.0

-   some utility functions in IGXRLoader
-   -= MAManager
-   ProductDataReader renamed to IGXELoader
-   += IArticle

### 1.0.0

-   += Dispatcher.register EAIWS connection
-   += CatalogManagers: getImage()
-   -= EAIWSCatalogManager: getIcon()
-   += IGXRLoader
