function SavePPT(config) {
    this.tanscale = Math.max(config.maxBoundary.maxX, config.maxBoundary.maxY) / 99
    this.config = this.computedConfig(config)
    this.pres = new PptxGenJS();
    this.slide = this.pres.addSlide();
    this.unit = 0.0254
    this.overBoundary = false

    this.config.data.pptData.map(node => this.addShapeRect(node, this.config.rect))
    this.config.data.pptPath.map(path => this.addLine(path, this.config.rect, this.config.isVertical))
}

SavePPT.prototype.computedConfig = function (config) {
    config.data = this.initPptData(config.data.pptData, config.data.pptPath, config.isVertical)
    config.rect = {
        w: config.rect.w / this.tanscale,
        h: config.rect.h / this.tanscale
    }
    return config
}

SavePPT.prototype.addText = function () {
    let textboxText = "组织架构图";
    let textboxOpts = {
        x: 1,
        y: 1,
        color: '363636',
        fill: {
            color: 'F1F1F1'
        },
        align: "center"
    };
    this.slide.addText(textboxText, textboxOpts);
}

SavePPT.prototype.getTxtLoc = function (card, rect) {
    let x = 0
    let y = 0

    if (typeof card.x === "string") {
        x = rect.w * (parseInt(card.x) / this.tanscale)
    } else {
        x = card.x
    }

    if (typeof card.y === "string") {
        y = rect.h * (parseInt(card.y) / this.tanscale)
    } else {
        y = card.y
    }
    return {
        x: x / this.tanscale,
        y: y / this.tanscale
    }
}

SavePPT.prototype.addShapeRect = function (node, rect) {
    if (isBoundary(node)) {
        this.overBoundary = true
        return
    }
    let cardModel = this.config.cardModel[this.config.selectCardModel(node)]
    this.slide.addShape(this.pres.ShapeType.rect, {
        x: node.x,
        y: node.y,
        w: rect.w,
        h: rect.h,
        // shadow: {
        //     type: "outer",
        //     angle: 45,
        //     blur: 3,
        //     color: "cccccc",
        //     offset: 1,
        //     opacity: 1
        // },
        line: {
            color: "cccccc",
            dashType: node.data.lineType ? "sysDot" : "solid",
            width: 1
        },
        fill: {
            color: "ffffff"
        }
    });

    cardModel.map(card => {
        let name = ""
        let fill = "ffffff"
        let fontToLenRate = 7 / 10
        let linenums = card.lineNums ? card.lineNums : 1
        let fontSize = card.fontSize * fontToLenRate * 100 / this.tanscale
        let {
            x,
            y
        } = this.getTxtLoc(card, rect)

        if (typeof card.fill === "function") {
            fill = card.fill(node.data)
        } else {
            fill = card.fill
        }

        let svgToPptRate = 100
        let fontLen = linenums * parseInt(rect.w * svgToPptRate / fontSize)
        name = card.text(node.data) || ""
        name = name.length <= fontLen ? name : (name.slice(0, fontLen - 2) + "……")
        let hh = linenums * fontSize / fontToLenRate / svgToPptRate

        this.slide.addText(name, {
            x: node.x + x,
            y: node.y + y - fontSize / svgToPptRate, //svg的文字Y=0，和PPT文字的Y=0k的起点不一样
            w: rect.w - x,
            h: hh,
            color: translateColor(fill),
            fontSize: fontSize,
            margin: 0,
            valign: "middle",
            lineSpacing: 0,
            shape: this.pres.ShapeType.rect
        });
    })

}

SavePPT.prototype.paintLine = function (source, lines) {
    lines.map(path => {
        if (path.key === "V") {
            this.painVertical(source, path.len)
            source.y += path.len
        }
        if (path.key === "H") {
            this.painHorizontal(source, path.len)
            source.x += path.len
        }
    })
}

SavePPT.prototype.painVertical = function (source, v) {
    let x = source.x - Math.abs(v) / 2
    let y = source.y + v / 2
    this.slide.addText("", {
        shape: this.pres.ShapeType.line,
        rotate: 90,
        x: x,
        y: y,
        w: Math.abs(v),
        line: {
            color: "777777",
            width: 1
        }
    });
}

