<commit_before>import { Injectable, ComponentFactoryResolver, Injector } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Subject, Observable } from 'rxjs';
import { filter } from 'rxjs/operators';
import { TranslateService } from '@ngx-translate/core';

import { UrlPath, UrlPathId } from 'app/shared/models';
import {
    UrlRouteManagerService,
    NewUrlStateNotificationService,
    WindowRefService,
    DynamicPopupService
} from 'app/shared/services';
import { MessagePopupContainerComponent } from 'app/core/components/message-popup/message-popup-container.component';
import { ServerErrorPopupContainerComponent } from 'app/core/components/server-error-popup/server-error-popup-container.component';

@Injectable()
export class TransactionMetaDataService {
    private requestURL = 'transactionmetadata.pinpoint';
    private retrieveErrorMessage: string;
    private lastFetchedIndex = 0;
    private maxLoadLength = 100;
    private requestSourceData: any[];
    private requestCount = 0;
    private countStatus = [0, 0];
    private outTransactionDataLoad: Subject<ITransactionMetaData[]> = new Subject();
    private outTransactionDataRange: Subject<number[]> = new Subject();
    private outTransactionDataCount: Subject<number[]> = new Subject();

    onTransactionDataLoad$: Observable<ITransactionMetaData[]>;
    onTransactionDataRange$: Observable<number[]>;
    onTransactionDataCount$: Observable<number[]>;

