import { Canvas, Meta, Story } from '@storybook/blocks';

<Meta title="tutorial/Intro" />

# Introduction

这个组件库是为 ocap 数据分析而设计的前端组件的集合。

## 准备环境代码

提供一个服务类通过类 `NgmDSCoreService` 继承类 `DSCoreService` 并初始化 Agent、 Models 等配置信息。
此类为 ocap 核心服务提供了 S4 的嵌入式 BW 引擎的 InfoCube 模型信息。

```typescript
import { Inject, Injectable, Optional } from '@angular/core'
import { NgmDSCacheService, NgmDSCoreService, OCAP_AGENT_TOKEN, OCAP_DATASOURCE_TOKEN } from '@xpert-ai/ocap-angular/core'
import { Agent, AgentType, DataSourceFactory, DataSourceOptions, Syntax } from '@xpert-ai/ocap-core'

@Injectable()
export class ZngS4DSCoreService extends NgmDSCoreService {
  
  static readonly S4ModelKey = '##########'
  static readonly S4ModelName = 'S4CDS'
  static readonly S4InfoCube = '$INFOCUBE'

  static readonly S4Model: DataSourceOptions = {
    key: ZngS4DSCoreService.S4ModelKey,
    name: ZngS4DSCoreService.S4ModelName,
    type: 'XMLA',
    agentType: AgentType.Server,
    syntax: Syntax.MDX,
    dialect: 'sapbw',
    catalog: ZngS4DSCoreService.S4InfoCube
  }

  constructor(
    @Inject(OCAP_AGENT_TOKEN)
    public override agents: Array<Agent>,
    @Inject(OCAP_DATASOURCE_TOKEN)
    public override dataSourceFactory?: Array<{ type: string; factory: DataSourceFactory }>,
    @Optional()
    override cacheService?: NgmDSCacheService
  ) {
    super(agents, [ZngS4DSCoreService.S4Model], dataSourceFactory, cacheService)
  }
}
```

还需要提供连接 S4 系统模型数据接口的 Agent 类实现，其中 request 将模型的数据请求转发至 S4 服务器端并返回相应结果：

```typescript
import { Injectable } from '@angular/core'
import { Agent, AgentStatus, AgentStatusEnum, AgentType, DataSourceOptions } from '@xpert-ai/ocap-core'
import { EMPTY, Observable, of } from 'rxjs'

@Injectable()
export class S4ServerAgent implements Agent {
  type = AgentType.Server

  selectStatus(): Observable<AgentStatus | AgentStatusEnum> {
    return of({
      status: AgentStatusEnum.ONLINE,
      payload: null
    })
  }

  selectError(): Observable<any> {
    return EMPTY
  }

  error(err: any): void {
    console.error(err)
  }

  /**
   * Redirect dataSource request to current S4 backend system
   * 
   * @param dataSource DataSource options of model
   * @param request Request options
   * @returns response text
   */
  async request(dataSource: DataSourceOptions, request: any): Promise<any> {
    const result = await fetch(`/sap/bw/xml/soap/xmla?sap-client=100`, {
      method: 'POST',
      headers: {
        ...request.headers
      },
      body: request.body
    })

    return await result.text()
  }

  /**
   * @todo new api
   * @param dataSource 
   * @param options 
   * @returns 
   */
  _request?(dataSource: DataSourceOptions, options: any): Observable<any> {
    return EMPTY
  }
}
```

在相应 NgModule 里提供以下 Providers：

```typescript
[
    ZngS4DSCoreService,
    {
      provide: NgmDSCoreService,
      useExisting: ZngS4DSCoreService
    },
    NgmAgentService,
    S4ServerAgent,
    {
      provide: OCAP_AGENT_TOKEN,
      useExisting: S4ServerAgent,
      multi: true
    },
    {
      provide: OCAP_DATASOURCE_TOKEN,
      useValue: {
        type: 'XMLA',
        factory: async (): Promise<Type<DataSource>> => {
          const { XmlaDataSource } = await import('@xpert-ai/ocap-xmla')
          return XmlaDataSource
        }
      },
      multi: true
    }
]
```
