"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const react_1 = __importDefault(require("react"));
const prop_types_1 = __importDefault(require("prop-types"));
const ButtonGroup_1 = __importDefault(require("react-bootstrap/lib/ButtonGroup"));
const Row_1 = __importDefault(require("react-bootstrap/lib/Row"));
const Col_1 = __importDefault(require("react-bootstrap/lib/Col"));
const lodash_1 = __importDefault(require("lodash"));
const classnames_1 = __importDefault(require("classnames"));
const Icon_1 = require("../Icon");
const Select_1 = require("../form/Select");
const Button_1 = require("../Button");
const utils_1 = require("../../../utils");
const CLASS_NAME_DOTS_HEAD = 'gap-left';
const CLASS_NAME_DOTS_TAIL = 'gap-right';
const CLASS_NAME_PREV_NAV = 'page-prev';
const CLASS_NAME_NEXT_NAV = 'page-next';
const CLASS_NAME_DISABLED = 'disabled';
const PAGING_MODE_LISTING = 'listing';
const PAGING_MODE_PAGES = 'pages';
var PagingMode;
(function (PagingMode) {
    PagingMode["PAGING_MODE_LISTING"] = "listing";
    PagingMode["PAGING_MODE_PAGES"] = "pages";
})(PagingMode || (PagingMode = {}));
class PurePagination extends react_1.default.Component {
    constructor() {
        super(...arguments);
        this.handlePrevClick = () => {
            this.props.onChangePage(this.props.activePage - 1);
        };
        this.handleClickNext = () => {
            this.props.onChangePage(this.props.activePage + 1);
        };
        this.handleChangePageSize = event => {
            const { value, selectedIndex } = event.target;
            this.props.onChangePageSize(Number(value), selectedIndex);
        };
    }
    calculatePageCount(itemsCount, pageSize) {
        return Math.ceil(itemsCount / pageSize);
    }
    /**
     * Calculates pagination ranges
     *
     * @param {Number} activePage Zero based value of active page
     * @param {Number} beforeAfterAmount A number of items wanted to show before and after active page
     * @param {Number} boundaryAmount A number of items wanted to show on head and on tail
     * @param {Number} pageCount Actual count of pages
     */
    getRanges(activePage, beforeAfterAmount, boundaryAmount, pageCount) {
        let headMiddleDistance = activePage - beforeAfterAmount - boundaryAmount;
        let headSize = headMiddleDistance < 0 ? 0 : boundaryAmount;
        headSize = Math.min(headSize, pageCount);
        let lastPage = pageCount - 1;
        let middleFrom = Math.max(0, activePage - beforeAfterAmount);
        let overlappedHead = boundaryAmount - headSize;
        let headFrom = 0;
        let headTo = headFrom + headSize - 1;
        let middleSize = 1 + 2 * beforeAfterAmount;
        middleSize = middleSize + overlappedHead;
        if (middleFrom - headSize <= 1) {
            middleSize = middleSize + 1;
            middleFrom = headSize;
        }
        let middleTo = middleFrom + middleSize - 1;
        let middleTailDistance = lastPage - boundaryAmount - middleTo;
        if (middleTailDistance === 1) {
            middleTo = middleTo + 1;
        }
        else if (middleTailDistance <= 0) {
            middleFrom = middleFrom - Math.abs(middleTailDistance);
            middleFrom = middleFrom - 1;
        }
        middleFrom = Math.max(middleFrom, headSize);
        middleTo = Math.min(lastPage, middleTo);
        let tailFrom = lastPage - boundaryAmount + 1;
        tailFrom = Math.max(middleTo + 1, tailFrom);
        let tailTo = lastPage;
        let result = {
            head: [headFrom, headTo],
            middle: [middleFrom, middleTo],
            tail: [tailFrom, tailTo]
        };
        result.head = this.isRangeEmpty(result.head) ? null : result.head;
        result.middle = this.isRangeEmpty(result.middle) ? [0, 0] : result.middle;
        result.tail = this.isRangeEmpty(result.tail) ? null : result.tail;
        return result;
    }
    isRangeEmpty(range) {
        if (!range) {
            return true;
        }
        return range[1] < range[0];
    }
    hasGap(rangeA, rangeB) {
        if (this.isRangeEmpty(rangeA) || this.isRangeEmpty(rangeB)) {
            return false;
        }
        return rangeB[0] - rangeA[1] > 1;
    }
    hasHeadDots(ranges) {
        return this.hasGap(ranges.head, ranges.middle);
    }
    hasTailDots(ranges) {
        return this.hasGap(ranges.middle, ranges.tail);
    }
    formatPageSize(digit, itemsCount, pageSizes) {
        // In case of store size less/equal/ to MAX_AVAILABLE_PAGE_SIZE, visually display
        // bigger page size option as 'all'
        const maxPageSize = Math.max(...pageSizes);
        if (digit === maxPageSize && itemsCount <= maxPageSize) {
            return utils_1.translate(this.props.allText);
        }
        return digit;
    }
    getPageSizeSelector(pageSizes, pageSize, itemsCount) {
        let dropdownItems = pageSizes.map((sizeValue, index) => {
            return (react_1.default.createElement("option", { key: index, value: sizeValue, "data-test-automation-id": 'size' + index }, this.formatPageSize(sizeValue, itemsCount, pageSizes)));
        });
        let controlId = `pageSizeSelector_${+new Date()}`;
        return (react_1.default.createElement(Select_1.Select, { name: "page-selector", value: pageSize, onChange: this.handleChangePageSize, className: "rc-items-per-page-selector", label: this.getPageSizeSelectorLabel(), testAutomationId: "pageSizeSelector", controlId: controlId }, dropdownItems));
    }
    getPageSizeSelectorLabel() {
        return this.props.pageSizeSelectorText;
    }
    getPageCount() {
        const { itemsCount, pageSize } = this.props;
        return this.calculatePageCount(itemsCount, pageSize);
    }
    getPageIndex() {
        return this.props.activePage + 1;
    }
    isNextButtonDisabled() {
        return this.props.activePage >= this.getPageCount() - 1;
    }
    isPrevButtonDisabled() {
        return this.props.activePage <= 0;
    }
    renderDot(className) {
        return (react_1.default.createElement(Button_1.Button, { disabled: true, bsStyle: 'link', className: className }, "..."));
    }
    renderPages(range, activePage, handler) {
        if (this.isRangeEmpty(range)) {
            return [];
        }
        const { goToPageLabel, currentPageLabel } = this.props;
        let list = lodash_1.default.times(range[1] - range[0] + 1, n => {
            let page = range[0] + n;
            let active = activePage === page;
            return (react_1.default.createElement(Button_1.Button, { "data-test-automation-id": 'p' + (page + 1), bsStyle: "link", "aria-label": `${goToPageLabel} ${page + 1}${active ? ', ' + currentPageLabel : ''}`, "data-page": page, onClick: handler.bind(this, page), key: page, active: active, disabled: active }, page + 1));
        });
        return list;
    }
    render() {
        let { pageNextLabel, pagePrevLabel, activePage, onChangePage, pageSizes, pageSize, itemsCount, beforeAfterAmount, boundaryAmount } = this.props;
        let ranges = this.getRanges(activePage, beforeAfterAmount, boundaryAmount, this.getPageCount());
        const isPrevButtonDisabled = this.isPrevButtonDisabled();
        const isNextButtonDisabled = this.isNextButtonDisabled();
        let isPagesMode = this.props.mode === PAGING_MODE_PAGES;
        let prevButtonClasses = classnames_1.default(CLASS_NAME_PREV_NAV, isPrevButtonDisabled && CLASS_NAME_DISABLED);
        let prevButton = (react_1.default.createElement(Button_1.Button, { "data-test-automation-id": "prev", bsStyle: "link", "aria-label": pagePrevLabel, className: prevButtonClasses, disabled: isPrevButtonDisabled, onClick: this.handlePrevClick },
            react_1.default.createElement(Icon_1.Icon, { name: "chevron-left-small" })));
        let nextButtonClasses = classnames_1.default(CLASS_NAME_NEXT_NAV, isNextButtonDisabled && CLASS_NAME_DISABLED);
        let nextButton = (react_1.default.createElement(Button_1.Button, { "data-test-automation-id": "next", bsStyle: "link", "aria-label": pageNextLabel, className: nextButtonClasses, disabled: isNextButtonDisabled, onClick: this.handleClickNext },
            react_1.default.createElement(Icon_1.Icon, { name: "chevron-right-small" })));
        let head = this.renderPages(ranges.head, activePage, onChangePage);
        let middle = this.renderPages(ranges.middle, activePage, onChangePage);
        let tail = this.renderPages(ranges.tail, activePage, onChangePage);
        let pageSizeSelector;
        if (this.props.showPageSizeSelector) {
            pageSizeSelector = this.getPageSizeSelector(pageSizes, pageSize, itemsCount);
        }
        let cn = classnames_1.default('rc-pagination', 'form-inline rc-form-inline', this.props.className);
        return (react_1.default.createElement("div", { "aria-label": "pagination", className: cn, "data-test-automation-id": "pages" },
            pageSizeSelector,
            isPagesMode ? (react_1.default.createElement("span", { className: "form-group" },
                react_1.default.createElement(ButtonGroup_1.default, { bsSize: "small" },
                    prevButton,
                    head,
                    this.hasHeadDots(ranges) ? this.renderDot(CLASS_NAME_DOTS_HEAD) : null,
                    middle,
                    this.hasTailDots(ranges) ? this.renderDot(CLASS_NAME_DOTS_TAIL) : null,
                    tail,
                    nextButton))) : (react_1.default.createElement("span", { className: "form-group" },
                react_1.default.createElement(Row_1.default, null,
                    react_1.default.createElement(Col_1.default, { xs: 3 }, prevButton),
                    react_1.default.createElement(Col_1.default, { xs: 6, className: "text-center" },
                        react_1.default.createElement("span", { "data-test-automation-id": "label" },
                            utils_1.translate(this.props.pageLabel),
                            " ",
                            this.getPageIndex())),
                    react_1.default.createElement(Col_1.default, { xs: 3 }, nextButton))))));
    }
}
PurePagination.PagingModes = {
    listing: PAGING_MODE_LISTING,
    pages: PAGING_MODE_PAGES
};
PurePagination.propTypes = {
    activePage: prop_types_1.default.number.isRequired,
    itemsCount: prop_types_1.default.number.isRequired,
    pageSize: prop_types_1.default.number.isRequired,
    onChangePage: prop_types_1.default.func.isRequired,
    onChangePageSize: prop_types_1.default.func.isRequired,
    pageSizes: prop_types_1.default.array,
    className: prop_types_1.default.string,
    showPageSizeSelector: prop_types_1.default.bool,
    beforeAfterAmount: prop_types_1.default.number,
    boundaryAmount: prop_types_1.default.number,
    mode: prop_types_1.default.oneOf([PAGING_MODE_LISTING, PAGING_MODE_PAGES]),
    currentPageLabel: prop_types_1.default.string,
    goToPageLabel: prop_types_1.default.string,
    pageNextLabel: prop_types_1.default.string,
    pagePrevLabel: prop_types_1.default.string,
    pageSizeSelectorText: prop_types_1.default.string,
    allText: prop_types_1.default.string,
    pageLabel: prop_types_1.default.string
};
PurePagination.defaultProps = {
    pageSizes: [10, 25, 50, 100, 500],
    className: null,
    showPageSizeSelector: true,
    beforeAfterAmount: 2,
    boundaryAmount: 1,
    mode: PAGING_MODE_PAGES,
    currentPageLabel: 'TRANSLATE:CURRENT_PAGE',
    goToPageLabel: 'TRANSLATE:GO_TO_PAGE',
    pageNextLabel: 'TRANSLATE:GO_TO_NEXT_PAGE',
    pagePrevLabel: 'TRANSLATE:GO_TO_PREV_PAGE',
    pageSizeSelectorText: 'TRANSLATE:PAGE_SIZE:',
    allText: 'TRANSLATE:ALL',
    pageLabel: 'TRANSLATE:PAGE'
};
exports.PurePagination = PurePagination;
//# sourceMappingURL=PurePagination.js.map