import { Injectable, Injector, Optional, Directive, TemplateRef, ViewContainerRef, Input, ɵɵdefineInjectable, ɵɵinject, APP_INITIALIZER, NgModule } from '@angular/core';
import { first, map, tap, distinctUntilChanged, catchError, filter, take, switchMap, finalize } from 'rxjs/operators';
import { __awaiter, __rest } from 'tslib';
import { Storage } from '@bravobit/bb-foundation/storage';
import { Api, ApiError } from '@bravobit/bb-foundation/api';
import { BehaviorSubject, of, throwError } from 'rxjs';
import { Router } from '@angular/router';
import { HttpErrorResponse, HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';

/**
 * @fileoverview added by tsickle
 * Generated from: lib/interfaces/token.interface.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
/**
 * @record
 */
function AuthToken() { }
if (false) {
    /** @type {?|undefined} */
    AuthToken.prototype.id;
    /** @type {?|undefined} */
    AuthToken.prototype.type;
    /** @type {?|undefined} */
    AuthToken.prototype.audience;
    /** @type {?|undefined} */
    AuthToken.prototype.issuer;
    /** @type {?|undefined} */
    AuthToken.prototype.subject;
    /** @type {?|undefined} */
    AuthToken.prototype.notValidBefore;
    /** @type {?|undefined} */
    AuthToken.prototype.expiresAt;
    /** @type {?|undefined} */
    AuthToken.prototype.issuedAt;
    /** @type {?|undefined} */
    AuthToken.prototype.role;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/interfaces/config.interface.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
class AuthConfig {
}
if (false) {
    /** @type {?} */
    AuthConfig.prototype.scheme;
    /** @type {?} */
    AuthConfig.prototype.redirectUrl;
    /** @type {?} */
    AuthConfig.prototype.loggedInUrl;
    /** @type {?} */
    AuthConfig.prototype.bootstrap;
    /** @type {?} */
    AuthConfig.prototype.applicationId;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/interfaces/mapper.interface.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
/**
 * @record
 */
function AuthMapperProtocol() { }
if (false) {
    /** @type {?} */
    AuthMapperProtocol.prototype.me;
    /** @type {?} */
    AuthMapperProtocol.prototype.register;
    /** @type {?} */
    AuthMapperProtocol.prototype.logout;
    /** @type {?} */
    AuthMapperProtocol.prototype.refresh;
    /** @type {?} */
    AuthMapperProtocol.prototype.resetPassword;
    /** @type {?} */
    AuthMapperProtocol.prototype.requestPassword;
    /**
     * @param {?} data
     * @return {?}
     */
    AuthMapperProtocol.prototype.role = function (data) { };
    /**
     * @param {?} data
     * @return {?}
     */
    AuthMapperProtocol.prototype.toRegister = function (data) { };
    /**
     * @param {?} data
     * @return {?}
     */
    AuthMapperProtocol.prototype.toRefresh = function (data) { };
}
/**
 * @record
 */
function AuthTokenResponse() { }
if (false) {
    /** @type {?} */
    AuthTokenResponse.prototype.accessToken;
    /** @type {?} */
    AuthTokenResponse.prototype.refreshToken;
}
/**
 * @record
 */
function AuthUserTokenResponse() { }
if (false) {
    /** @type {?} */
    AuthUserTokenResponse.prototype.user;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/interfaces/provider.interface.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
/**
 * @record
 */
function AuthProvider() { }
if (false) {
    /**
     * @param {?} api
     * @return {?}
     */
    AuthProvider.prototype.authenticate = function (api) { };
}
/**
 * @record
 */
function AuthProviderResponse() { }
if (false) {
    /** @type {?|undefined} */
    AuthProviderResponse.prototype.user;
    /** @type {?|undefined} */
    AuthProviderResponse.prototype.provider;
    /** @type {?|undefined} */
    AuthProviderResponse.prototype.verifyToken;
    /** @type {?|undefined} */
    AuthProviderResponse.prototype.accessToken;
    /** @type {?|undefined} */
    AuthProviderResponse.prototype.refreshToken;
}
/**
 * @record
 */
function AuthSignInResponse() { }
if (false) {
    /** @type {?|undefined} */
    AuthSignInResponse.prototype.user;
    /** @type {?|undefined} */
    AuthSignInResponse.prototype.provider;
    /** @type {?|undefined} */
    AuthSignInResponse.prototype.verifyToken;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/helpers/jwt.helper.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
class JwtHelper {
    constructor() {
        this.baseDecodeUnicode = (/**
         * @param {?} value
         * @return {?}
         */
        (value) => {
            return decodeURIComponent(atob(value).replace(/(.)/g, (/**
             * @param {?} m
             * @param {?} p
             * @return {?}
             */
            (m, p) => {
                /** @type {?} */
                let code = p.charCodeAt(0).toString(16).toUpperCase();
                if (code.length < 2) {
                    code = '0' + code;
                }
                return '%' + code;
            })));
        });
        this.parse = (/**
         * @param {?} data
         * @return {?}
         */
        (data) => {
            return (/** @type {?} */ ({
                id: data['iss'] || null,
                type: data['typ'] || null,
                audience: data['aud'] || null,
                issuer: data['iss'] || null,
                subject: data['sub'] || null,
                role: data['role'] || null,
                notValidBefore: this.parseDate(data['nbf']),
                expiresAt: this.parseDate(data['exp']),
                issuedAt: this.parseDate(data['iat'])
            }));
        });
        this.parseDate = (/**
         * @param {?} epochInSeconds
         * @return {?}
         */
        (epochInSeconds) => {
            if (!epochInSeconds || epochInSeconds <= 0) {
                return null;
            }
            return new Date(epochInSeconds * 1000);
        });
    }
    /**
     * @param {?} token
     * @return {?}
     */
    decode(token) {
        try {
            /** @type {?} */
            const json = JSON.parse(this.urlDecode(token.split('.')[1]));
            return this.parse(json);
        }
        catch (_a) {
            return null;
        }
    }
    /**
     * @private
     * @param {?} token
     * @return {?}
     */
    urlDecode(token) {
        /** @type {?} */
        const value = token || '';
        /** @type {?} */
        let output = value
            .replace(/-/g, '+')
            .replace(/_/g, '/');
        switch (output.length % 4) {
            case 0:
                break;
            case 2:
                output += '==';
                break;
            case 3:
                output += '=';
                break;
            default:
                throw 'Illegal base64url string!';
        }
        try {
            return this.baseDecodeUnicode(output);
        }
        catch (_a) {
            return atob(output);
        }
    }
}
if (false) {
    /**
     * @type {?}
     * @private
     */
    JwtHelper.prototype.baseDecodeUnicode;
    /**
     * @type {?}
     * @private
     */
    JwtHelper.prototype.parse;
    /**
     * @type {?}
     * @private
     */
    JwtHelper.prototype.parseDate;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/helpers/mapper.helper.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
class AuthMapper {
    constructor() {
        // Routes.
        this.me = 'auth/me';
        this.register = 'auth/register';
        this.logout = 'auth/logout';
        this.refresh = 'auth/refresh';
        this.requestPassword = 'auth/reset';
        this.resetPassword = 'auth/reset-password';
    }
    /**
     * @param {?} data
     * @return {?}
     */
    role(data) {
        return (data && data.role) || null;
    }
    /**
     * @param {?} data
     * @return {?}
     */
    toRegister(data) {
        // Retrieve the params.
        const { token, refresh_token, user } = data;
        // Map the data to the correct format.
        return { accessToken: token, refreshToken: refresh_token, user: user };
    }
    /**
     * @param {?} data
     * @return {?}
     */
    toRefresh(data) {
        // Retrieve the params.
        const { token, refresh_token } = data;
        // Map the data to the correct format.
        return { accessToken: token, refreshToken: refresh_token };
    }
}
if (false) {
    /** @type {?} */
    AuthMapper.prototype.me;
    /** @type {?} */
    AuthMapper.prototype.register;
    /** @type {?} */
    AuthMapper.prototype.logout;
    /** @type {?} */
    AuthMapper.prototype.refresh;
    /** @type {?} */
    AuthMapper.prototype.requestPassword;
    /** @type {?} */
    AuthMapper.prototype.resetPassword;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/providers/verify.provider.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
class AuthVerifyProvider {
    /**
     * @param {?} _code
     * @param {?} _verifyToken
     * @param {?=} _endpoint
     */
    constructor(_code, _verifyToken, _endpoint = 'auth/verify') {
        this._code = _code;
        this._verifyToken = _verifyToken;
        this._endpoint = _endpoint;
    }
    /**
     * @param {?} api
     * @return {?}
     */
    authenticate(api) {
        return __awaiter(this, void 0, void 0, function* () {
            // Execute API call.
            const { token, refresh_token, user } = yield api.post(this._endpoint, {
                token: this._code,
                verify_token: this._verifyToken
            });
            // Map the data to the correct format.
            return { accessToken: token, refreshToken: refresh_token, user: user };
        });
    }
}
if (false) {
    /**
     * @type {?}
     * @private
     */
    AuthVerifyProvider.prototype._code;
    /**
     * @type {?}
     * @private
     */
    AuthVerifyProvider.prototype._verifyToken;
    /**
     * @type {?}
     * @private
     */
    AuthVerifyProvider.prototype._endpoint;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/providers/email.provider.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
class AuthEmailProvider {
    /**
     * @param {?} _email
     * @param {?} _password
     * @param {?=} _endpoint
     */
    constructor(_email, _password, _endpoint = 'auth/login') {
        this._email = _email;
        this._password = _password;
        this._endpoint = _endpoint;
    }
    /**
     * @param {?} api
     * @return {?}
     */
    authenticate(api) {
        return __awaiter(this, void 0, void 0, function* () {
            // Execute API call.
            const { token, refresh_token, user, provider, verify_token } = yield api.post(this._endpoint, {
                email: this._email,
                password: this._password
            });
            // Map the data to the correct format.
            return {
                accessToken: token,
                refreshToken: refresh_token,
                user: user,
                provider: provider,
                verifyToken: verify_token
            };
        });
    }
}
if (false) {
    /**
     * @type {?}
     * @private
     */
    AuthEmailProvider.prototype._email;
    /**
     * @type {?}
     * @private
     */
    AuthEmailProvider.prototype._password;
    /**
     * @type {?}
     * @private
     */
    AuthEmailProvider.prototype._endpoint;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/auth.service.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
class Auth {
    /**
     * @param {?} _storage
     * @param {?} _mapper
     * @param {?} _injector
     * @param {?=} _api
     * @param {?=} _config
     */
    constructor(_storage, _mapper, _injector, _api, _config) {
        this._storage = _storage;
        this._mapper = _mapper;
        this._injector = _injector;
        this._api = _api;
        this._config = _config;
        // Data.
        this._user$ = new BehaviorSubject(null);
        // Validate the API was injected.
        if (!this._api) {
            throw new Error('The API is required for this module to work.');
        }
        // Set the storage keys based on the application id.
        /** @type {?} */
        const applicationId = (this._config && this._config.applicationId) || 'angular';
        this._apiUserStorageKey = `${applicationId}_auth-user`;
        this._apiTokenStorageKey = `${applicationId}_auth-token`;
        this._apiRefreshTokenStorageKey = `${applicationId}_auth-refresh-token`;
        // Fetch the user from the storage.
        /** @type {?} */
        const user = this._storage.cookie.get(this._apiUserStorageKey);
        // Cache the user in memory.
        this._user$.next(user);
    }
    /**
     * @private
     * @return {?}
     */
    get router() {
        return this._injector.get(Router);
    }
    /**
     * @return {?}
     */
    initialize() {
        return (/**
         * @return {?}
         */
        () => __awaiter(this, void 0, void 0, function* () {
            /** @type {?} */
            const shouldBootstrap = (this._config && this._config.bootstrap) === undefined
                ? true
                : this._config.bootstrap;
            // Check if the app should bootstrap
            // the authentication.
            if (!shouldBootstrap) {
                return;
            }
            // Only retrieve from the server
            // when an access token is saved.
            if (!this.accessToken && !this.refreshToken) {
                return;
            }
            // Try to fetch the user from the server.
            /** @type {?} */
            const user = yield this.me().pipe(first()).toPromise();
            // Save the user in the storage.
            return this.setUser(user);
        }));
    }
    /**
     * @return {?}
     */
    get isAuthenticated() {
        return !!this.payload;
    }
    /**
     * @return {?}
     */
    get user() {
        return this._user$.asObservable();
    }
    /**
     * @return {?}
     */
    get accessToken() {
        return this._storage.cookie.get(this._apiTokenStorageKey);
    }
    /**
     * @return {?}
     */
    get refreshToken() {
        return this._storage.cookie.get(this._apiRefreshTokenStorageKey);
    }
    /**
     * @return {?}
     */
    get payload() {
        return new JwtHelper().decode(this.accessToken);
    }
    /**
     * @template T
     * @return {?}
     */
    me() {
        return this._api.get(this._mapper.me);
    }
    /**
     * @param {?} provider
     * @param {?=} as
     * @return {?}
     */
    signIn(provider, as) {
        return __awaiter(this, void 0, void 0, function* () {
            const _a = yield provider.authenticate(this._api), { accessToken, refreshToken, user } = _a, result = __rest(_a, ["accessToken", "refreshToken", "user"]);
            // Check if the role matches.
            if (as && !as.includes(this._mapper.role(user))) {
                throw new Error('Invalid role.');
            }
            // Validate if the provider is one of the available
            // providers then return the user object and the provider.
            /** @type {?} */
            const apiProvider = (result && result.provider) || null;
            /** @type {?} */
            const apiVerifyToken = (result && result.verifyToken) || null;
            /** @type {?} */
            const availableProviders = ['email'];
            if (availableProviders.includes(apiProvider)) {
                return (/** @type {?} */ ({ user, provider: apiProvider, verifyToken: apiVerifyToken }));
            }
            // Set the tokens in storage.
            this.setTokens(accessToken, refreshToken);
            // Set the user in storage.
            this.setUser(user);
            // Return the user.
            return (/** @type {?} */ ({ user }));
        });
    }
    /**
     * @param {?} email
     * @param {?} password
     * @param {?=} as
     * @return {?}
     */
    signInWithEmail(email, password, as) {
        return __awaiter(this, void 0, void 0, function* () {
            return this.signIn(new AuthEmailProvider(email, password), as);
        });
    }
    /**
     * @param {?} code
     * @param {?} verifyToken
     * @return {?}
     */
    signInWithVerifyCode(code, verifyToken) {
        return __awaiter(this, void 0, void 0, function* () {
            return this.signIn(new AuthVerifyProvider(code, verifyToken));
        });
    }
    /**
     * @template T
     * @param {?} data
     * @return {?}
     */
    register(data) {
        return __awaiter(this, void 0, void 0, function* () {
            // Execute API call.
            /** @type {?} */
            const result = yield this._api.post(this._mapper.register, data);
            // Map to the correct response.
            const { accessToken, refreshToken, user } = this._mapper.toRegister(result);
            // Set the tokens in storage.
            this.setTokens(accessToken, refreshToken);
            // Set the user in storage.
            this.setUser(user);
            // Return the user.
            return user;
        });
    }
    /**
     * @return {?}
     */
    logout() {
        try {
            // Log the user out.
            this._api.get(this._mapper.logout, { headers: { Authorization: this.refreshToken } })
                .toPromise().then((/**
             * @param {?} _
             * @return {?}
             */
            _ => _));
        }
        catch (_a) {
            // Do nothing because the tokens will be deleted anyways from the storage.
        }
        // Delete the tokens from the session.
        return this.clear();
    }
    /**
     * @return {?}
     */
    refresh() {
        // If the refresh token does
        // not exist just return an observable of null.
        if (!this.refreshToken) {
            return of(null);
        }
        // Perform the refresh call.
        /** @type {?} */
        const scheme = (this._config && this._config.scheme) || 'Bearer';
        return this._api.get(this._mapper.refresh, {
            headers: {
                'Authorization': `${scheme} ${this.refreshToken}`,
                'X-No-Authorization': 'yes'
            }
        }).pipe(map((/**
         * @param {?} data
         * @return {?}
         */
        data => this._mapper.toRefresh(data))), tap((/**
         * @param {?} __0
         * @return {?}
         */
        ({ accessToken, refreshToken }) => this.setTokens(accessToken, refreshToken))), map((/**
         * @param {?} __0
         * @return {?}
         */
        ({ accessToken }) => accessToken)));
    }
    /**
     * @param {?} email
     * @return {?}
     */
    requestPassword(email) {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                return yield this._api.post(this._mapper.requestPassword, { email });
            }
            catch (error) {
                throw error;
            }
        });
    }
    /**
     * @param {?} token
     * @param {?} newPassword
     * @return {?}
     */
    resetPassword(token, newPassword) {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                return yield this._api.post(this._mapper.resetPassword, { token, password: newPassword });
            }
            catch (error) {
                throw error;
            }
        });
    }
    /**
     * @param {?} type
     * @return {?}
     */
    guard(type) {
        /** @type {?} */
        let url = null;
        switch (type) {
            case 'authenticated':
                url = this._config && this._config.loggedInUrl;
                break;
            case 'unauthenticated':
                url = this._config && this._config.redirectUrl;
                break;
        }
        if (this.router && url) {
            return this.router.parseUrl(url);
        }
        return false;
    }
    /**
     * @param {?=} accessToken
     * @param {?=} refreshToken
     * @return {?}
     */
    setTokens(accessToken, refreshToken) {
        // Set the token if the token exists.
        if (accessToken) {
            const { expiresAt } = new JwtHelper().decode(accessToken);
            this._storage.cookie.set(this._apiTokenStorageKey, accessToken, {
                expires: expiresAt
            });
        }
        // Set the refresh token if the refresh token exists.
        if (refreshToken) {
            const { expiresAt } = new JwtHelper().decode(refreshToken);
            this._storage.cookie.set(this._apiRefreshTokenStorageKey, refreshToken, {
                expires: expiresAt
            });
        }
    }
    /**
     * @param {?} user
     * @return {?}
     */
    setUser(user) {
        // Validate the user exists.
        if (!user) {
            return;
        }
        // Push the next user.
        this._user$.next(user);
        // Make the user data valid for one year.
        /** @type {?} */
        const date = new Date();
        date.setFullYear(date.getFullYear() + 1);
        /** @type {?} */
        const timestamp = date.getTime();
        // Save the user in the storage.
        return this._storage.cookie.set(this._apiUserStorageKey, user, {
            expires: timestamp
        });
    }
    /**
     * @return {?}
     */
    clear() {
        // Delete the items from the local storage.
        this._storage.cookie.remove(this._apiUserStorageKey);
        this._storage.cookie.remove(this._apiTokenStorageKey);
        this._storage.cookie.remove(this._apiRefreshTokenStorageKey);
        // Push an empty user.
        this._user$.next(null);
    }
}
Auth.decorators = [
    { type: Injectable }
];
/** @nocollapse */
Auth.ctorParameters = () => [
    { type: Storage },
    { type: AuthMapper },
    { type: Injector },
    { type: Api, decorators: [{ type: Optional }] },
    { type: AuthConfig, decorators: [{ type: Optional }] }
];
if (false) {
    /**
     * @type {?}
     * @private
     */
    Auth.prototype._apiUserStorageKey;
    /**
     * @type {?}
     * @private
     */
    Auth.prototype._apiTokenStorageKey;
    /**
     * @type {?}
     * @private
     */
    Auth.prototype._apiRefreshTokenStorageKey;
    /**
     * @type {?}
     * @private
     */
    Auth.prototype._user$;
    /**
     * @type {?}
     * @private
     */
    Auth.prototype._storage;
    /**
     * @type {?}
     * @private
     */
    Auth.prototype._mapper;
    /**
     * @type {?}
     * @private
     */
    Auth.prototype._injector;
    /**
     * @type {?}
     * @private
     */
    Auth.prototype._api;
    /**
     * @type {?}
     * @private
     */
    Auth.prototype._config;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/directives/authenticated.directive.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
class BbAuthenticated {
    /**
     * @param {?} _auth
     * @param {?} _template
     * @param {?} _viewContainerRef
     */
    constructor(_auth, _template, _viewContainerRef) {
        this._auth = _auth;
        this._template = _template;
        this._viewContainerRef = _viewContainerRef;
    }
    /**
     * @return {?}
     */
    ngOnInit() {
        this._subscription = this._auth.user.pipe(map((/**
         * @param {?} user
         * @return {?}
         */
        user => !!user)), distinctUntilChanged()).subscribe((/**
         * @param {?} isAuthenticated
         * @return {?}
         */
        isAuthenticated => {
            if (isAuthenticated) {
                this._viewContainerRef.createEmbeddedView(this._template);
            }
            else {
                this._viewContainerRef.clear();
            }
        }));
    }
    /**
     * @return {?}
     */
    ngOnDestroy() {
        this._subscription && this._subscription.unsubscribe();
    }
}
BbAuthenticated.decorators = [
    { type: Directive, args: [{
                selector: '[bbAuthenticated]'
            },] }
];
/** @nocollapse */
BbAuthenticated.ctorParameters = () => [
    { type: Auth },
    { type: TemplateRef },
    { type: ViewContainerRef }
];
if (false) {
    /**
     * @type {?}
     * @private
     */
    BbAuthenticated.prototype._subscription;
    /**
     * @type {?}
     * @private
     */
    BbAuthenticated.prototype._auth;
    /**
     * @type {?}
     * @private
     */
    BbAuthenticated.prototype._template;
    /**
     * @type {?}
     * @private
     */
    BbAuthenticated.prototype._viewContainerRef;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/directives/role.directive.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
class BbRole {
    /**
     * @param {?} _auth
     * @param {?} _template
     * @param {?} _viewContainerRef
     */
    constructor(_auth, _template, _viewContainerRef) {
        this._auth = _auth;
        this._template = _template;
        this._viewContainerRef = _viewContainerRef;
        this.getPermissions = (/**
         * @param {?} value
         * @return {?}
         */
        (value) => {
            return Array.isArray(value) ? value : [value];
        });
    }
    /**
     * @return {?}
     */
    ngOnInit() {
        this._subscription = this._auth.user.pipe(map((/**
         * @param {?} user
         * @return {?}
         */
        user => (user && user.role) || null)), distinctUntilChanged()).subscribe((/**
         * @param {?} role
         * @return {?}
         */
        role => {
            /** @type {?} */
            const permissions = this.getPermissions(this.bbRole);
            if (permissions.includes(role)) {
                this._viewContainerRef.createEmbeddedView(this._template);
            }
            else {
                this._viewContainerRef.clear();
            }
        }));
    }
    /**
     * @return {?}
     */
    ngOnDestroy() {
        this._subscription && this._subscription.unsubscribe();
    }
}
BbRole.decorators = [
    { type: Directive, args: [{
                selector: '[bbRole]'
            },] }
];
/** @nocollapse */
BbRole.ctorParameters = () => [
    { type: Auth },
    { type: TemplateRef },
    { type: ViewContainerRef }
];
BbRole.propDecorators = {
    bbRole: [{ type: Input }]
};
if (false) {
    /** @type {?} */
    BbRole.prototype.bbRole;
    /**
     * @type {?}
     * @private
     */
    BbRole.prototype._subscription;
    /**
     * @type {?}
     * @private
     */
    BbRole.prototype.getPermissions;
    /**
     * @type {?}
     * @private
     */
    BbRole.prototype._auth;
    /**
     * @type {?}
     * @private
     */
    BbRole.prototype._template;
    /**
     * @type {?}
     * @private
     */
    BbRole.prototype._viewContainerRef;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/guards/anonymous.guard.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
class BbAnonymousGuard {
    /**
     * @param {?} _auth
     */
    constructor(_auth) {
        this._auth = _auth;
    }
    /**
     * @param {?} route
     * @param {?} state
     * @return {?}
     */
    canActivate(route, state) {
        // If the user is not authenticated it can
        // access the anonymous page.
        if (!this._auth.isAuthenticated) {
            return true;
        }
        // Return the user back to the authenticated page.
        return this._auth.guard('authenticated');
    }
    /**
     * @param {?} childRoute
     * @param {?} state
     * @return {?}
     */
    canActivateChild(childRoute, state) {
        return this.canActivate(childRoute, state);
    }
}
BbAnonymousGuard.decorators = [
    { type: Injectable, args: [{
                providedIn: 'root'
            },] }
];
/** @nocollapse */
BbAnonymousGuard.ctorParameters = () => [
    { type: Auth }
];
/** @nocollapse */ BbAnonymousGuard.ngInjectableDef = ɵɵdefineInjectable({ factory: function BbAnonymousGuard_Factory() { return new BbAnonymousGuard(ɵɵinject(Auth)); }, token: BbAnonymousGuard, providedIn: "root" });
if (false) {
    /**
     * @type {?}
     * @private
     */
    BbAnonymousGuard.prototype._auth;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/guards/authenticated.guard.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
class BbAuthenticatedGuard {
    /**
     * @param {?} _auth
     */
    constructor(_auth) {
        this._auth = _auth;
    }
    /**
     * @param {?} route
     * @param {?} state
     * @return {?}
     */
    canActivate(route, state) {
        // If the user is authenticated it can
        // access the authenticated page.
        if (this._auth.isAuthenticated) {
            return true;
        }
        // The user is not authorized to see that
        // page so un-authorize him.
        return this._auth.guard('unauthenticated');
    }
    /**
     * @param {?} childRoute
     * @param {?} state
     * @return {?}
     */
    canActivateChild(childRoute, state) {
        return this.canActivate(childRoute, state);
    }
}
BbAuthenticatedGuard.decorators = [
    { type: Injectable, args: [{
                providedIn: 'root'
            },] }
];
/** @nocollapse */
BbAuthenticatedGuard.ctorParameters = () => [
    { type: Auth }
];
/** @nocollapse */ BbAuthenticatedGuard.ngInjectableDef = ɵɵdefineInjectable({ factory: function BbAuthenticatedGuard_Factory() { return new BbAuthenticatedGuard(ɵɵinject(Auth)); }, token: BbAuthenticatedGuard, providedIn: "root" });
if (false) {
    /**
     * @type {?}
     * @private
     */
    BbAuthenticatedGuard.prototype._auth;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/auth.interceptor.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
class AuthInterceptor {
    /**
     * @param {?} _auth
     * @param {?} _router
     * @param {?} _config
     */
    constructor(_auth, _router, _config) {
        this._auth = _auth;
        this._router = _router;
        this._config = _config;
        // Data.
        this.isRefreshing = false;
        this.token$ = new BehaviorSubject(null);
        this.getToken = (/**
         * @param {?} request
         * @return {?}
         */
        (request) => {
            // Get the token based on header.
            if (request.headers.has('Authorization')) {
                return request.headers.get('Authorization');
            }
            // Return the default access token.
            return this._auth.accessToken;
        });
        this.composeRequest = (/**
         * @param {?} request
         * @param {?=} token
         * @return {?}
         */
        (request, token = null) => {
            // If the token is not set, delete the authorization header.
            if (!token) {
                return request.clone({ headers: request.headers.delete('Authorization') });
            }
            // Get the auth scheme from the config,
            // if the scheme was not set use bearer.
            /** @type {?} */
            const authScheme = (this._config && this._config.scheme) || 'Bearer';
            // Clone and add the authorization header.
            return request.clone({
                setHeaders: { Authorization: `${authScheme} ${token}` }
            });
        });
    }
    /**
     * @param {?} request
     * @param {?} next
     * @return {?}
     */
    intercept(request, next) {
        // Just return when the user is performing an refresh request.
        if (request.headers.has('X-No-Authorization')) {
            /** @type {?} */
            const newRequest = request.clone({ headers: request.headers.delete('X-No-Authorization') });
            return next.handle(newRequest);
        }
        // Compose the new request.
        /** @type {?} */
        const newRequest = this.composeRequest(request, this.getToken(request));
        // Handle all errors.
        return next.handle(newRequest).pipe(catchError((/**
         * @param {?} error
         * @return {?}
         */
        error => {
            // Create a custom error.
            /** @type {?} */
            const apiError = new ApiError(error.status, error.error);
            // Check if it is an error response.
            if (!(error instanceof HttpErrorResponse)) {
                return throwError(apiError);
            }
            // Handle a 401 error.
            if (error.status === 401) {
                return this.handle401Error(request, next);
            }
            // Just re-throw the error.
            return throwError(apiError);
        })));
    }
    /**
     * @private
     * @param {?} request
     * @param {?} next
     * @return {?}
     */
    handle401Error(request, next) {
        // If already refreshing wait for the token to complete.
        if (this.isRefreshing) {
            return this.token$.pipe(filter((/**
             * @param {?} token
             * @return {?}
             */
            token => token !== null)), take(1), switchMap((/**
             * @param {?} token
             * @return {?}
             */
            token => next.handle(this.composeRequest(request, token)))));
        }
        // Set the refreshing to true.
        this.isRefreshing = true;
        this.token$.next(null);
        return this._auth.refresh().pipe(switchMap((/**
         * @param {?} newToken
         * @return {?}
         */
        newToken => {
            if (!newToken) {
                return this.logoutUser();
            }
            this.token$.next(newToken);
            return next.handle(this.composeRequest(request, newToken));
        })), catchError((/**
         * @param {?} error
         * @return {?}
         */
        error => {
            return this.logoutUser(error);
        })), finalize((/**
         * @return {?}
         */
        () => {
            this.isRefreshing = false;
        })));
    }
    /**
     * @private
     * @param {?=} error
     * @return {?}
     */
    logoutUser(error) {
        // Delete the tokens from the session.
        this._auth.clear();
        // Compose the route url.
        /** @type {?} */
        const routeUrl = this._config && this._config.redirectUrl;
        // Route back if the user provided a redirect url.
        if (this._router && routeUrl) {
            this._router.navigate([routeUrl]).then((/**
             * @param {?} _
             * @return {?}
             */
            _ => _));
        }
        // Throw the error.
        return throwError(error || 'Invalid refresh token; user was logged out.');
    }
}
AuthInterceptor.decorators = [
    { type: Injectable }
];
/** @nocollapse */
AuthInterceptor.ctorParameters = () => [
    { type: Auth },
    { type: Router, decorators: [{ type: Optional }] },
    { type: AuthConfig, decorators: [{ type: Optional }] }
];
if (false) {
    /** @type {?} */
    AuthInterceptor.prototype.isRefreshing;
    /** @type {?} */
    AuthInterceptor.prototype.token$;
    /**
     * @type {?}
     * @private
     */
    AuthInterceptor.prototype.getToken;
    /**
     * @type {?}
     * @private
     */
    AuthInterceptor.prototype.composeRequest;
    /**
     * @type {?}
     * @private
     */
    AuthInterceptor.prototype._auth;
    /**
     * @type {?}
     * @private
     */
    AuthInterceptor.prototype._router;
    /**
     * @type {?}
     * @private
     */
    AuthInterceptor.prototype._config;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/auth.module.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
/** @type {?} */
const DECLARATIONS_EXPORTS = [
    BbAuthenticated,
    BbRole
];
class AuthModule {
    /**
     * @param {?=} config
     * @return {?}
     */
    static forRoot(config) {
        return {
            ngModule: AuthModule,
            providers: [
                Auth,
                { provide: AuthConfig, useValue: config },
                { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
                { useFactory: initializeAuth, provide: APP_INITIALIZER, deps: [Auth], multi: true }
            ]
        };
    }
}
AuthModule.decorators = [
    { type: NgModule, args: [{
                imports: [HttpClientModule],
                declarations: [...DECLARATIONS_EXPORTS],
                exports: [...DECLARATIONS_EXPORTS],
                providers: [
                    { provide: AuthMapper, useClass: AuthMapper }
                ]
            },] }
];
/**
 * @param {?} auth
 * @return {?}
 */
function initializeAuth(auth) {
    return auth.initialize();
}

/**
 * @fileoverview added by tsickle
 * Generated from: public_api.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */

/**
 * @fileoverview added by tsickle
 * Generated from: bravobit-bb-foundation-auth.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */

export { Auth, AuthConfig, AuthEmailProvider, AuthMapper, AuthModule, AuthVerifyProvider, BbAnonymousGuard, BbAuthenticated, BbAuthenticatedGuard, BbRole, JwtHelper, initializeAuth, AuthInterceptor as ɵa };
//# sourceMappingURL=bravobit-bb-foundation-auth.js.map
