"use strict"

/**
 * 兼容高分辨率屏幕高像素比的情况
 *
 * @param {*} context
 */
function getPixelRatio(context) {
    let backingStore = context.backingStorePixelRatio ||
        context.webkitBackingStorePixelRatio ||
        context.mozBackingStorePixelRatio ||
        context.msBackingStorePixelRatio ||
        context.oBackingStorePixelRatio ||
        context.backingStorePixelRatio || 1
    return (window.devicePixelRatio || 1) / backingStore
}

/**
 * 针对阅卷平台场景多图片处理工具
 * 1. 支持指定服务器地址、是否强制刷新、是否严格模式、自适应大图切割规则
 * 2. 支持按阅卷平台规则筛选实际需要加载的图片
 * 3. 支持动态使用画布，按阅卷平台规则垂直拼接出新的图片
 *
 * @param {{server: *, flush: boolean, strict: boolean, split: array}} option
 */
function ImageLoader(option) {
    option = option || {}
    this.server = option.server || ''
    this.flush = option.flush === true
    this.strict = option.strict === true
    this.split = []
    if (Array.isArray(option.split) && option.split.length > 0) {
        for (let i = 0; i < (option.split.length - 1); i = i + 2) {
            this.split.push({left: option.split[i], width: option.split[i + 1]})
        }
    }
    if (this.split.length == 0) {
        this.split.push({left: 0, width: 0.55})
        this.split.push({left: 0.45, width: 0.55})
    }
}

ImageLoader.prototype.load = function (urls, config, onSuccess, onError) {
    onSuccess = onSuccess || (function () {
    })
    onError = onError || (function (error) {
        console.log(error)
    })
    urls = Array.isArray(urls) ? urls : []
    config = Array.isArray(config) ? config : []
    let promises = []
    let images = []
    let self = this
    for (let i = 0; i < urls.length; i++) {
        let url = this.server + urls[i] + (this.flush ? ('?' + new Date().getTime()) : '')
        let image = new Image()
        image.index = i + 1
        image.loaded = false
        images.push(image)
        promises.push(new Promise((resolve, reject) => {
            if (self.contain(image.index, config)) {
                image.onload = function () {
                    this.loaded = true
                    resolve()
                }
                image.onerror = function () {
                    this.onerror = undefined
                    if (self.strict) {
                        reject(url + ' load error')
                    } else {
                        resolve()
                    }
                }
                image.crossOrigin = ''
                image.src = url
            } else {
                resolve()
            }
        }))
    }

    Promise.all(promises).then(() => {
        self.checkSize(images)
        onSuccess(images)
    }).catch(error => {
        onError(error)
    })
}

/**
 * 遍历所有加载图片，根据宽高相互比较，判断是否大小图
 * @param {array} images
 */
ImageLoader.prototype.checkSize = function (images) {
    //let maxWidth = 0
    for (let i = 0; i < images.length; i++) {
        //宽度小于等于高度，自动判断为小图
        if (images[i].width <= images[i].height) {
            images[i].wide = false
        } else {
            //maxWidth = Math.max(maxWidth, images[i].width)
            images[i].wide = true
        }
    }
    // for (let i = 0; i < images.length; i++) {
    //     if (images[i].width > images[i].height) {
    //         //宽度大于高度，但是不到所有大图最大宽度的85%，也判定为小图
    //         let diff = images[i].width / maxWidth
    //         images[i].wide = diff >= 0.85
    //     }
    // }
}

/**
 * 判断指定序号的图片是否在拼接规则中存在，默认返回true
 *
 * @param {number} number
 * @param {array} config
 */
ImageLoader.prototype.contain = function (number, config) {
    if (config.length > 0) {
        let find = false
        for (let i = 0; i < config.length; i++) {
            if (config[i].i == number) {
                find = true
                break
            }
        }
        return find
    } else {
        return true
    }
}


/**
 * 使用指定画布，按照阅卷平台拼接规则，加载图片并组合
 *
 * @param {array} urls
 * @param {canvas} canvas
 * @param {array} config
 * @param {function} onSuccess
 * @param {function} onError
 */
