import { BehaviorSubject } from 'rxjs';
import { filter, map } from 'rxjs/operators';
import { __decorate, __awaiter, __param } from 'tslib';
import { Injectable, Optional, SkipSelf, NgModule } from '@angular/core';
import { HttpClient, HttpClientModule } from '@angular/common/http';

class ApiConfig {
}

class DataSourceRequest {
    constructor() {
        // Data.
        this._request$ = new BehaviorSubject(null);
        this._loading$ = new BehaviorSubject(true);
    }
    get loading() {
        return this._loading$.asObservable();
    }
    get when() {
        return this._request$.pipe(filter(data => !!data));
    }
    startLoading() {
        this._loading$.next(true);
    }
    stopLoading() {
        this._loading$.next(false);
    }
    update(params = {}) {
        const currentValue = this._request$.getValue();
        // Set the page number to 1 if the query or page size was changed.
        if (currentValue && params && (currentValue.query !== params.query || currentValue.pageSize !== params.pageSize)) {
            params.pageNumber = 1;
        }
        this._request$.next(Object.assign(Object.assign({}, currentValue), params));
    }
}
class ApiDataSource {
}

let ApiMapper = class ApiMapper {
    toPageResponse(data) {
        return {
            pageSize: data['page_size'],
            pageNumber: data['page_number'],
            totalPages: data['total_pages'],
            totalEntries: data['total_entries'],
            data: data['data']
        };
    }
    toPageRequest(data) {
        const params = {};
        params['page'] = `${data.pageNumber || 1}`;
        params['page_size'] = `${data.pageSize || 25}`;
        const sort = (data.sort || [])
            .map(({ name }) => name)
            .filter(name => !!name)
            .join(',');
        const sortDirection = (data.sort || [])
            .map(({ direction }) => direction)
            .filter(direction => !!direction)
            .join(',');
        if (sort.length > 0 && sortDirection.length > 0) {
            params['sort'] = sort;
            params['sort_direction'] = sortDirection;
        }
        if (data.query && data.query.length > 0 && data.queryFields && data.queryFields.length > 0) {
            params['query'] = data.query;
            params['query_fields'] = data.queryFields.join(',');
        }
        return params;
    }
};
ApiMapper = __decorate([
    Injectable()
], ApiMapper);

let Api = class Api {
    constructor(_http, _mapper, _config) {
        this._http = _http;
        this._mapper = _mapper;
        this._config = _config;
        // Validate the config exists.
        if (!this._config) {
            throw new Error('API configuration was not received properly.');
        }
        // Cache the base url.
        this._baseUrl = this._config.baseUrl;
    }
    page(endpoint, params = {}, options) {
        // Compose the params and headers.
        const pageParams = this._mapper.toPageRequest(params);
        const extraParams = (options && options.params) || {};
        const extraHeaders = (options && options.headers) || {};
        // Return an observable so it can be a stream.
        return this.get(endpoint, {
            headers: extraHeaders,
            params: Object.assign(Object.assign({}, pageParams), extraParams)
        }).pipe(map(response => this._mapper.toPageResponse(response)));
    }
    get(endpoint, options) {
        // Add the base url to the endpoint.
        const url = this.toAbsoluteUrl(endpoint);
        // Return an observable so it can be a stream.
        return this._http.get(url, options);
    }
    post(endpoint, body) {
        return __awaiter(this, void 0, void 0, function* () {
            // Add the base url to the endpoint.
            const url = this.toAbsoluteUrl(endpoint);
            // Execute the post call as a promise.
            return yield this._http.post(url, body).toPromise();
        });
    }
    put(endpoint, body) {
        return __awaiter(this, void 0, void 0, function* () {
            // Add the base url to the endpoint.
            const url = this.toAbsoluteUrl(endpoint);
            // Execute the put call as a promise.
            return yield this._http.put(url, body).toPromise();
        });
    }
    patch(endpoint, body) {
        return __awaiter(this, void 0, void 0, function* () {
            // Add the base url to the endpoint.
            const url = this.toAbsoluteUrl(endpoint);
            // Execute the patch call as a promise.
            return yield this._http.patch(url, body).toPromise();
        });
    }
    delete(endpoint) {
        return __awaiter(this, void 0, void 0, function* () {
            // Add the base url to the endpoint.
            const url = this.toAbsoluteUrl(endpoint);
            // Execute the delete call as a promise.
            return yield this._http.delete(url).toPromise();
        });
    }
    toAbsoluteUrl(endpoint) {
        return `${this._baseUrl}${endpoint}`;
    }
};
Api.ctorParameters = () => [
    { type: HttpClient },
    { type: ApiMapper },
    { type: ApiConfig, decorators: [{ type: Optional }] }
];
Api = __decorate([
    Injectable(),
    __param(2, Optional())
], Api);

class ApiError {
    constructor(_status, _error) {
        this._status = _status;
        this._error = _error;
    }
    get status() {
        return this._status;
    }
    get error() {
        return this._error;
    }
    get(token, delimiter = '.') {
        const tokens = (token || '').split(delimiter);
        const result = tokens.reduce((previous, token) => {
            if (previous && previous[token]) {
                return previous[token];
            }
            return null;
        }, this._error || {});
        return result;
    }
    has(token, delimiter = '.') {
        return !!this.get(token, delimiter);
    }
    includes(token, value) {
        const array = this.get(token);
        return (array || []).includes(value);
    }
}

var ApiModule_1;
let ApiModule = ApiModule_1 = class ApiModule {
    constructor(_parent) {
        if (_parent) {
            throw new Error('ApiModule is already loaded; Import it in the AppModule only.');
        }
    }
    static forRoot(config) {
        return {
            ngModule: ApiModule_1,
            providers: [
                { provide: ApiConfig, useValue: config },
                Api
            ]
        };
    }
};
ApiModule.ctorParameters = () => [
    { type: ApiModule, decorators: [{ type: Optional }, { type: SkipSelf }] }
];
ApiModule = ApiModule_1 = __decorate([
    NgModule({
        imports: [
            HttpClientModule
        ],
        providers: [
            { provide: ApiMapper, useClass: ApiMapper }
        ]
    }),
    __param(0, Optional()), __param(0, SkipSelf())
], ApiModule);

/**
 * Generated bundle index. Do not edit.
 */

export { Api, ApiConfig, ApiDataSource, ApiError, ApiMapper, ApiModule, DataSourceRequest };
//# sourceMappingURL=bravobit-bb-foundation-api.js.map