SavePPT.prototype.painHorizontal = function (source, H) {
    let x = source.x + (H > 0 ? 0 : H)
    let y = source.y
    this.slide.addText("", {
        shape: this.pres.ShapeType.line,
        x: x,
        y: y,
        w: Math.abs(H),
        line: {
            color: "777777",
            width: 1
        }
    });
}

SavePPT.prototype.addLine = function (path, rect, isVertical = true) {
    if (isBoundary(path.source) || isBoundary(path.target)) {
        this.overBoundary = true
        return
    }
    let isleafpar = path.source.isleafpar
    let childlen = path.source.childlen
    let tarIndex = path.target.tarIndex

    let source = {
        x: isVertical ? (path.source.x + rect.w / 2) : (path.source.x + rect.w),
        y: isVertical ? (path.source.y + rect.h) : (path.source.y + rect.h / 2)
    }

    let lines = []

    if (isleafpar) {
        let target = {
            x: 0,
            y: 0
        }
        if (childlen % 2 != 0 && childlen === (tarIndex + 1)) {
            target = {
                x: isVertical ? (path.target.x + rect.w / 2) : path.target.x,
                y: isVertical ? path.target.y : (path.target.y + rect.h / 2)
            }
        } else if (tarIndex % 2 === 1) {
            target = {
                x: isVertical ? (path.target.x) : (path.target.x + rect.w / 2),
                y: isVertical ? (path.target.y + rect.h / 2) : path.target.y
            }
        } else if (tarIndex % 2 === 0) {
            target = {
                x: isVertical ? (path.target.x + +rect.w) : (path.target.x + rect.w / 2),
                y: isVertical ? (path.target.y + rect.h / 2) : (path.target.y + rect.h)
            }
        }
        let h = isVertical ? (source.x - target.x) : Math.abs(source.x - target.x)
        let v = isVertical ? Math.abs(source.y - target.y) : (source.y - target.y)
        if (isVertical) {
            lines = [{
                key: "V",
                len: v
            }, {
                key: "H",
                len: h
            }]
        } else {
            lines = [{
                key: "H",
                len: h
            }, {
                key: "V",
                len: v
            }]
        }
    } else {
        let target = {
            x: isVertical ? (path.target.x + rect.w / 2) : path.target.x,
            y: isVertical ? path.target.y : (path.target.y + rect.h / 2)
        }

        let h = isVertical ? (target.x - source.x) : Math.abs(source.x - target.x)
        let v = isVertical ? Math.abs(source.y - target.y) : (source.y - target.y)
        if (isVertical) {
            lines = [{
                key: "V",
                len: v / 2
            }, {
                key: "H",
                len: h
            }, {
                key: "V",
                len: v / 2
            }]
        } else {
            lines = [{
                key: "H",
                len: h / 2
            }, {
                key: "V",
                len: v
            }, {
                key: "H",
                len: h / 2
            }]
        }
    }
    this.paintLine(source, lines)
}

SavePPT.prototype.down = function down() {
    this.pres.writeFile("组织架构图");
    if (this.overBoundary) {
        console.error("溢出");
    }
}

SavePPT.prototype.initPptData = function (pptData, pptPath, isVertical) {
    for (let i = 0; i < pptData.length; i++) {
        pptData[i].x = pptData[i].x / this.tanscale //+ (isVertical ? 5 : 2)
        pptData[i].y = pptData[i].y / this.tanscale //+ (isVertical ? 0 : 2)
    }
    for (let i = 0; i < pptPath.length; i++) {
        pptPath[i].source.x = pptPath[i].source.x / this.tanscale //+ (isVertical ? 5 : 2)
        pptPath[i].source.y = pptPath[i].source.y / this.tanscale //+ (isVertical ? 0 : 2)

        pptPath[i].target.x = pptPath[i].target.x / this.tanscale //+ (isVertical ? 5 : 2)
        pptPath[i].target.y = pptPath[i].target.y / this.tanscale //+ (isVertical ? 0 : 2)
    }
    return {
        pptData,
        pptPath
    }
}

function translateColor(color) {
    color = color.replace("#", "")
    if (color.length === 3) {
        let colors = ""
        color.split('').map(c => {
            colors += (c + "" + c)
        })
        return colors
    }
    return color
}

function isBoundary(node) {
    return (node.x >= 100 || node.y >= 100 || node.x <= -100 || node.y <= -100)
}