ImageLoader.prototype.combine = function (urls, canvas, config, onSuccess, onError) {
    onSuccess = onSuccess || (function () {
    })
    onError = onError || (function (error) {
        console.log(error)
    })
    urls = Array.isArray(urls) ? urls : []
    config = Array.isArray(config) ? config : []
    let self = this
    this.load(urls, config, function (images) {
        if (config.length == 0) {
            //不指定拼接配置时，默认按顺序显示所有图片
            //区分大小图，小图原样显示，大图默认一分为二
            for (let i = 0; i < images.length; i++) {
                let image = images[i]
                if (image.loaded === true) {
                    if (image.wide === true) {
                        //大图按切割规则
                        for (let j = 0; j < self.split.length; j++) {
                            config.push({
                                i: i + 1,
                                x: image.width * self.split[j].left,
                                y: 0,
                                w: image.width * self.split[j].width,
                                h: image.height
                            })
                        }
                    } else {
                        //小图原样显示
                        config.push({
                            i: i + 1,
                            x: 0,
                            y: 0,
                            w: image.width,
                            h: image.height
                        })
                    }
                }
            }
        }
        let maxWidth = 0
        let totalHeight = 0
        for (let i = 0; i < config.length; i++) {
            let image = images[config[i].i - 1]
            //必须图片存在且正常加载配置才生效
            if (image && image.loaded === true) {
                //计算最大宽度与合计高度
                if (config[i].w <= 0) {
                    config[i].w = image.width
                }
                if (config[i].h <= 0) {
                    config[i].h = image.height
                }
                maxWidth = Math.max(maxWidth, config[i].w)
                totalHeight += config[i].h
            }
        }
        let context = canvas.getContext("2d")
        //获取设备像素比
        //暂时只用原始尺寸，避免转换图片过大导致性能问题
        //let ratio = getPixelRatio(context)
        let ratio = 1
        //设置画布大小
        canvas.width = maxWidth * ratio
        canvas.height = totalHeight * ratio
        context.clearRect(0, 0, canvas.width, canvas.height)
        context.fillStyle = "white";
        context.fillRect(0, 0, canvas.width, canvas.height);
        //绘画到画布
        //高度位置与图片配置对应关系
        let layout = []
        let height = 0
        for (let i = 0; i < config.length; i++) {
            let image = images[config[i].i - 1]
            if (image && image.loaded === true) {
                context.drawImage(image, config[i].x, config[i].y, config[i].w, config[i].h, 0, height, config[i].w * ratio, config[i].h * ratio)
                layout.push({
                    ratio: ratio,
                    top: height,
                    bottom: height + config[i].h * ratio,
                    config: config[i]
                })
                height += config[i].h * ratio
            }
        }
        onSuccess(layout)
    }, onError)
}

ImageLoader.prototype.merge = function (urls, canvas, config, onSuccess, onError) {
    this.combine(urls, canvas, config, function (layout) {
        let image = new Image()
        image.onload = function () {
            onSuccess(image)
        }
        image.onerror = function () {
            onError('image merge error')
        }
        image.layout = layout
        image.src = canvas.toDataURL()
    }, null)
}

/**
 * 针对画布的辅助工具类
 * 1. 灵活调整大小与视网膜屏幕下的高清显示
 * 2. 按照阅卷平台的图片拼接规则绘制图片内容
 *
 * @param {} option
 */
function EasyCanvas(option) {
    this.canvas = option.canvas
    this.context = this.canvas.getContext("2d")
    this.ratio = getPixelRatio()

    this.originSize = {
        width: 0,
        height: 0
    }
    this.styleSize = {
        width: 0,
        height: 0
    }
    this.boxSize = {}
    this.changeBoxSize(option.boxWidth, this.boxHeight)

    this.fontConfig = {
        name: option.fontName || 'Arial',
        size: option.fontSize || 60,
        color: option.fontColor || 'red'
    }
    this.lineConfig = {
        width: option.lineWidth || 3,
        color: option.lineColor || 'red'
    }

    this.onClick = option.onClick || (function () {
    })

    let self = this
    this.canvas.onclick = function (event) {
        if (self.originSize.width > 0 && self.originSize.height > 0) {
            self.onClick({
                left: event.offsetX,
                top: event.offsetY
            })
        }
    }
}

