/*胡红勋 定义字体符号定义类----
 */

import { inherits } from 'ol'
import ol_style_RegularShape from 'ol/style/RegularShape'
import ol_style_Image from 'ol/style/Image'
import { asString as ol_color_asString } from 'ol/color'

/**
 * @classdesc
 * A marker style to use with font symbols.
 *
 * @constructor
 * @param {} options Options.
 *  @param {number} options.glyph the glyph name or a char to display as symbol. 
 * 		The name must be added using the {@link ol.style.FontSymbol.addDefs} function.
 *  @param {string} options.form 
 * 		none|circle|poi|bubble|marker|coma|shield|blazon|bookmark|hexagon|diamond|triangle|sign|ban|lozenge|square
 * 		a form that will enclose the glyph, default none
 *  @param {number} options.radius
 *  @param {number} options.rotation
 *  @param {number} options.rotateWithView
 *  @param {number} options.opacity
 *  @param {number} options.fontSize, default 1
 *  @param {string} options.fontStyle the font style (bold, italic, bold italic, etc), default none
 *  @param {boolean} options.gradient true to display a gradient on the symbol
 *  @param {_ol_style_Fill_} options.fill
 *  @param {_ol_style_Stroke_} options.stroke
 * @extends {ol_style_RegularShape}
 * @implements {ol.structs.IHasChecksum}
 * @api
 */
var ol_style_FontSymbol = function(options) {
        options = options || {}
        var strokeWidth = 0
        if (options.stroke) {
            strokeWidth = options.stroke.getWidth()
        }
        // 调用父类的构造函数，获取父类的方法和属性-----
        ol_style_RegularShape.call(this, {
            radius: options.radius,
            fill: options.fill,
            rotation: options.rotation,
            rotateWithView: options.rotateWithView
        })
        if (typeof(options.opacity) == "number") {
            this.setOpacity(options.opacity)
        }
        this.color_ = options.color
        this.fontSize_ = options.fontSize || 1
        this.fontStyle_ = options.fontStyle || ''
        this.stroke_ = options.stroke
        this.fill_ = options.fill
        this.radius_ = options.radius - strokeWidth
        this.form_ = options.form || "none"
        this.gradient_ = options.gradient
        this.offset_ = [options.offsetX ? options.offsetX : 0, options.offsetY ? options.offsetY : 0]
            // 字形符号
        this.glyph_ = this.getGlyph(options.glyph) || ""
            // 渲染点-----
        this.renderMarker_()
    }
    // 定义继承关系------
inherits(ol_style_FontSymbol, ol_style_RegularShape)

/** 很酷的东西来获得一种风格的图像符号
 */
ol_style_Image.prototype.getImagePNG = function() {
    var canvas = this.getImage()
    if (canvas) {
        try { return canvas.toDataURL("image/png") } catch (e) {
            return false
        }
    } else {
        return false
    }
}

/** 
 *	Font defs
 */
ol_style_FontSymbol.prototype.defs = { 'fonts': {}, 'glyphs': {} }

/** 静态函数,添加字体和字形依赖------ 
 * @param {String|Object} font 字体描述----
 * @param {} glyphs 字形定义的键/值列表
 * 		每个键都是字形的名称, 
 * 		该值是对字体和字符代码进行编码的对象, 
 * 		字形的名称和搜索字符串.
 */
ol_style_FontSymbol.addDefs = function(font, glyphs) {
    var thefont = font
    if (typeof(font) == "string") {
        thefont = { "font": font, "name": font, "copyright": "" }
    }
    if (!thefont.font || typeof(thefont.font) != "string") {
        console.log("bad font def")
        return
    }
    var fontname = thefont.font
    ol_style_FontSymbol.prototype.defs.fonts[fontname] = thefont
    for (var i in glyphs) {
        var g = glyphs[i] // 对象，格式：{ "font": "fontmaki", "code": 59392, "name": "bicycle", "search": "bicycle" }
        if (typeof(g) == "string" && g.length == 1) {
            g = { char: g }
        }
        // g.char || "" + String.fromCharCode(parseInt(g.code, 16).toString(10)) || "",
        ol_style_FontSymbol.prototype.defs.glyphs[i] = {
            font: thefont.font,
            char: g.code,
            theme: g.theme || thefont.name,
            name: g.name || i,
            search: g.search || ""
        }
    }
}

