<template>
    <span :class="classes" :style="styles">
        <img :src="src" v-if="src" @error="handleError">
        <Icon :type="icon" :custom="customIcon" v-else-if="icon || customIcon"></Icon>
        <span ref="children" :class="[prefixCls + '-string']" :style="childrenStyle" v-else><slot></slot></span>
    </span>
</template>
<script>
    import { getCurrentInstance } from 'vue';
    import Icon from '../icon';
    import { oneOf } from '../../utils/assist';

    const prefixCls = 'ivu-avatar';

    const sizeList = ['small', 'large', 'default'];

    export default {
        name: 'Avatar',
        components: { Icon },
        emits: ['on-error'],
        props: {
            shape: {
                validator (value) {
                    return oneOf(value, ['circle', 'square']);
                },
                default: 'circle'
            },
            size: {
                type: [String, Number],
                default () {
                    const global = getCurrentInstance().appContext.config.globalProperties;
                    return !global.$VIEWUI || global.$VIEWUI.size === '' ? 'default' : global.$VIEWUI.size;
                }
            },
            src: {
                type: String
            },
            icon: {
                type: String
            },
            customIcon: {
                type: String,
                default: ''
            }
        },
        data () {
            return {
                prefixCls: prefixCls,
                scale: 1,
                childrenWidth: 0,
                isSlotShow: false,
                slotTemp: null
            };
        },
        computed: {
            classes () {
                return [
                    `${prefixCls}`,
                    `${prefixCls}-${this.shape}`,
                    {
                        [`${prefixCls}-image`]: !!this.src,
                        [`${prefixCls}-icon`]: !!this.icon || !!this.customIcon,
                        [`${prefixCls}-${this.size}`]: oneOf(this.size, sizeList)
                    }
                ];
            },
            styles () {
                let style = {};
                if (this.size && !oneOf(this.size, sizeList)) {
                    style.width = `${this.size}px`;
                    style.height = `${this.size}px`;
                    style.lineHeight = `${this.size}px`;
                    style.fontSize = `${this.size/2}px`;
                }
                return style;
            },
            childrenStyle () {
                let style = {};
                if (this.isSlotShow) {
                    style = {
                        msTransform: `scale(${this.scale})`,
                        WebkitTransform: `scale(${this.scale})`,
                        transform: `scale(${this.scale})`,
                        position: 'absolute',
                        display: 'inline-block',
                        left: `calc(50% - ${Math.round(this.childrenWidth / 2)}px)`
                    };
                }
                return style;
            }
        },
        watch: {
            size (val, oldVal) {
                if (val !== oldVal) this.setScale();
            }
        },
        methods: {
            setScale () {
                this.isSlotShow = !this.src && !this.icon;
                if (this.$refs.children) {
                    // set children width again to make slot centered
                    this.childrenWidth = this.$refs.children.offsetWidth;
                    const avatarWidth = this.$el.getBoundingClientRect().width;
                    // add 4px gap for each side to get better performance
                    if (avatarWidth - 8 < this.childrenWidth) {
                        this.scale = (avatarWidth - 8) / this.childrenWidth;
                    } else {
                        this.scale = 1;
                    }
                }
            },
            handleError (e) {
                this.$emit('on-error', e);
            }
        },
        beforeCreate () {
            this.slotTemp = this.$slots.default ? this.$slots.default() : null;
        },
        mounted () {
            this.setScale();
        },
        updated () {
            const slot = this.$slots.default ? this.$slots.default() : null;
            if (slot && slot !== this.slotTemp) this.setScale();
        }
    };
</script>
