/*
 *  Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 *  This source file is part of the Cangjie project, licensed under Apache-2.0
 *  with Runtime Library Exception.
 *
 *  See https://cangjie-lang.cn/pages/LICENSE for license information.
 */

package stdx.string_intern

import std.sync.AtomicOptionReference

/**
 * Define an open interface for string-intern. Users should not use this interface, but directly use the {String#intern} method
 */
public interface Internable {
    /**
     * Returns a canonical representation for the string object.
     *
     * @param str new string object
     * @return string object in strings pool
     */
    static func intern(str: String): String

    /**
     * Returns a canonical representation for the string object.
     *
     * @param array new array object
     * @return string object in strings pool
     */
    static func intern(array: Array<Byte>): String

    /**
     * Config string intern pool
     *
     * @param capacity dynamic string pool capacity
     * @param strMaxLength max lenght of string in dynamic string pool
     */
    static func configInternPool(capacity!: Int64, strMaxLength!: Int64): Unit
}

class InternStringPoolHolder {
    static let poolRef = AtomicOptionReference<InternStringPool>()

    static func intern(value: String): String {
        if (value.size == 0) {
            return String.empty
        }

        match (poolRef.load()) {
            case Some(pool) => return pool.intern(value)
            case None => return value
        }
    }

    static func intern(value: Array<Byte>): String {
        if (value.size == 0) {
            return String.empty
        }

        match (poolRef.load()) {
            case Some(pool) => return pool.intern(value)
            case None =>
            let raw = unsafe {
                String.withRawData(value)
            }
            return raw
        }
    }

    static func config(capacity: Int64, strMaxLength: Int64): Unit {
        poolRef.compareAndSwap(None, InternStringPool(capacity, strMaxLength))
    }
}

extend String <: Internable {

    /**
     * Returns a canonical representation for the string object.
     *
     * @param str new string object
     * @return string object in strings pool
     */
    public static func intern(str: String): String {
        return InternStringPoolHolder.intern(str)
    }

    /**
     * Returns a canonical representation for the string object.
     *
     * @param array new array object
     * @return string object which is same as array in strings pool
     */
    public static func intern(array: Array<Byte>): String {
        return InternStringPoolHolder.intern(array)
    }

    /**
     * Config string intern pool
     *
     * @param capacity dynamic string pool capacity
     * @param strMaxLength max lenght of string in dynamic string pool
     */
    public static func configInternPool(capacity!: Int64 = 8192, strMaxLength!: Int64 = 512): Unit {
        if (capacity <= 0) {
            throw IllegalArgumentException("capacity should be positive: " + capacity.toString())
        }
        if (strMaxLength <= 0) {
            throw IllegalArgumentException("strMaxLength should be positive: " + strMaxLength.toString())
        }
        InternStringPoolHolder.config(capacity, strMaxLength)
    }
}