/**
 * 克隆样式--------
 * @return {ol_style_FontSymbol}
 */
ol_style_FontSymbol.prototype.clone = function() {
    var g = new ol_style_FontSymbol({
        glyph: "",
        color: this.color_,
        fontSize: this.fontSize_,
        fontStyle: this.fontStyle_,
        stroke: this.stroke_,
        fill: this.fill_,
        radius: this.radius_ + (this.stroke_ ? this.stroke_.getWidth() : 0),
        form: this.form_,
        gradient: this.gradient_,
        offsetX: this.offset_[0],
        offsetY: this.offset_[1],
        opacity: this.getOpacity(),
        rotation: this.getRotation(),
        rotateWithView: this.getRotateWithView()
    })
    g.setScale(this.getScale())
    g.glyph_ = this.glyph_
    g.renderMarker_()
    return g
}

/**
 * 获取此样式的填充样式-----
 * @return {ol_style_Fill} Fill style.
 * @api
 */
ol_style_FontSymbol.prototype.getFill = function() {
    return this.fill_
}

/**
 * 获取此符号的线样式---------
 * @return {_ol_style_Stroke_} Stroke style.
 * @api
 */
ol_style_FontSymbol.prototype.getStroke = function() {
    return this.stroke_
}

/**
 * 获取此符号的字形定义----------
 * @param {string|undefined} name a glyph name to get the definition, default return the glyph definition for the style.
 * @return {_ol_style_Stroke_} 线样式-----
 * @api
 */
ol_style_FontSymbol.prototype.getGlyph = function(name) {
    if (name) {
        return ol_style_FontSymbol.prototype.defs.glyphs[name] || { "font": "none", "char": name.charAt(0), "theme": "none", "name": "none", "search": "" }
    } else {
        return this.glyph_
    }
}

/**
 * 获取字形名称---
 * @return {string} the name
 * @api
 */
ol_style_FontSymbol.prototype.getGlyphName = function() {
    for (var i in ol_style_FontSymbol.prototype.defs.glyphs) {
        if (ol_style_FontSymbol.prototype.defs.glyphs[i] === this.glyph_) {
            return i
        }
    }
    return ""
}

/**
 * 获取符号的线样式---
 * @return {_ol_style_Stroke_} Stroke style.
 * @api
 */
ol_style_FontSymbol.prototype.getFontInfo = function(glyph) {
    return ol_style_FontSymbol.prototype.defs.fonts[glyph.font]
}

/** @private 渲染绘制点----
 */
ol_style_FontSymbol.prototype.renderMarker_ = function() {
    var strokeStyle
    var strokeWidth = 0

    if (this.stroke_) {
        strokeStyle = ol_color_asString(this.stroke_.getColor())
        strokeWidth = this.stroke_.getWidth()
    }

    // no atlas manager is used, create a new canvas
    var canvas = this.getImage()

    /** @type {ol_style_FontSymbol.RenderOptions} */
    var renderOptions = {
            strokeStyle: strokeStyle,
            strokeWidth: strokeWidth,
            size: canvas.width,
        }
        // 绘制圆在canvas
    var context = (canvas.getContext('2d'))
    context.clearRect(0, 0, canvas.width, canvas.height)
    this.drawMarker_(renderOptions, context, 0, 0)
        // 设置锚点
    var a = this.getAnchor()
    a[0] = canvas.width / 2 - this.offset_[0]
    a[1] = canvas.width / 2 - this.offset_[1]
}

/**
 * @private
 * @param {ol_style_FontSymbol.RenderOptions} renderOptions
 * @param {CanvasRenderingContext2D} context
 */