EasyCanvas.prototype.changeBoxSize = function (width, height) {
    if (width != undefined) {
        this.boxSize.width = width
        this.boxSize.height = undefined
    } else if (height != undefined) {
        this.boxSize.height = height
        this.boxSize.width = undefined
    }
}

EasyCanvas.prototype.clear = function () {
    this.context.clearRect(0, 0, this.canvas.width, this.canvas.heigth)
}

EasyCanvas.prototype.reset = function (width, height) {
    this.originSize.width = Math.max((width || 0), 0)
    this.originSize.height = Math.max((height || 0), 0)
    this.styleSize.width = this.originSize.width
    this.styleSize.height = this.originSize.height

    if (this.styleSize.width > 0 && this.styleSize.height > 0) {
        if (this.boxSize.width != undefined) {
            this.styleSize.width = Math.min(this.originSize.width, this.boxSize.width)
            this.styleSize.height = this.styleSize.width * this.originSize.height / this.originSize.width
        } else if (this.boxSize.height != undefined) {
            this.styleSize.height = Math.min(this.originSize.height, this.boxSize.height)
            this.styleSize.width = this.styleSize.height * this.originSize.width / this.originSize.height
        }
    }

    this.canvas.width = this.styleSize.width * this.ratio
    this.canvas.height = this.styleSize.height * this.ratio
    this.canvas.style.width = this.styleSize.width + 'px'
    this.canvas.style.height = this.styleSize.height + 'px'

    this.clear()
}

EasyCanvas.prototype.drawImage = function (image, scale) {
    this.drawImages([image], undefined, scale)
}

EasyCanvas.prototype.drawImages = function (images, config, scale) {
    scale = scale || 1.0
    if (config == undefined || config.length == 0) {
        //不指定拼接配置时，默认按顺序显示所有图片
        config = []
        for (let i = 0; i < images.length; i++) {
            config.push({
                i: i + 1,
                x: 0,
                y: 0,
                w: 0,
                h: 0
            })
        }
    }
    let maxWidth = 0;
    let totalHeight = 0;
    for (let i = 0; i < config.length; i++) {
        //计算最大宽度与合计高度
        if (config[i].w <= 0) {
            config[i].w = images[config[i].i - 1].width;
        }
        if (config[i].h <= 0) {
            config[i].h = images[config[i].i - 1].height;
        }
        maxWidth = Math.max(maxWidth, config[i].w * scale);
        totalHeight += config[i].h * scale;
    }
    if (maxWidth > 0 && totalHeight > 0) {
        //设置画布大小
        this.reset(maxWidth, totalHeight)
        //绘画到画布
        scale = scale * this.styleSize.width / this.originSize.width
        let height = 0;
        for (let i = 0; i < config.length; i++) {
            this.context.drawImage(images[config[i].i - 1], config[i].x, config[i].y, config[i].w, config[i].h, 0, height, config[i].w * scale * this.ratio, config[i].h * scale * this.ratio);
            height += (config[i].h * scale * this.ratio);
        }
    } else {
        this.reset()
    }
}

EasyCanvas.prototype.drawText = function (text, left, top) {
    this.context.font = this.fontConfig.size * this.ratio + 'px ' + this.fontConfig.name
    this.context.fillStyle = this.fontConfig.color
    this.context.fillText(text, left * this.ratio, top * this.ratio)
}

EasyCanvas.prototype.drawShape = function (trace) {
    if (trace && trace.length > 0) {
        this.context.lineWidth = this.lineConfig.width
        this.context.strokeStyle = this.lineConfig.color

        this.context.beginPath()
        this.context.moveTo(trace[0].x, trace[0].y)
        for (let i = 1; i < trace.length; i++) {
            this.context.lineTo(trace[i].x, trace[i].y)
            this.context.stroke()
        }
        this.context.closePath()
    }
}