import React from 'react';
import PropTypes from 'prop-types';
import style from './Tooltip.module.css';

export default class Tooltip extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            title: null,
            left: 0,
            top: 0,
            arrowLeft: 0,
            isArrowRight: null,
            isHtml: false
        };
        this.handleOver = this.handleOver.bind(this);
        this.getToolTipDOM = this.getToolTipDOM.bind(this);
        this.reset = this.reset.bind(this);
        this.getDirection = document.getElementsByTagName('html')[0];
        this.leftRightScreenEdge = this.leftRightScreenEdge.bind(this);
        this.topBottomScreenEdge = this.topBottomScreenEdge.bind(this);
    }

    getToolTipDOM(el) {
        this.toolTip = el;
    }

    reset() {
        let { title } = this.state;
        if (title !== null) {
            this.setState({
                title: null,
                top: 0,
                left: 0
            });
        }
    }

    /* left and right screen edge check for top and bottom tooltip position */
    leftRightScreenEdge(
        tLeft,
        toolTipArrowLeft,
        thisLeft,
        thisWidth,
        tooltipoffsetWidth,
        bodyWidth,
        rightEdge,
        bodyLeft
    ) {
        if ((tLeft - bodyLeft) <= 1) {
            // top & bottom position left side screen edge case
            tLeft = bodyLeft + 2;
            toolTipArrowLeft = parseInt((thisLeft - bodyLeft) + thisWidth / 2 - 6);
        } else if ((tLeft - bodyLeft) + tooltipoffsetWidth > bodyWidth) {
            // top & bottom position right side screen edge case
            rightEdge = tLeft + tooltipoffsetWidth - bodyWidth + 2;
            tLeft = (tLeft + bodyLeft) - rightEdge;
            toolTipArrowLeft = (toolTipArrowLeft - bodyLeft) + rightEdge;
        } else if ((tLeft + tooltipoffsetWidth) + tooltipoffsetWidth >= bodyWidth - 2) {
            // top & bottom center screen tooltip collide with right edge screen
            tLeft = parseInt(thisLeft - (tooltipoffsetWidth - thisWidth) / 2);
            toolTipArrowLeft = parseInt(tooltipoffsetWidth / 2 - 4);
        }
        return {
            tLeft,
            toolTipArrowLeft,
            thisLeft,
            thisWidth,
            tooltipoffsetWidth,
            bodyWidth,
            rightEdge
        };
    }

    /* top and bottom screen edge check for left and right tooltip position */
    topBottomScreenEdge(
        tTop,
        toolTipArrowTop,
        thisTop,
        thisHeight,
        tooltipoffsetHeight,
        bodyHeight,
        bottomEdge
    ) {
        if (tTop <= 1) {
            tTop = 2;
            toolTipArrowTop = parseInt(thisTop + thisHeight / 2);
        } else if (tTop + tooltipoffsetHeight > bodyHeight) {
            bottomEdge = tTop + tooltipoffsetHeight - bodyHeight + 2;
            tTop -= bottomEdge;
            toolTipArrowTop += bottomEdge;
        }
        return {
            tTop,
            toolTipArrowTop,
            thisTop,
            thisHeight,
            tooltipoffsetHeight,
            bodyHeight,
            bottomEdge
        };
    }

    handleOver(e) {
        let element = e.target;
        let titleDiv =
            element.hasAttribute('data-title') || element.hasAttribute('title')
                ? element
                : element.closest('[data-title]') || element.closest('[title]');
        if (titleDiv) {
            let title =
                titleDiv.getAttribute('data-title') || titleDiv.getAttribute('title');

            /* if data-title-position is left or right change right and left in rtl case */
            let isPosition = titleDiv.getAttribute('data-title-position');
            let elem = this.getDirection;
            if (elem.getAttribute('dir') == 'rtl') {
                if (isPosition == 'left') {
                    isPosition = 'right';
                } else if (isPosition == 'right') {
                    isPosition = 'left';
                }
            }

            if (title !== '' && title) {
                titleDiv.setAttribute('data-title', title);
                titleDiv.removeAttribute('title');
                if (
                    element.nodeName !== 'I' &&
                    element.innerText &&
                    element.innerText.trim() !== ''
                ) {
                    let isContentDotted = '';
                    if (element.scrollWidth !== 0) {
                        isContentDotted = element.offsetWidth < element.scrollWidth;
                        if (!isContentDotted) {
                            isContentDotted = element.offsetHeight < element.scrollHeight;
                        }
                        // if (!isContentDotted) {Need to check the code Sivanesh
                        //   isContentDotted = element.offsetHeight < element.scrollHeight;
                        // }
                    } else {
                        isContentDotted =
                            element.parentElement.offsetWidth <
                            element.parentElement.scrollWidth;
                    }
                    let originText = element.innerText.replace(/\s/g, '').toLowerCase();
                    let tooltipText = title.replace(/\s/g, '').toLowerCase();
                    let isDefaultTooltip =
                        element.hasAttribute('data-istitle') ||
                            element.hasAttribute('istitle')
                            ? element.getAttribute('data-istitle') ||
                            element.getAttribute('istitle')
                            : 'false';
                    isDefaultTooltip = isDefaultTooltip === 'true';
                    let isSameText =
                        originText.indexOf(tooltipText) !== -1 ? true : false;
                    if (!isContentDotted && isSameText && !isDefaultTooltip) {
                        return false;
                    }
                    if (isContentDotted && titleDiv.getAttribute('data-dottedTitle')) {
                        title = titleDiv.getAttribute('data-dottedTitle');
                    }
                }
                let isHtml = titleDiv.getAttribute('data-ishtml');
                let dataTooltipnoArrow =
                    titleDiv.getAttribute('data-tooltip-noarrow') === 'true'
                        ? true
                        : false;
                let clientRect = titleDiv.getBoundingClientRect();
                let boxLayout = document.body.getBoundingClientRect();
                this.setState({ title, isHtml, dataTooltipnoArrow }, () => {
                    let tooltip = this.toolTip;
                    if (tooltip) {
                        /* element top, left, height, width */
                        let thisTop = clientRect.top;
                        let thisLeft = clientRect.left;
                        let thisHeight = clientRect.height;
                        let thisWidth = clientRect.width;
                        /* box layout left spacing */
                        let bodyLeft = boxLayout.left;
                        // let checkTop = thisTop + thisHeight;
                        /* element left plus element width */
                        let checkLeft = thisLeft + thisWidth;
                        let tTop;
                        let tLeft;
                        let toolTipArrowTop;
                        let toolTipArrowLeft;
                        let rightEdge;
                        let bottomEdge;
                        let tooltipLeft;
                        /* offset width, height of body */
                        let bodyWidth = document.body.offsetWidth;
                        let bodyHeight = document.body.offsetHeight;
                        let isArrowHorizontal = false;
                        let isArrowDown = false;
                        let isArrowRight = false;
                        let tWidth = '';
                        /* overall body height minus element top + element height */
                        let thisBottom = bodyHeight - (thisTop + thisHeight);
                        /* overall body width minus element left + element width */
                        let thisRight = bodyWidth - (thisLeft + thisWidth);
                        /* tooltip width and height */
                        let tooltipoffsetWidth = tooltip.offsetWidth;
                        let tooltipoffsetHeight = tooltip.offsetHeight;

                        if (isPosition) {
                            if (isPosition == 'top') {
                                /* if top does not have enough space show tooltip in bottom area */
                                if (thisTop <= tooltipoffsetHeight + 5) {
                                    /* if top space is larger than bottom space show tooltip in top area */
                                    if (thisTop > thisBottom) {
                                        tTop = parseInt(thisTop - (tooltipoffsetHeight + 10));
                                        tLeft = parseInt(
                                            thisLeft - (tooltipoffsetWidth - thisWidth) / 2 + 2
                                        );
                                        toolTipArrowTop = parseInt(tooltipoffsetHeight - 4);
                                        toolTipArrowLeft = parseInt(tooltipoffsetWidth / 2 - 6);
                                        isArrowDown = true;
                                    } else {
                                        /* bottom position */
                                        tTop = parseInt(thisTop + (thisHeight + 10));
                                        tLeft = parseInt(
                                            thisLeft - (tooltipoffsetWidth - thisWidth) / 2 + 2
                                        );
                                        toolTipArrowTop = -4;
                                        toolTipArrowLeft = parseInt(tooltipoffsetWidth / 2 - 6);
                                        isArrowDown = false;
                                    }
                                } else {
                                    /* if top have enough space show tooltip in top area */
                                    tTop = parseInt(thisTop - (tooltipoffsetHeight + 10));
                                    tLeft = parseInt(
                                        thisLeft - (tooltipoffsetWidth - thisWidth) / 2 + 2
                                    );
                                    toolTipArrowTop = parseInt(tooltipoffsetHeight - 4);
                                    toolTipArrowLeft = parseInt(tooltipoffsetWidth / 2 - 6);
                                    isArrowDown = true;
                                }

                                /* top tooltip left and right corner edge case */
                                let values = this.leftRightScreenEdge(
                                    tLeft,
                                    toolTipArrowLeft,
                                    thisLeft,
                                    thisWidth,
                                    tooltipoffsetWidth,
                                    bodyWidth,
                                    rightEdge,
                                    bodyLeft
                                );

                                (tLeft = values.tLeft),
                                    (toolTipArrowLeft = values.toolTipArrowLeft),
                                    (thisLeft = values.thisLeft),
                                    (thisWidth = values.thisWidth),
                                    (tooltipoffsetWidth = values.tooltipoffsetWidth),
                                    (bodyWidth = values.bodyWidth),
                                    (rightEdge = values.rightEdge);
                            } else if (isPosition == 'bottom') {
                                /* if bottom does not have enough space show tooltip in top area */
                                if (thisBottom <= tooltipoffsetHeight + 5) {
                                    /* if bottom space is larger than top space show tooltip in bottom area */
                                    if (thisTop > thisBottom) {
                                        tTop = parseInt(thisTop - (tooltipoffsetHeight + 10));
                                        tLeft = parseInt(
                                            thisLeft - (tooltipoffsetWidth - thisWidth) / 2 + 2
                                        );
                                        toolTipArrowTop = parseInt(tooltipoffsetHeight - 4);
                                        toolTipArrowLeft = parseInt(tooltipoffsetWidth / 2 - 6);
                                        isArrowDown = true;
                                    } else {
                                        /* top position */
                                        tTop = parseInt(thisTop + (thisHeight + 10));
                                        tLeft = parseInt(
                                            thisLeft - (tooltipoffsetWidth - thisWidth) / 2 + 2
                                        );
                                        toolTipArrowTop = -4;
                                        toolTipArrowLeft = parseInt(tooltipoffsetWidth / 2 - 6);
                                        isArrowDown = false;
                                    }
                                } else {
                                    /* if bottom have enough space show tooltip in bottom area */
                                    tTop = parseInt(thisTop + (thisHeight + 10));
                                    tLeft = parseInt(
                                        thisLeft - (tooltipoffsetWidth - thisWidth) / 2 + 2
                                    );
                                    toolTipArrowTop = -4;
                                    toolTipArrowLeft = parseInt(tooltipoffsetWidth / 2 - 6);
                                    isArrowDown = false;
                                }

                                /* bottom tooltip left and right corner edge case */
                                let values = this.leftRightScreenEdge(
                                    tLeft,
                                    toolTipArrowLeft,
                                    thisLeft,
                                    thisWidth,
                                    tooltipoffsetWidth,
                                    bodyWidth,
                                    rightEdge,
                                    bodyLeft
                                );

                                (tLeft = values.tLeft),
                                    (toolTipArrowLeft = values.toolTipArrowLeft),
                                    (thisLeft = values.thisLeft),
                                    (thisWidth = values.thisWidth),
                                    (tooltipoffsetWidth = values.tooltipoffsetWidth),
                                    (bodyWidth = values.bodyWidth),
                                    (rightEdge = values.rightEdge);
                            } else if (isPosition == 'left') {
                                isArrowHorizontal = true;

                                if ((thisLeft - bodyLeft) <= tooltipoffsetWidth) {
                                    if ((thisLeft - bodyLeft) <= thisRight) {
                                        /* if left does not have enough space show tooltip in right area */
                                        tTop = parseInt(
                                            thisTop + (thisHeight / 2 - tooltipoffsetHeight / 2)
                                        );
                                        tLeft = parseInt(thisLeft + thisWidth + 10);
                                        toolTipArrowTop = parseInt(tooltipoffsetHeight / 2 - 1);
                                        toolTipArrowLeft = -1;
                                        isArrowRight = false;
                                    } else {
                                        /* if left space is larger than right space show tooltip in left (default) area */
                                        if (bodyLeft + tooltipoffsetWidth >= thisLeft) {
                                            /* if tooltip width is greater than left space, set left space width to tooltip  */
                                            tWidth = thisLeft;
                                            tTop = parseInt(
                                                thisTop + (thisHeight / 2 - tooltipoffsetHeight / 2)
                                            );
                                            tLeft = parseInt(thisLeft - tWidth - 7);
                                            toolTipArrowTop = parseInt(tooltipoffsetHeight / 2 - 1);
                                            toolTipArrowLeft = parseInt(tWidth - 2);
                                            isArrowRight = true;
                                        }
                                    }
                                } else {
                                    /* if left have enough space show tooltip in left area */
                                    tTop = parseInt(
                                        thisTop + (thisHeight / 2 - tooltipoffsetHeight / 2)
                                    );
                                    tLeft = parseInt(thisLeft - tooltipoffsetWidth - 7);
                                    toolTipArrowTop = parseInt(tooltipoffsetHeight / 2 - 1);
                                    toolTipArrowLeft = parseInt(tooltipoffsetWidth - 2);
                                    isArrowRight = true;
                                }

                                /* left tooltip top and bottom corner edge case */
                                let values = this.topBottomScreenEdge(
                                    tTop,
                                    toolTipArrowTop,
                                    thisTop,
                                    thisHeight,
                                    tooltipoffsetHeight,
                                    bodyHeight,
                                    bottomEdge
                                );

                                (tTop = values.tTop),
                                    (toolTipArrowTop = values.toolTipArrowTop),
                                    (thisTop = values.thisTop),
                                    (thisHeight = values.thisHeight),
                                    (tooltipoffsetHeight = values.tooltipoffsetHeight),
                                    (bodyHeight = values.bodyHeight),
                                    (bottomEdge = values.bottomEdge);
                            } else if (isPosition == 'right') {
                                isArrowHorizontal = true;

                                if ((thisRight + bodyLeft) <= tooltipoffsetWidth) {
                                    if ((thisLeft + bodyLeft) <= thisRight) {
                                        /* if right space is larger than left space show tooltip in right (default) area */
                                        tTop = parseInt(
                                            thisTop + (thisHeight / 2 - tooltipoffsetHeight / 2)
                                        );
                                        tLeft = parseInt(thisLeft + thisWidth + 7);
                                        toolTipArrowTop = parseInt(tooltipoffsetHeight / 2 - 1);
                                        toolTipArrowLeft = -1;
                                        isArrowRight = false;
                                    } else {
                                        /* if right does not have enough space show tooltip in left area */
                                        if (tooltipoffsetWidth >= thisLeft) {
                                            /* if tooltip width is greater than left space, set left space width to tooltip  */
                                            tWidth = thisLeft;
                                            tTop = parseInt(
                                                thisTop + (thisHeight / 2 - tooltipoffsetHeight / 2)
                                            );
                                            tLeft = parseInt(thisLeft - tWidth - 7);
                                            toolTipArrowTop = parseInt(tooltipoffsetHeight / 2 - 1);
                                            toolTipArrowLeft = parseInt(tWidth - 2);
                                            isArrowRight = true;
                                        } else {
                                            /* show tooltip in left area without setting left space width to tooltip */
                                            tTop = parseInt(
                                                thisTop + (thisHeight / 2 - tooltipoffsetHeight / 2)
                                            );
                                            tLeft = parseInt(thisLeft - tooltipoffsetWidth - 7);
                                            toolTipArrowTop = parseInt(tooltipoffsetHeight / 2 - 1);
                                            toolTipArrowLeft = parseInt(tooltipoffsetWidth - 2);
                                            isArrowRight = true;
                                        }
                                    }
                                } else {
                                    /* if right have enough space show tooltip in right area */
                                    tTop = parseInt(
                                        thisTop + (thisHeight / 2 - tooltipoffsetHeight / 2)
                                    );
                                    tLeft = parseInt(thisLeft + thisWidth + 7);
                                    toolTipArrowTop = parseInt(tooltipoffsetHeight / 2 - 1);
                                    toolTipArrowLeft = -1;
                                    isArrowRight = false;
                                }

                                /* right tooltip left and right corner edge case */
                                let values = this.topBottomScreenEdge(
                                    tTop,
                                    toolTipArrowTop,
                                    thisTop,
                                    thisHeight,
                                    tooltipoffsetHeight,
                                    bodyHeight,
                                    bottomEdge
                                );

                                (tTop = values.tTop),
                                    (toolTipArrowTop = values.toolTipArrowTop),
                                    (thisTop = values.thisTop),
                                    (thisHeight = values.thisHeight),
                                    (tooltipoffsetHeight = values.tooltipoffsetHeight),
                                    (bodyHeight = values.bodyHeight),
                                    (bottomEdge = values.bottomEdge);
                            }

                            this.setState({
                                top: tTop,
                                left: tLeft,
                                arrowTop: toolTipArrowTop,
                                arrowLeft: toolTipArrowLeft,
                                isArrowHorizontal: isArrowHorizontal,
                                isArrowDown: isArrowDown,
                                isArrowRight: isArrowRight,
                                width: tWidth
                            });
                        } else {
                            this.setState({ isArrowRight: null });
                            tTop = parseInt(thisTop + thisHeight + 10);
                            tLeft = parseInt(
                                thisLeft - (tooltipoffsetWidth / 2 - thisWidth / 2) + 2
                            );
                            tooltipLeft = parseInt(tooltipoffsetWidth / 2 - 6);
                            if ((tLeft - bodyLeft) <= 1) {
                                // default left side screen edge case
                                tooltipLeft = parseInt((thisLeft - bodyLeft) + (thisWidth / 2) - 6);
                                tLeft = bodyLeft + 2;
                            } else if ((tLeft - bodyLeft) + tooltipoffsetWidth > bodyWidth) {
                                checkLeft = tLeft + tooltipoffsetWidth - bodyWidth + 2;
                                tooltipLeft = (tooltipLeft - bodyLeft) + checkLeft;
                                tLeft = (tLeft + bodyLeft) - checkLeft;
                            } else if (tLeft + tooltipoffsetWidth >= bodyWidth - 2) {
                                // default center screen tooltip collide with right edge screen
                                tLeft = parseInt(
                                    thisLeft - (tooltipoffsetWidth - thisWidth) / 2
                                );
                                tooltipLeft = parseInt(tooltipoffsetWidth / 2 - 4);
                            }
                            isArrowDown = false;

                            if (tTop + tooltipoffsetHeight > bodyHeight) {
                                /* if bottom does not have enough space show tooltip in top area */
                                if (thisTop > thisBottom) {
                                    isArrowDown = true;
                                    tTop -= tooltipoffsetHeight + thisHeight + 20;
                                }
                            }

                            if (isArrowDown) {
                                let arrowTop = tooltipoffsetHeight - 4;
                                this.setState({
                                    top: tTop,
                                    left: tLeft,
                                    arrowLeft: tooltipLeft,
                                    arrowTop,
                                    isArrowDown: true,
                                    isArrowHorizontal: isArrowHorizontal
                                });
                            } else {
                                this.setState({
                                    top: tTop,
                                    left: tLeft,
                                    arrowLeft: tooltipLeft,
                                    arrowTop: -4,
                                    isArrowDown: false,
                                    isArrowHorizontal: isArrowHorizontal
                                });
                            }
                        }
                    }
                });
                titleDiv.addEventListener('click', this.reset);
                titleDiv.addEventListener('mouseup', this.reset);
                titleDiv.addEventListener('mouseleave', this.reset);
            }
        } else {
            this.reset();
        }
    }

    render() {
        let {
            title,
            left,
            top,
            arrowLeft,
            arrowTop,
            isArrowDown,
            isArrowRight,
            isArrowHorizontal,
            width,
            isHtml,
            dataTooltipnoArrow
        } = this.state;
        let { dataId, customClass } = this.props;
        let arrowStyle = isArrowHorizontal
            ? isArrowRight
                ? style.arrowRight
                : style.arrowLeft
            : isArrowDown
                ? style.arrowDown
                : style.arrowUp;
        title = title ? title.trim() : null;
        return title ? (
            <div
                className={`${customClass} ${style.tooltiptext}`}
                style={{ left, top, width }}
                ref={this.getToolTipDOM}
                data-id={dataId}
            >
                {!dataTooltipnoArrow ? (
                    <span
                        className={`${style.tooltiparrow} ${arrowStyle}`}
                        style={{ left: arrowLeft, top: arrowTop }}
                    />
                ) : null}
                {isHtml ? (
                    <div
                        className={style.tooltipcont}
                        dangerouslySetInnerHTML={{ __html: title }}
                    />
                ) : (
                    <div className={style.tooltipcont}>{title}</div>
                )}
            </div>
        ) : null;
    }
}

Tooltip.propTypes = {
    dataId: PropTypes.string,
    isHtml: PropTypes.string,
    isPosition: PropTypes.oneOf(['top', 'bottom', 'left', 'right']),
    title: PropTypes.string,
    customClass: PropTypes.string
};

Tooltip.defaultProps = {
    dataId: 'toolTip',
    customClass: ''
};

if (__DOCS__) {
    Tooltip.docs = {
        componentGroup: 'Atom',
        folderName: 'Style Guide',
        description: ' ',
        external: true
    };
}
