import { __decorate, __param, __awaiter } from 'tslib';
import { Optional, Inject, PLATFORM_ID, ɵɵdefineInjectable, ɵɵinject, Injectable } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { mapTo, map, distinctUntilChanged, shareReplay, debounceTime, startWith } from 'rxjs/operators';
import { of, fromEvent, Observable, merge } from 'rxjs';

const hasV8BreakIterator = (typeof Intl !== 'undefined' && Intl.v8BreakIterator);
let Platform = class Platform {
    constructor(_platformId) {
        this._platformId = _platformId;
    }
    // Browser check.
    get isBrowser() {
        return this._platformId
            ? isPlatformBrowser(this._platformId)
            : typeof document === 'object' && !!document;
    }
    // Rendering engines.
    get isTrident() {
        return this.isBrowser && /(msie|trident)/i.test(navigator.userAgent);
    }
    get isBlink() {
        return this.isBrowser && (!!(window.chrome || hasV8BreakIterator) &&
            typeof CSS !== 'undefined' && !this.isEdge && !this.isTrident);
    }
    get isWebkit() {
        return this.isBrowser && /AppleWebKit/i.test(navigator.userAgent)
            && !this.isBlink && !this.isEdge && !this.isTrident;
    }
    // Browsers.
    get isChrome() {
        return this.isBrowser && /Google Inc./.test(navigator.vendor);
    }
    get isEdge() {
        return this.isBrowser && /(edge)/i.test(navigator.userAgent);
    }
    get isFirefox() {
        return this.isBrowser && /(firefox|minefield)/i.test(navigator.userAgent);
    }
    get isSafari() {
        return this.isBrowser && /safari/i.test(navigator.userAgent) && this.isWebkit;
    }
    // Platforms.
    get isIos() {
        return this.isBrowser && /iPad|iPhone|iPod/.test(navigator.userAgent) && !('MSStream' in window);
    }
    get isAndroid() {
        return this.isBrowser && /android/i.test(navigator.userAgent) && !this.isTrident;
    }
    get isDesktop() {
        return this.isBrowser && !(/(iPhone|iPod|iPad|Android|BlackBerry|IEMobile)/.test(navigator.userAgent));
    }
};
Platform.ctorParameters = () => [
    { type: Object, decorators: [{ type: Optional }, { type: Inject, args: [PLATFORM_ID,] }] }
];
Platform.ɵprov = ɵɵdefineInjectable({ factory: function Platform_Factory() { return new Platform(ɵɵinject(PLATFORM_ID, 8)); }, token: Platform, providedIn: "root" });
Platform = __decorate([
    Injectable({
        providedIn: 'root'
    }),
    __param(0, Optional()), __param(0, Inject(PLATFORM_ID))
], Platform);

let FileLoader = class FileLoader {
    toFile(dataUri, name = 'file') {
        try {
            // Convert base64 to raw binary data held in a string.
            const byteString = window.atob(dataUri.split(',')[1]);
            // Separate out the mime component.
            const mimeString = dataUri.split(',')[0].split(':')[1].split(';')[0];
            // Write the bytes of the string to an ArrayBuffer.
            const arrayBuffer = new ArrayBuffer(byteString.length);
            const uint8Array = new Uint8Array(arrayBuffer);
            for (let index = 0; index < byteString.length; index++) {
                uint8Array[index] = byteString.charCodeAt(index);
            }
            const dataView = new DataView(arrayBuffer);
            const blob = new Blob([dataView.buffer], { type: mimeString });
            // Convert the blob to a file.
            blob.lastModifiedDate = new Date();
            blob.name = name;
            return blob;
        }
        catch (_a) {
            return null;
        }
    }
    asDataUrl(file) {
        return this.read(file, 'dataurl');
    }
    asArrayBuffer(file) {
        return this.read(file, 'arraybuffer');
    }
    read(file, type) {
        return __awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => {
                if (!file || !(file instanceof File)) {
                    return reject('Invalid file');
                }
                const reader = new FileReader();
                reader.onerror = () => reject('Error file read');
                reader.onabort = () => reject('Abort file read');
                reader.onload = () => {
                    const result = reader.result;
                    return resolve(result);
                };
                if (type === 'dataurl') {
                    reader.readAsDataURL(file);
                }
                else if (type === 'arraybuffer') {
                    reader.readAsArrayBuffer(file);
                }
            });
        });
    }
};
FileLoader.ɵprov = ɵɵdefineInjectable({ factory: function FileLoader_Factory() { return new FileLoader(); }, token: FileLoader, providedIn: "root" });
FileLoader = __decorate([
    Injectable({
        providedIn: 'root'
    })
], FileLoader);