    constructor(
        private http: HttpClient,
        private windowRefService: WindowRefService,
        private translateService: TranslateService,
        private newUrlStateNotificationService: NewUrlStateNotificationService,
        private urlRouteManagerService: UrlRouteManagerService,
        private dynamicPopupService: DynamicPopupService,
        private componentFactoryResolver: ComponentFactoryResolver,
        private injector: Injector
    ) {
        this.onTransactionDataLoad$ = this.outTransactionDataLoad.asObservable();
        this.onTransactionDataRange$ = this.outTransactionDataRange.asObservable();
        this.onTransactionDataCount$ = this.outTransactionDataCount.asObservable();

        this.translateService.get('TRANSACTION_LIST.TRANSACTION_RETRIEVE_ERROR').subscribe((text: string) => {
            this.retrieveErrorMessage = text;
        });
        this.newUrlStateNotificationService.onUrlStateChange$.pipe(
            filter((urlService: NewUrlStateNotificationService) => {
                return urlService && urlService.hasValue(UrlPathId.APPLICATION, UrlPathId.PERIOD, UrlPathId.END_TIME);
            })
        ).subscribe(() => {
            this.requestSourceData = this.getInfoFromOpener();
            this.countStatus[1] = this.requestSourceData.length;
        });
    }
    loadData(): void {
        if (this.requestSourceData.length === 0) {
            this.dynamicPopupService.openPopup({
                data: {
                    title: 'Notice',
                    contents: this.retrieveErrorMessage,
                },
                component: MessagePopupContainerComponent,
                onCloseCallback: () => {
                    this.urlRouteManagerService.moveOnPage({
                        url: [
                            UrlPath.MAIN,
                            this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(),
                            this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(),
                            this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime()
                        ]
                    });
                }
            }, {
                resolver: this.componentFactoryResolver,
                injector: this.injector
            });
        } else {
            this.http.post<{ metadata: ITransactionMetaData[] }>(this.requestURL, this.makeRequestOptionsArgs(), {
                headers: new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
            }).subscribe((responseData: { metadata: ITransactionMetaData[] }) => {
                const responseLength = responseData.metadata.length;
                if (this.requestCount !== responseLength) {
                    if (this.requestCount > responseLength) {
                        this.countStatus[1] -= (this.requestCount - responseLength);
                    } else {
                        this.countStatus[1] += (responseLength - this.requestCount);
                    }
                }
                if (responseLength === 0) {
                    this.outFullRange();
                } else {
                    this.countStatus[0] += responseLength;
                    if (this.countStatus[0] === this.countStatus[1]) {
                        this.outFullRange();
                    } else {
                        this.outTransactionDataRange.next([
                            responseData.metadata[responseLength - 1].collectorAcceptTime,
                            this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getDate().valueOf()
                        ]);
                    }
                    this.outTransactionDataLoad.next(responseData.metadata);
                }
                this.outTransactionDataCount.next(this.countStatus);
            }, (error: IServerErrorFormat) => {
                this.dynamicPopupService.openPopup({
                    data: {
                        title: 'Error',
                        contents: error
                    },
                    component: ServerErrorPopupContainerComponent,
                    onCloseCallback: () => {
                        this.urlRouteManagerService.reload();
                    }
                }, {
                    resolver: this.componentFactoryResolver,
                    injector: this.injector
                });
            });
        }
    }
    moreLoad(): void {
        this.loadData();
    }
    private outFullRange(): void {
        this.outTransactionDataRange.next([
            this.newUrlStateNotificationService.getStartTimeToNumber(),
            this.newUrlStateNotificationService.getEndTimeToNumber()
        ]);
    }
    private makeRequestOptionsArgs(): string {
        const requestStr = [];
        const len = this.requestSourceData.length;
        const maxLen = Math.min(len, this.maxLoadLength + this.lastFetchedIndex);
        for ( let index = 0, dataIndex = this.lastFetchedIndex ; dataIndex < maxLen ; index++, dataIndex++ ) {
            // transactionId, x, y
            requestStr.push(`I${index}=${this.requestSourceData[dataIndex][0]}`);
            requestStr.push(`T${index}=${this.requestSourceData[dataIndex][1]}`);
            requestStr.push(`R${index}=${this.requestSourceData[dataIndex][2]}`);
        }
        this.requestCount = requestStr.length / 3;
        this.lastFetchedIndex = maxLen;
        return requestStr.join('&');
        // load from parent window;
        // 브라우저 윈도우 이름으로 아래의 정보를 넘김
        // applicationName
        // oDragXY.fromX
        // oDragXY.toX
        // oDragXY.fromY
        // oDragXY.toY
        // agent
        // inclue?
        // Success/Failed 정보는 현재 window.opener.htoScatter['applicationName'] 에 저장해 둔 Scatter 객체가 가지고 있음.
        // window.htoScatter['']
        //
        // transactionList 데이터의 총합은 이전 window에서 가져옴.
        // indicator의 range는
        // 가져온 데이터 중 가장 예전의 collectorAcceptTime ~ endTime
        // 가져온 데이터의 갯수가 0 이거나 total 보다 커지면 끝
        // 요청 갯수와 응답 갯수가 다른 경우 total 값을 계속 update 해줘야 함.
        // 10개 transaction 데이터를 요청했는데 11개 혹은 12개가 오는 케이스가 있음.
        // --한번에 요청하는 갯수는 일단 최대 100개<commit_msg>[#noissue] Add app name on transaction data api call<commit_after>import { Injectable, ComponentFactoryResolver, Injector } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Subject, Observable } from 'rxjs';
import { filter } from 'rxjs/operators';
import { TranslateService } from '@ngx-translate/core';

import { UrlPath, UrlPathId } from 'app/shared/models';
import {
    UrlRouteManagerService,
    NewUrlStateNotificationService,
    WindowRefService,
    DynamicPopupService
} from 'app/shared/services';
import { MessagePopupContainerComponent } from 'app/core/components/message-popup/message-popup-container.component';
import { ServerErrorPopupContainerComponent } from 'app/core/components/server-error-popup/server-error-popup-container.component';

@Injectable()
export class TransactionMetaDataService {
    private requestURL = 'transactionmetadata.pinpoint';
    private retrieveErrorMessage: string;
    private lastFetchedIndex = 0;
    private maxLoadLength = 100;
    private requestSourceData: any[];
    private requestCount = 0;
    private countStatus = [0, 0];
    private outTransactionDataLoad: Subject<ITransactionMetaData[]> = new Subject();
    private outTransactionDataRange: Subject<number[]> = new Subject();
    private outTransactionDataCount: Subject<number[]> = new Subject();

    onTransactionDataLoad$: Observable<ITransactionMetaData[]>;
    onTransactionDataRange$: Observable<number[]>;
    onTransactionDataCount$: Observable<number[]>;

    constructor(
        private http: HttpClient,
        private windowRefService: WindowRefService,
        private translateService: TranslateService,
        private newUrlStateNotificationService: NewUrlStateNotificationService,
        private urlRouteManagerService: UrlRouteManagerService,
        private dynamicPopupService: DynamicPopupService,
        private componentFactoryResolver: ComponentFactoryResolver,
        private injector: Injector
    ) {
        this.onTransactionDataLoad$ = this.outTransactionDataLoad.asObservable();
        this.onTransactionDataRange$ = this.outTransactionDataRange.asObservable();
        this.onTransactionDataCount$ = this.outTransactionDataCount.asObservable();

        this.translateService.get('TRANSACTION_LIST.TRANSACTION_RETRIEVE_ERROR').subscribe((text: string) => {
            this.retrieveErrorMessage = text;
        });
        this.newUrlStateNotificationService.onUrlStateChange$.pipe(
            filter((urlService: NewUrlStateNotificationService) => {
                return urlService && urlService.hasValue(UrlPathId.APPLICATION, UrlPathId.PERIOD, UrlPathId.END_TIME);
            })
        ).subscribe(() => {
            this.requestSourceData = this.getInfoFromOpener();
            this.countStatus[1] = this.requestSourceData.length;
        });
    }
    loadData(): void {
        if (this.requestSourceData.length === 0) {
            this.dynamicPopupService.openPopup({
                data: {
                    title: 'Notice',
                    contents: this.retrieveErrorMessage,
                },
                component: MessagePopupContainerComponent,
                onCloseCallback: () => {
                    this.urlRouteManagerService.moveOnPage({
                        url: [
                            UrlPath.MAIN,
                            this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(),
                            this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(),
                            this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime()
                        ]
                    });
                }
            }, {
                resolver: this.componentFactoryResolver,
                injector: this.injector
            });
        } else {
            this.http.post<{ metadata: ITransactionMetaData[] }>(this.requestURL, this.makeRequestOptionsArgs(), {
                headers: new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
            }).subscribe((responseData: { metadata: ITransactionMetaData[] }) => {
                const responseLength = responseData.metadata.length;
                if (this.requestCount !== responseLength) {
                    if (this.requestCount > responseLength) {
                        this.countStatus[1] -= (this.requestCount - responseLength);
                    } else {
                        this.countStatus[1] += (responseLength - this.requestCount);
                    }
                }
                if (responseLength === 0) {
                    this.outFullRange();
                } else {
                    this.countStatus[0] += responseLength;
                    if (this.countStatus[0] === this.countStatus[1]) {
                        this.outFullRange();
                    } else {
                        this.outTransactionDataRange.next([
                            responseData.metadata[responseLength - 1].collectorAcceptTime,
                            this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getDate().valueOf()
                        ]);
                    }
                    this.outTransactionDataLoad.next(responseData.metadata);
                }
                this.outTransactionDataCount.next(this.countStatus);
            }, (error: IServerErrorFormat) => {
                this.dynamicPopupService.openPopup({
                    data: {
                        title: 'Error',
                        contents: error
                    },
                    component: ServerErrorPopupContainerComponent,
                    onCloseCallback: () => {
                        this.urlRouteManagerService.reload();
                    }
                }, {
                    resolver: this.componentFactoryResolver,
                    injector: this.injector
                });
            });
        }
    }
    moreLoad(): void {
        this.loadData();
    }
    private outFullRange(): void {
        this.outTransactionDataRange.next([
            this.newUrlStateNotificationService.getStartTimeToNumber(),
            this.newUrlStateNotificationService.getEndTimeToNumber()
        ]);
    }
    private makeRequestOptionsArgs(): string {
        const requestStr = [];
        const len = this.requestSourceData.length;
        const appName = this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getApplicationName();
        const maxLen = Math.min(len, this.maxLoadLength + this.lastFetchedIndex);

        for (let index = 0, dataIndex = this.lastFetchedIndex; dataIndex < maxLen; index++, dataIndex++) {
            // transactionId, x, y
            requestStr.push(`I${index}=${this.requestSourceData[dataIndex][0]}`);
            requestStr.push(`T${index}=${this.requestSourceData[dataIndex][1]}`);
            requestStr.push(`R${index}=${this.requestSourceData[dataIndex][2]}`);
        }

        this.requestCount = requestStr.length / 3;
        this.lastFetchedIndex = maxLen;

        return `ApplicationName=${appName}&${requestStr.join('&')}`;
        // load from parent window;
        // 브라우저 윈도우 이름으로 아래의 정보를 넘김
        // applicationName
        // oDragXY.fromX
        // oDragXY.toX
        // oDragXY.fromY
        // oDragXY.toY
        // agent
        // inclue?
        // Success/Failed 정보는 현재 window.opener.htoScatter['applicationName'] 에 저장해 둔 Scatter 객체가 가지고 있음.
        // window.htoScatter['']
        //
        // transactionList 데이터의 총합은 이전 window에서 가져옴.
        // indicator의 range는
        // 가져온 데이터 중 가장 예전의 collectorAcceptTime ~ endTime
        // 가져온 데이터의 갯수가 0 이거나 total 보다 커지면 끝
        // 요청 갯수와 응답 갯수가 다른 경우 total 값을 계속 update 해줘야 함.
        // 10개 transaction 데이터를 요청했는데 11개 혹은 12개가 오는 케이스가 있음.
        // --한번에 요청하는 갯수는 일단 최대 100개
{'fraction_non_alphanumeric': 0.10048426150121065, 'fraction_numerical': 0.003950554351981649, 'mean_word_length': 2.072631166797181, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6966520', 'n_tokens_mistral': 4267, 'n_tokens_neox': 4292, 'n_words': 714}