/*
Copyright (c) 2025 WuJingrun(吴京润)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
 */
package f_util

import f_base.StringGenerator

abstract sealed class CaseFormat {
    /**
     * 首字母大写的驼峰
     */
    public static let Pascal: CaseFormat = PascalCaseFormat()
    /**
     * 首字母小写的驼峰
     */
    public static let Camel: CaseFormat = CamelCaseFormat()
    /**
     * 全小写按下划线分割
     */
    public static let LowerUnderScore: CaseFormat = LowerUnderScoreCaseFormat()
    /**
     * 全大写按下划线分割
     */
    public static let UpperUnderScore: CaseFormat = UpperUnderScoreCaseFormat()
    /**
     * 全小写按-分割
     */
    public static let LowerHyphen: CaseFormat = LowerHyphenCaseFormat()
    /**
     * 全大写按-分割
     */
    public static let UpperHyphen: CaseFormat = UpperHyphenCaseFormat()

    protected CaseFormat(protected let withDelimiter!: Bool) {}

    public func convert(text: String, to!: CaseFormat): String {
        let builder = StringGenerator()
        let caseFormat = to.new()
        let withDelim = this.withDelimiter
        for (ch in text.runes()) {
            let delim = isDelimiter(ch)
            if (delim && withDelim) {
                caseFormat.convert(ch, delim, builder)
            } else if (delim) {
                caseFormat.delimiter(builder)
            } else {
                caseFormat.convert(ch, false, builder)
            }
        }
        builder.toString()
    }
    protected func convert(ch: Rune, delimiter: Bool, builder: StringGenerator): Unit
    protected func delimiter(builder: StringGenerator): Unit
    protected func isDelimiter(ch: Rune): Bool
    protected func new(): CaseFormat
}

class PascalCaseFormat <: CaseFormat {
    init() {
        super(withDelimiter: true)
    }
    private var sectionStart = true
    protected func convert(ch: Rune, delimiter: Bool, builder: StringGenerator): Unit {
        let c = if (builder.size == 0) {
            sectionStart = false
            ch.toAsciiUpperCase()
        } else if (delimiter || sectionStart) {
            sectionStart = false
            ch.toAsciiUpperCase()
        } else {
            ch.toAsciiLowerCase()
        }
        builder.append(c)
    }
    protected func isDelimiter(ch: Rune): Bool {
        ch.isAsciiUpperCase()
    }
    protected func new(): CaseFormat {
        PascalCaseFormat()
    }
    protected func delimiter(builder: StringGenerator): Unit {
        sectionStart = true
    }
}

class CamelCaseFormat <: CaseFormat {
    init() {
        super(withDelimiter: true)
    }
    private var sectionStart = true
    protected func convert(ch: Rune, delimiter: Bool, builder: StringGenerator): Unit {
        let c = if (builder.size == 0) {
            sectionStart = false
            ch.toAsciiLowerCase()
        } else if (delimiter || sectionStart) {
            sectionStart = false
            ch.toAsciiUpperCase()
        } else {
            ch.toAsciiLowerCase()
        }
        builder.append(c)
    }
    protected func isDelimiter(ch: Rune): Bool {
        ch.isAsciiUpperCase()
    }
    protected func new(): CaseFormat {
        CamelCaseFormat()
    }
    protected func delimiter(builder: StringGenerator): Unit {
        sectionStart = true
    }
}

class LowerUnderScoreCaseFormat <: CaseFormat {
    init() {
        super(withDelimiter: false)
    }
    private static const DELIMITER = r'_'
    protected func convert(ch: Rune, delimiter: Bool, builder: StringGenerator): Unit {
        if (builder.size == 0) {
            builder.append(ch.toAsciiLowerCase())
        } else if (delimiter) {
            this.delimiter(builder)
            builder.append(ch.toAsciiLowerCase())
        } else {
            builder.append(ch.toAsciiLowerCase())
        }
    }
    protected func delimiter(builder: StringGenerator): Unit {
        builder.append(DELIMITER)
    }
    protected func isDelimiter(ch: Rune): Bool {
        ch == DELIMITER
    }
    protected func new(): CaseFormat {
        this
    }
}

class UpperUnderScoreCaseFormat <: CaseFormat {
    init() {
        super(withDelimiter: false)
    }
    private static const DELIMITER = r'_'
    protected func convert(ch: Rune, delimiter: Bool, builder: StringGenerator): Unit {
        if (builder.size == 0) {
            builder.append(ch.toAsciiUpperCase())
        } else if (delimiter) {
            this.delimiter(builder)
            builder.append(ch.toAsciiUpperCase())
        } else {
            builder.append(ch.toAsciiUpperCase())
        }
    }
    protected func delimiter(builder: StringGenerator): Unit {
        builder.append(DELIMITER)
    }
    protected func isDelimiter(ch: Rune): Bool {
        ch == DELIMITER
    }
    protected func new(): CaseFormat {
        this
    }
}

class LowerHyphenCaseFormat <: CaseFormat {
    init() {
        super(withDelimiter: false)
    }
    private static const DELIMITER = r'-'
    protected func convert(ch: Rune, delimiter: Bool, builder: StringGenerator): Unit {
        if (builder.size == 0) {
            builder.append(ch.toAsciiLowerCase())
        } else if (delimiter) {
            this.delimiter(builder)
            builder.append(ch.toAsciiLowerCase())
        } else {
            builder.append(ch.toAsciiLowerCase())
        }
    }
    protected func delimiter(builder: StringGenerator): Unit {
        builder.append(DELIMITER)
    }
    protected func isDelimiter(ch: Rune): Bool {
        ch == DELIMITER
    }
    protected func new(): CaseFormat {
        this
    }
}

class UpperHyphenCaseFormat <: CaseFormat {
    init() {
        super(withDelimiter: false)
    }
    private static const DELIMITER = r'-'
    protected func convert(ch: Rune, delimiter: Bool, builder: StringGenerator): Unit {
        if (builder.size == 0) {
            builder.append(ch.toAsciiUpperCase())
        } else if (delimiter) {
            this.delimiter(builder)
            builder.append(ch.toAsciiUpperCase())
        } else {
            builder.append(ch.toAsciiUpperCase())
        }
    }
    protected func delimiter(builder: StringGenerator): Unit {
        builder.append(DELIMITER)
    }
    protected func isDelimiter(ch: Rune): Bool {
        ch == DELIMITER
    }
    protected func new(): CaseFormat {
        this
    }
}