let ImageConverter = class ImageConverter {
    constructor(_platform, _fileLoader) {
        this._platform = _platform;
        this._fileLoader = _fileLoader;
        // Data.
        this._types = ['image/png', 'image/jpeg'];
        this.calculateOffsetAndDimensions = (image, canvasWidth, canvasHeight) => {
            const originalWidth = image.width;
            const originalHeight = image.height;
            const widthRatio = canvasWidth / originalWidth;
            const heightRatio = canvasHeight / originalHeight;
            let width;
            let height;
            if (originalWidth > originalHeight) {
                height = originalHeight * heightRatio;
                width = (originalWidth / originalHeight) * height;
            }
            else {
                width = originalWidth * widthRatio;
                height = (originalHeight / originalWidth) * width;
            }
            let xOffset = 0;
            let yOffset = 0;
            if (canvasHeight === height) {
                xOffset = -((width - canvasWidth) / 2);
            }
            else if (canvasWidth === width) {
                yOffset = -((height - canvasHeight) / 2);
            }
            return { xOffset, yOffset, width, height };
        };
    }
    toDataUri(contents, options = null) {
        return __awaiter(this, void 0, void 0, function* () {
            // Check if the current platform is a browser.
            if (!this._platform.isBrowser) {
                return null;
            }
            // Get the image.
            const image = yield this.getImage(contents);
            // Get the canvas width and height.
            const canvasWidth = (options && options.width) || image.width;
            const canvasHeight = (options && options.height) || image.height;
            // Get the canvas and context.
            const canvas = document.createElement('canvas');
            const context = canvas.getContext('2d');
            canvas.width = canvasWidth;
            canvas.height = canvasHeight;
            // Check if dimensions where supplied, else create the image.
            if (!options) {
                // Draw the image.
                context.drawImage(image, 0, 0);
                // Convert the canvas to a data url.
                return canvas.toDataURL(this._types[0]);
            }
            // Get the dimensions and offsets.
            const { width, height, xOffset, yOffset } = this.calculateOffsetAndDimensions(image, canvasWidth, canvasHeight);
            // Draw the image.
            context.drawImage(image, 0, 0, image.width, image.height, xOffset, yOffset, width, height);
            // Convert the canvas to a data url.
            return canvas.toDataURL(this._types[0]);
        });
    }
    fileToImage(file, types = this._types) {
        return __awaiter(this, void 0, void 0, function* () {
            // Check if the file matches an image.
            if (!types.includes(file.type)) {
                throw new Error('The selected file does not meet the required format.');
            }
            // Get the data URI from the file.
            const dataUri = yield this._fileLoader.asDataUrl(file);
            // Convert the data URI to a image element.
            return yield this.stringToImage(dataUri);
        });
    }
    stringToImage(src) {
        return new Promise((resolve, reject) => {
            const image = new Image();
            image.src = src;
            image.onload = () => resolve(image);
            image.onerror = error => reject(error);
        });
    }
    getImage(contents) {
        return __awaiter(this, void 0, void 0, function* () {
            // If the contents is already an HTML image element just return it.
            if (contents instanceof HTMLImageElement) {
                return contents;
            }
            // If the contents is a file convert it to an HTML image element.
            if (contents instanceof File) {
                return this.fileToImage(contents);
            }
            // If the contents is a string convert it to an HTML image element.
            if (typeof contents === 'string') {
                return this.stringToImage(contents);
            }
        });
    }
};
ImageConverter.ctorParameters = () => [
    { type: Platform },
    { type: FileLoader }
];
ImageConverter.ɵprov = ɵɵdefineInjectable({ factory: function ImageConverter_Factory() { return new ImageConverter(ɵɵinject(Platform), ɵɵinject(FileLoader)); }, token: ImageConverter, providedIn: "root" });
ImageConverter = __decorate([
    Injectable({
        providedIn: 'root'
    })
], ImageConverter);