ol_style_FontSymbol.prototype.drawPath_ = function(renderOptions, context) {
    var s = 2 * this.radius_ + renderOptions.strokeWidth + 1
    var w = renderOptions.strokeWidth / 2
    var c = renderOptions.size / 2
    var transfo = { fac: 1, posX: renderOptions.size / 2, posY: renderOptions.size / 2 }
    context.lineJoin = 'round'
    context.beginPath()
        // 绘制符号---
    switch (this.form_) {
        case "none":
            transfo.fac = 1
            break
        case "circle":
        case "ban":
            context.arc(c, c, s / 2, 0, 2 * Math.PI, true)
            break
        case "poi":
            context.arc(c, c - 0.4 * this.radius_, 0.6 * this.radius_, 0.15 * Math.PI, 0.85 * Math.PI, true)
            context.lineTo(c - 0.89 * 0.05 * s, (0.95 + 0.45 * 0.05) * s + w)
            context.arc(c, 0.95 * s + w, 0.05 * s, 0.85 * Math.PI, 0.15 * Math.PI, true)
            transfo = { fac: 0.45, posX: c, posY: c - 0.35 * this.radius_ }
            break
        case "bubble":
            context.arc(c, c - 0.2 * this.radius_, 0.8 * this.radius_, 0.4 * Math.PI, 0.6 * Math.PI, true)
            context.lineTo(0.5 * s + w, s + w)
            transfo = { fac: 0.7, posX: c, posY: c - 0.2 * this.radius_ }
            break
        case "marker":
            context.arc(c, c - 0.2 * this.radius_, 0.8 * this.radius_, 0.25 * Math.PI, 0.75 * Math.PI, true)
            context.lineTo(0.5 * s + w, s + w)
            transfo = { fac: 0.7, posX: c, posY: c - 0.2 * this.radius_ }
            break
        case "coma":
            context.moveTo(c + 0.8 * this.radius_, c - 0.2 * this.radius_)
            context.quadraticCurveTo(0.95 * s + w, 0.75 * s + w, 0.5 * s + w, s + w)
            context.arc(c, c - 0.2 * this.radius_, 0.8 * this.radius_, 0.45 * Math.PI, 0, false)
            transfo = { fac: 0.7, posX: c, posY: c - 0.2 * this.radius_ }
            break
        default:
            {
                var pts = []
                switch (this.form_) {
                    case "shield":
                        pts = [0.05, 0, 0.95, 0, 0.95, 0.8, 0.5, 1, 0.05, 0.8, 0.05, 0]
                        transfo.posY = 0.45 * s + w
                        break;
                    case "blazon":
                        pts = [0.1, 0, 0.9, 0, 0.9, 0.8, 0.6, 0.8, 0.5, 1, 0.4, 0.8, 0.1, 0.8, 0.1, 0]
                        transfo.fac = 0.8
                        transfo.posY = 0.4 * s + w
                        break;
                    case "bookmark":
                        pts = [0.05, 0, 0.95, 0, 0.95, 1, 0.5, 0.8, 0.05, 1, 0.05, 0]
                        transfo.fac = 0.9
                        transfo.posY = 0.4 * s + w
                        break;
                    case "hexagon":
                        pts = [0.05, 0.2, 0.5, 0, 0.95, 0.2, 0.95, 0.8, 0.5, 1, 0.05, 0.8, 0.05, 0.2]
                        transfo.fac = 0.9
                        transfo.posY = 0.5 * s + w
                        break;
                    case "diamond":
                        pts = [0.25, 0, 0.75, 0, 1, 0.2, 1, 0.4, 0.5, 1, 0, 0.4, 0, 0.2, 0.25, 0]
                        transfo.fac = 0.75
                        transfo.posY = 0.35 * s + w
                        break;
                    case "triangle":
                        pts = [0, 0, 1, 0, 0.5, 1, 0, 0]
                        transfo.fac = 0.6
                        transfo.posY = 0.3 * s + w
                        break;
                    case "sign":
                        pts = [0.5, 0.05, 1, 0.95, 0, 0.95, 0.5, 0.05]
                        transfo.fac = 0.7
                        transfo.posY = 0.65 * s + w
                        break;
                    case "lozenge":
                        pts = [0.5, 0, 1, 0.5, 0.5, 1, 0, 0.5, 0.5, 0]
                        transfo.fac = 0.7
                        break;
                    case "square":
                    default:
                        pts = [0, 0, 1, 0, 1, 1, 0, 1, 0, 0]
                        break
                }
                for (var i = 0; i < pts.length; i += 2) {
                    context.lineTo(pts[i] * s + w, pts[i + 1] * s + w)
                }
            }
    }
    context.closePath()
    return transfo
}

