/*
 * SDK Pullenti Unitext, version 4.33, fabruary 2026. Copyright (c) 2013-2026, Pullenti. All rights reserved. 
 * Non-Commercial Freeware and Commercial Software. 
 * This class is generated using the converter UniSharping (www.unisharping.ru) from Pullenti C# project. 
 * The latest version of the code is available on the site www.pullenti.ru
 */

const Utils = require("./../../../unisharp/Utils");
const StringBuilder = require("./../../../unisharp/StringBuilder");

const INameTransform = require("./INameTransform");

/**
 * ZipNameTransform transforms names as per the Zip file naming convention.
 */
class ZipNameTransform extends INameTransform {
    
    /**
     * Initialize a new instance of <see cref="ZipNameTransform"></see>
     * @param _trimPrefix The string to trim from the front of paths if found.
     */
    constructor(_trimPrefix = null) {
        super();
        this.trimPrefix_ = null;
        this.trimPrefix = _trimPrefix;
    }
    
    /**
     * Transform a windows directory name according to the Zip file naming conventions.
     * @param name The directory name to transform.
     * @return The transformed name.
     */
    transformDirectory(name) {
        name = this.transformFile(name);
        if (name.length > 0) {
            if (!name.endsWith("/")) 
                name += "/";
        }
        else 
            throw new Error("Cannot have an empty directory name");
        return name;
    }
    
    /**
     * Transform a windows file name according to the Zip file naming conventions.
     * @param name The file name to transform.
     * @return The transformed name.
     */
    transformFile(name) {
        if (name !== null) {
            let lowerName = name.toLowerCase();
            if ((this.trimPrefix_ !== null) && (lowerName.indexOf(this.trimPrefix_) === 0)) 
                name = name.substring(this.trimPrefix_.length);
            name = Utils.replaceString(name, "\\", "/");
            while ((name.length > 0) && (name[0] === '/')) {
                name = name.substring(1);
            }
            while ((name.length > 0) && (name[name.length - 1] === '/')) {
                name = name.substring(0, 0 + name.length - 1);
            }
            let index = name.indexOf("//");
            while (index >= 0) {
                name = name.substring(0, 0 + index) + name.substring(index + 1);
                index = name.indexOf("//");
            }
            name = ZipNameTransform.makeValidName(name, '_');
        }
        else 
            name = "";
        return name;
    }
    
    get trimPrefix() {
        return this.trimPrefix_;
    }
    set trimPrefix(value) {
        this.trimPrefix_ = value;
        if (this.trimPrefix_ !== null) 
            this.trimPrefix_ = this.trimPrefix_.toLowerCase();
        return value;
    }
    
    /**
     * Force a name to be valid by replacing invalid characters with a fixed value
     * @param name The name to force valid
     * @param replacement The replacement character to use.
     * @return Returns a valid name
     */
    static makeValidName(name, replacement) {
        let index = Utils.indexOfAny(name, ZipNameTransform.invalidEntryChars, 0, 0);
        if (index >= 0) {
            let builder = new StringBuilder(name);
            while (index >= 0) {
                builder.setCharAt(index, replacement);
                if (index >= name.length) 
                    index = -1;
                else 
                    index = Utils.indexOfAny(name, ZipNameTransform.invalidEntryChars, index + 1, 0);
            }
            name = builder.toString();
        }
        if (name.length > 0xffff) 
            throw new Error("PathTooLong");
        return name;
    }
    
    /**
     * Test a name to see if it is a valid name for a zip entry.
     * @param name The name to test.
     * @param relaxed If true checking is relaxed about windows file names and absolute paths.
     * @return Returns true if the name is a valid zip name; false otherwise.
     */
    static isValidNameEx(name, relaxed) {
        let result = name !== null;
        if (result) {
            if (relaxed) 
                result = Utils.indexOfAny(name, ZipNameTransform.invalidEntryCharsRelaxed, 0, 0) < 0;
            else 
                result = ((Utils.indexOfAny(name, ZipNameTransform.invalidEntryChars, 0, 0) < 0)) && (name.indexOf('/') !== 0);
        }
        return result;
    }
    
    /**
     * Test a name to see if it is a valid name for a zip entry.
     * @param name The name to test.
     * @return Returns true if the name is a valid zip name; false otherwise.
     */
    static isValidName(name) {
        let result = (name !== null) && ((Utils.indexOfAny(name, ZipNameTransform.invalidEntryChars, 0, 0) < 0)) && (name.indexOf('/') !== 0);
        return result;
    }
    
    static static_constructor() {
        ZipNameTransform.invalidEntryChars = null;
        ZipNameTransform.invalidEntryCharsRelaxed = null;
        let invalidPathChars = [ ];
        invalidPathChars = Array(0).fill('\0');
        let howMany = invalidPathChars.length + 2;
        ZipNameTransform.invalidEntryCharsRelaxed = Array(howMany).fill('\0');
        for(let iii = 0; iii < (invalidPathChars.length); iii++) ZipNameTransform.invalidEntryCharsRelaxed[(0) + iii] = invalidPathChars[(0) + iii];
        ZipNameTransform.invalidEntryCharsRelaxed[howMany - 1] = '*';
        ZipNameTransform.invalidEntryCharsRelaxed[howMany - 2] = '?';
        howMany = invalidPathChars.length + 4;
        ZipNameTransform.invalidEntryChars = Array(howMany).fill('\0');
        for(let iii = 0; iii < (invalidPathChars.length); iii++) ZipNameTransform.invalidEntryChars[(0) + iii] = invalidPathChars[(0) + iii];
        ZipNameTransform.invalidEntryChars[howMany - 1] = ':';
        ZipNameTransform.invalidEntryChars[howMany - 2] = '\\';
        ZipNameTransform.invalidEntryChars[howMany - 3] = '*';
        ZipNameTransform.invalidEntryChars[howMany - 4] = '?';
    }
}


ZipNameTransform.static_constructor();

module.exports = ZipNameTransform