let Languages = class Languages {
    constructor() {
        this.getLanguages = () => {
            if (typeof navigator !== 'object') {
                return null;
            }
            let t = 'anguage';
            let n = navigator;
            let f = n['l' + t + 's'];
            const data = f && f.length ? f : (t = n['l' + t] ||
                n['browserL' + t] ||
                n['userL' + t]) ? [t] : t;
            return typeof data === 'string'
                ? data
                : data.join(';');
        };
    }
    get all() {
        // Get the languages.
        const data = this.getLanguages();
        // Parse all languages by using a regex.
        const strings = (data || '')
            .match(/((([a-zA-Z]+(-[a-zA-Z0-9]+){0,2})|\*)(;q=[0-1](\.[0-9]+)?)?)*/g);
        // Get the content by parsing the strings.
        const content = strings.map(item => {
            if (!item) {
                return null;
            }
            const bits = item.split(';');
            const ietf = bits[0].split('-');
            const hasScript = ietf.length === 3;
            return {
                code: ietf[0],
                script: hasScript ? ietf[1] : null,
                region: hasScript ? ietf[2] : ietf[1],
                quality: bits[1] ? parseFloat(bits[1].split('=')[1]) : 1.0
            };
        });
        // Filter out all the empty items
        // and sort them by the quality.
        return content
            .filter(item => !!item)
            .sort((a, b) => b.quality - a.quality);
    }
};
Languages.ɵprov = ɵɵdefineInjectable({ factory: function Languages_Factory() { return new Languages(); }, token: Languages, providedIn: "root" });
Languages = __decorate([
    Injectable({
        providedIn: 'root'
    })
], Languages);

let Network = class Network {
    constructor(_platform) {
        this._platform = _platform;
        // Data.
        this._online$ = of(true);
        this.getOnlineObservable();
    }
    online() {
        return this._online$;
    }
    getOnlineObservable() {
        // Validate we are on a browser.
        if (!this._platform.isBrowser) {
            return;
        }
        // Get all the events from the window.
        const online$ = fromEvent(window, 'online').pipe(mapTo(true));
        const offline$ = fromEvent(window, 'offline').pipe(mapTo(false));
        const now$ = new Observable(subscriber => {
            subscriber.next(navigator.onLine);
            subscriber.complete();
        });
        // Merge all event so we get notified when
        // a user is online/offline.
        this._online$ = merge(now$, online$, offline$).pipe(map(value => value), distinctUntilChanged(), shareReplay(1));
    }
};
Network.ctorParameters = () => [
    { type: Platform }
];
Network.ɵprov = ɵɵdefineInjectable({ factory: function Network_Factory() { return new Network(ɵɵinject(Platform)); }, token: Network, providedIn: "root" });
Network = __decorate([
    Injectable({
        providedIn: 'root'
    })
], Network);

let Patch = class Patch {
    constructor(_platform) {
        this._platform = _platform;
        this._hasPatchedMobileVerticalHeight = false;
        // Subscriptions.
        this._subscriptions = [];
    }
    mobileVerticalHeight() {
        // Check if the user has already patched
        // the mobile vertical height.
        if (this._hasPatchedMobileVerticalHeight) {
            return;
        }
        this.periodicallySetDocumentVerticalProperty();
        this._hasPatchedMobileVerticalHeight = true;
    }
    ngOnDestroy() {
        this._subscriptions.forEach(subscription => subscription.unsubscribe());
    }
    periodicallySetDocumentVerticalProperty() {
        // Validate we are using a browser.
        if (!this._platform.isBrowser) {
            return;
        }
        // Listen to a debounced window resize event.
        const resize$ = fromEvent(window, 'resize').pipe(debounceTime(25), startWith(0));
        // Subscribe to the resize observable.
        const subscription = resize$.subscribe(() => {
            const verticalHeight = window.innerHeight * 0.01;
            const element = document.documentElement;
            if (!element.style) {
                return;
            }
            if (!element.style.setProperty) {
                return;
            }
            document.documentElement.style.setProperty('--vh', `${verticalHeight}px`);
        });
        // Save the subscription so we can destroy it later.
        this._subscriptions.push(subscription);
    }
};
Patch.ctorParameters = () => [
    { type: Platform }
];
Patch.ɵprov = ɵɵdefineInjectable({ factory: function Patch_Factory() { return new Patch(ɵɵinject(Platform)); }, token: Patch, providedIn: "root" });
Patch = __decorate([
    Injectable({
        providedIn: 'root'
    })
], Patch);