/**
 * @private
 * @param {ol_style_FontSymbol.RenderOptions} renderOptions
 * @param {CanvasRenderingContext2D} context
 * @param {number} x The origin for the symbol (x).
 * @param {number} y The origin for the symbol (y).
 */
ol_style_FontSymbol.prototype.drawMarker_ = function(renderOptions, context, x, y) {
    var fcolor = this.fill_ ? this.fill_.getColor() : "#000"
    var scolor = this.stroke_ ? this.stroke_.getColor() : "#000"
    if (this.form_ == "none" && this.stroke_ && this.fill_) {
        scolor = this.fill_.getColor()
        fcolor = this.stroke_.getColor()
    }
    context.setTransform(1, 0, 0, 1, 0, 0)
        // 移动到该点-----
    context.translate(x, y)
    var tr = this.drawPath_(renderOptions, context)
    if (this.fill_) {
        if (this.gradient_ && this.form_ != "none") {
            var grd = context.createLinearGradient(0, 0, renderOptions.size / 2, renderOptions.size)
            grd.addColorStop(1, ol_color_asString(fcolor))
            grd.addColorStop(0, ol_color_asString(scolor))
            context.fillStyle = grd
        } else {
            context.fillStyle = ol_color_asString(fcolor)
        }
        context.fill()
    }
    if (this.stroke_ && renderOptions.strokeWidth) {
        context.strokeStyle = renderOptions.strokeStyle
        context.lineWidth = renderOptions.strokeWidth
        context.stroke()
    }
    // 绘制该符号-------
    if (this.glyph_.char) {
        context.font = this.fontStyle_ + ' ' +
            (2 * tr.fac * (this.radius_) * this.fontSize_) + "px " +
            this.glyph_.font
        context.strokeStyle = context.fillStyle
        context.lineWidth = renderOptions.strokeWidth * (this.form_ == "none" ? 2 : 1)
        context.fillStyle = ol_color_asString(this.color_ || scolor)
        context.textAlign = "center"
        context.textBaseline = "middle"
        var t = this.glyph_.char
        var icon = eval('("' + t.replace('&#x', '\\u').replace(';', '') + '")')
        if (renderOptions.strokeWidth && scolor != "transparent") context.strokeText(icon, tr.posX, tr.posY)
        context.fillText(icon, tr.posX, tr.posY)
    }
    if (this.form_ == "ban" && this.stroke_ && renderOptions.strokeWidth) {
        context.strokeStyle = renderOptions.strokeStyle
        context.lineWidth = renderOptions.strokeWidth
        var r = this.radius_ + renderOptions.strokeWidth
        var d = this.radius_ * Math.cos(Math.PI / 4)
        context.moveTo(r + d, r - d)
        context.lineTo(r - d, r + d)
        context.stroke()
    }
}

/**
 * @inheritDoc
 */
ol_style_FontSymbol.prototype.getChecksum = function() {
    var strokeChecksum = (this.stroke_ !== null) ?
        this.stroke_.getChecksum() : '-'
    var fillChecksum = (this.fill_ !== null) ?
        this.fill_.getChecksum() : '-'

    var recalculate = (this.checksums_ === null) ||
        (strokeChecksum != this.checksums_[1] ||
            fillChecksum != this.checksums_[2] ||
            this.radius_ != this.checksums_[3] ||
            this.form_ + "-" + this.glyphs_ != this.checksums_[4])

    if (recalculate) {
        var checksum = 'c' + strokeChecksum + fillChecksum +
            ((this.radius_ !== void 0) ? this.radius_.toString() : '-') +
            this.form_ + "-" + this.glyphs_
        this.checksums_ = [checksum, strokeChecksum, fillChecksum, this.radius_, this.form_ + "-" + this.glyphs_]
    }

    return this.checksums_[0]
}

export default ol_style_FontSymbol