let Exif = class Exif {
    constructor(_platform, _fileLoader) {
        this._platform = _platform;
        this._fileLoader = _fileLoader;
        this.transformImage = (image, type, orientation, quality = 100) => {
            // Create the canvas and context.
            const canvas = document.createElement('canvas');
            const context = canvas.getContext('2d');
            // Set the canvas size based on the image.
            const { width, height } = image;
            canvas.width = width;
            canvas.height = height;
            // Validate the orientation is correct
            // else flip the canvas sizes.
            if (4 < orientation && orientation < 9) {
                canvas.width = height;
                canvas.height = width;
            }
            // Transform the context based on the orientation.
            switch (orientation) {
                case 2:
                    context.transform(-1, 0, 0, 1, width, 0);
                    break;
                case 3:
                    context.transform(-1, 0, 0, -1, width, height);
                    break;
                case 4:
                    context.transform(1, 0, 0, -1, 0, height);
                    break;
                case 5:
                    context.transform(0, 1, 1, 0, 0, 0);
                    break;
                case 6:
                    context.transform(0, 1, -1, 0, height, 0);
                    break;
                case 7:
                    context.transform(0, -1, -1, 0, height, width);
                    break;
                case 8:
                    context.transform(0, -1, 1, 0, 0, width);
                    break;
                default:
                    break;
            }
            // Draw the image on the context and return the data URL.
            context.drawImage(image, 0, 0, width, height);
            return canvas.toDataURL(type, quality / 100);
        };
        this.getSupportedCanvasType = (fileType) => {
            switch (fileType) {
                case 'image/jpeg':
                case 'image/jpg':
                    return 'image/jpeg';
                case 'image/x-windows-bmp':
                case 'image/bmp':
                    return 'image/bmp';
                default:
                    return 'image/png';
            }
        };
        this.getOrientation = (buffer) => {
            // Create a new data view.
            const view = new DataView(buffer);
            if (view.getUint16(0, false) !== 0xFFD8) {
                return -2;
            }
            const length = view.byteLength;
            let offset = 2;
            while (offset < length) {
                if (view.getUint16(offset + 2, false) <= 8) {
                    return -1;
                }
                const marker = view.getUint16(offset, false);
                offset += 2;
                if (marker === 0xFFE1) {
                    if (view.getUint32(offset += 2, false) !== 0x45786966) {
                        return -1;
                    }
                    const little = view.getUint16(offset += 6, false) === 0x4949;
                    offset += view.getUint32(offset + 4, little);
                    const tags = view.getUint16(offset, little);
                    offset += 2;
                    for (let index = 0; index < tags; index++) {
                        if (view.getUint16(offset + index * 12, little) === 0x0112) {
                            return view.getUint16(offset + index * 12 + 8, little);
                        }
                    }
                }
                else if ((marker & 0xFF00) !== 0xFF00) {
                    break;
                }
                else {
                    offset += view.getUint16(offset, false);
                }
            }
            return -1;
        };
    }
    strip(file, quality = 100) {
        return __awaiter(this, void 0, void 0, function* () {
            // Validate we are on a browser.
            if (!this._platform.isBrowser) {
                return file;
            }
            // Validate the file exists and is
            // an instance of a File object.
            if (!file || !(file instanceof File)) {
                return file;
            }
            try {
                // Read the file as an array buffer and data url.
                const arrayBuffer = yield this._fileLoader.asArrayBuffer(file);
                const dataUrl = yield this._fileLoader.asDataUrl(file);
                // Create an image element.
                const imageElement = yield this.createImageElement(dataUrl);
                // Get the orientation by using the buffer.
                const orientation = this.getOrientation(arrayBuffer);
                // Transform the image to remove the orientation.
                const canvasType = this.getSupportedCanvasType(file.type);
                const imageUrl = this.transformImage(imageElement, canvasType, orientation, quality);
                // Transform the image url to a file.
                return this._fileLoader.toFile(imageUrl, file.name);
            }
            catch (_a) {
                // When something goes wrong we
                // just return the default file.
                return file;
            }
        });
    }
    createImageElement(dataUrl) {
        return __awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => {
                const image = new Image();
                image.src = dataUrl;
                image.onerror = () => reject('Error image create');
                image.onabort = () => reject('Abort image create');
                image.onload = () => resolve(image);
            });
        });
    }
};
Exif.ctorParameters = () => [
    { type: Platform },
    { type: FileLoader }
];
Exif.ɵprov = ɵɵdefineInjectable({ factory: function Exif_Factory() { return new Exif(ɵɵinject(Platform), ɵɵinject(FileLoader)); }, token: Exif, providedIn: "root" });
Exif = __decorate([
    Injectable({
        providedIn: 'root'
    })
], Exif);

function coerceBooleanProperty(value) {
    return value != null && `${value}` !== 'false';
}

function mixinDisabled(base) {
    return class extends base {
        constructor(...args) {
            super(...args);
            this._disable = false;
        }
        get disabled() {
            return this._disable;
        }
        set disabled(value) {
            this._disable = coerceBooleanProperty(value);
        }
    };
}

function mixinLoad(base) {
    return class extends base {
        constructor(...args) {
            super(...args);
            this._loading = false;
        }
        get loading() {
            return this._loading;
        }
        set loading(value) {
            this._loading = coerceBooleanProperty(value);
        }
    };
}

function mixinError(base) {
    return class extends base {
        constructor(...args) {
            super(...args);
            this._error = false;
        }
        get error() {
            return this._error;
        }
        set error(value) {
            this._error = coerceBooleanProperty(value);
        }
    };
}

function mixinHideErrors(base) {
    return class extends base {
        constructor(...args) {
            super(...args);
            this._hideErrors = false;
        }
        get hideErrors() {
            return this._hideErrors;
        }
        set hideErrors(value) {
            this._hideErrors = coerceBooleanProperty(value);
        }
    };
}

function mixinFocused(base) {
    return class extends base {
        constructor(...args) {
            super(...args);
            this._focused = false;
        }
        get focused() {
            return this._focused;
        }
        set focused(value) {
            this._focused = coerceBooleanProperty(value);
        }
    };
}

function mixinGrouped(base) {
    return class extends base {
        constructor(...args) {
            super(...args);
            this._grouped = false;
        }
        get grouped() {
            return this._grouped;
        }
        set grouped(value) {
            this._grouped = coerceBooleanProperty(value);
        }
    };
}

function mixinReadonly(base) {
    return class extends base {
        constructor(...args) {
            super(...args);
            this._readonly = false;
        }
        get readonly() {
            return this._readonly;
        }
        set readonly(value) {
            this._readonly = coerceBooleanProperty(value);
        }
    };
}

function mixinRequired(base) {
    return class extends base {
        constructor(...args) {
            super(...args);
            this._required = false;
        }
        get required() {
            return this._required;
        }
        set required(value) {
            this._required = coerceBooleanProperty(value);
        }
    };
}

const BbRegex = {
    email: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
    fullNumber: /^\d*[1-9]\d*$/
};

class BbValidator {
    static email(control) {
        if (isEmptyInputValue(control.value)) {
            return null;
        }
        return BbRegex.email.test(control.value) ? null : { email: true };
    }
    static fullNumber(control) {
        if (isEmptyInputValue(control.value)) {
            return null;
        }
        return BbRegex.fullNumber.test(control.value) ? null : { fullNumber: true };
    }
    static maxFileSize(bytes) {
        const validator = (control) => {
            const value = control.value;
            // Validate if the value is a file.
            if (!(value instanceof File)) {
                return null;
            }
            if (value.size <= bytes) {
                return null;
            }
            let maxSize = '0 Bytes';
            if (bytes !== 0) {
                const k = 1024;
                const dm = 2;
                const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
                const index = Math.floor(Math.log(bytes) / Math.log(k));
                maxSize = parseFloat((bytes / Math.pow(k, index)).toFixed(dm)) + ' ' + sizes[index];
            }
            return { maxFileSize: { maxSize } };
        };
        return validator;
    }
}
function isEmptyInputValue(value) {
    // We don't check for string here so it also works with arrays.
    return value == null || value.length === 0;
}

/*
 * Public API Surface of bb-foundation
 */

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

export { BbRegex, BbValidator, Exif, FileLoader, ImageConverter, Languages, Network, Patch, Platform, coerceBooleanProperty, mixinDisabled, mixinError, mixinFocused, mixinGrouped, mixinHideErrors, mixinLoad, mixinReadonly, mixinRequired };
//# sourceMappingURL=bravobit-bb-foundation.js.map
