// Core JavaScript helper functions
'use strict';

// quickElement(tagType, parentReference [, textInChildNode, attribute, attributeValue ...]);
/**
 * 快速创建并插入DOM元素
 * 简化创建元素、添加文本、设置属性、插入父容器的流程
 * @param {string} arguments[0] - 要创建的元素标签名（如"div"、"a"）
 * @param {HTMLElement} arguments[1] - 父容器元素（新元素将插入到该容器中）
 * @param {string} [arguments[2]] - 新元素的文本内容（可选）
 * @param {string} [arguments[3], arguments[4]...] - 属性名和属性值（成对传入，可选）
 * @return {HTMLElement} 创建并插入后的新元素
 */
function quickElement() {
    const obj = document.createElement(arguments[0]);
    if (arguments[2]) {
        const textNode = document.createTextNode(arguments[2]);
        obj.appendChild(textNode);
    }
    const len = arguments.length;
    for (let i = 3; i < len; i += 2) {
        obj.setAttribute(arguments[i], arguments[i + 1]);
    }
    arguments[1].appendChild(obj);
    return obj;
}

// "a" is reference to an object
/**
 * 清空元素的所有子节点
 * @param {HTMLElement} a - 要清空子节点的父元素
 */
function removeChildren(a) {
    while (a.hasChildNodes()) {
        a.removeChild(a.lastChild);
    }
}

// ----------------------------------------------------------------------------
// Find-position functions by PPK
// See https://www.quirksmode.org/js/findpos.html
// ----------------------------------------------------------------------------
/**
 * 计算元素相对于文档的水平偏移量（X轴位置）
 * @param {HTMLElement} obj - 要计算位置的元素
 * @return {number} 元素左上角相对于文档左侧的距离（像素）
 */
function findPosX(obj) {
    let curleft = 0;
    // 若元素有offsetParent（定位父元素），循环向上计算偏移
    if (obj.offsetParent) {
        while (obj.offsetParent) {
            curleft += obj.offsetLeft - obj.scrollLeft;
            obj = obj.offsetParent;
        }
    } else if (obj.x) {
        curleft += obj.x;
    }
    return curleft;
}
/**
 * 计算元素相对于文档的垂直偏移量（Y轴位置）
 * @param {HTMLElement} obj - 要计算位置的元素
 * @return {number} 元素左上角相对于文档顶部的距离（像素）
 */
function findPosY(obj) {
    let curtop = 0;
    if (obj.offsetParent) {
        while (obj.offsetParent) {
            curtop += obj.offsetTop - obj.scrollTop;
            obj = obj.offsetParent;
        }
    } else if (obj.y) {
        curtop += obj.y;
    }
    return curtop;
}

//-----------------------------------------------------------------------------
// Date object extensions
// ----------------------------------------------------------------------------
{
    /**
     * 获取12小时制的小时数（0-11 → 1-12）
     * @return {number} 12小时制小时数（如13点返回1，0点返回12）
     */
    Date.prototype.getTwelveHours = function() {
        return this.getHours() % 12 || 12;
    };
    /**
     * 获取两位数的月份（1-9 → 01-09，10-12 → 10-12）
     * @return {string} 两位数月份字符串
     */
    Date.prototype.getTwoDigitMonth = function() {
        return (this.getMonth() < 9) ? '0' + (this.getMonth() + 1) : (this.getMonth() + 1);
    };

    Date.prototype.getTwoDigitDate = function() {
        return (this.getDate() < 10) ? '0' + this.getDate() : this.getDate();
    };

    Date.prototype.getTwoDigitTwelveHour = function() {
        return (this.getTwelveHours() < 10) ? '0' + this.getTwelveHours() : this.getTwelveHours();
    };

    Date.prototype.getTwoDigitHour = function() {
        return (this.getHours() < 10) ? '0' + this.getHours() : this.getHours();
    };

    Date.prototype.getTwoDigitMinute = function() {
        return (this.getMinutes() < 10) ? '0' + this.getMinutes() : this.getMinutes();
    };

    Date.prototype.getTwoDigitSecond = function() {
        return (this.getSeconds() < 10) ? '0' + this.getSeconds() : this.getSeconds();
    };

    Date.prototype.getAbbrevDayName = function() {
        return typeof window.CalendarNamespace === "undefined"
            ? '0' + this.getDay()
            : window.CalendarNamespace.daysOfWeekAbbrev[this.getDay()];
    };

    Date.prototype.getFullDayName = function() {
        return typeof window.CalendarNamespace === "undefined"
            ? '0' + this.getDay()
            : window.CalendarNamespace.daysOfWeek[this.getDay()];
    };

    Date.prototype.getAbbrevMonthName = function() {
        return typeof window.CalendarNamespace === "undefined"
            ? this.getTwoDigitMonth()
            : window.CalendarNamespace.monthsOfYearAbbrev[this.getMonth()];
    };

    Date.prototype.getFullMonthName = function() {
        return typeof window.CalendarNamespace === "undefined"
            ? this.getTwoDigitMonth()
            : window.CalendarNamespace.monthsOfYear[this.getMonth()];
    };
    /**
     * 格式化日期为指定字符串（类似Python的strftime）
     * @param {string} format - 格式化字符串（含%占位符，如“%Y-%m-%d %H:%M”）
     * @return {string} 格式化后的日期字符串
     */
    Date.prototype.strftime = function(format) {
        const fields = {
            a: this.getAbbrevDayName(),
            A: this.getFullDayName(),
            b: this.getAbbrevMonthName(),
            B: this.getFullMonthName(),
            c: this.toString(),
            d: this.getTwoDigitDate(),
            H: this.getTwoDigitHour(),
            I: this.getTwoDigitTwelveHour(),
            m: this.getTwoDigitMonth(),
            M: this.getTwoDigitMinute(),
            p: (this.getHours() >= 12) ? 'PM' : 'AM',
            S: this.getTwoDigitSecond(),
            w: '0' + this.getDay(),
            x: this.toLocaleDateString(),
            X: this.toLocaleTimeString(),
            y: ('' + this.getFullYear()).substr(2, 4),
            Y: '' + this.getFullYear(),
            '%': '%'
        };
        let result = '', i = 0;
        while (i < format.length) {
            if (format.charAt(i) === '%') {
                result += fields[format.charAt(i + 1)];
                ++i;
            }
            else {
                result += format.charAt(i);
            }
            ++i;
        }
        return result;
    };

    // ----------------------------------------------------------------------------
    // String object extensions
    // ----------------------------------------------------------------------------
    /**
     * 将字符串按指定格式解析为Date对象（类似Python的strptime）
     * 支持的格式占位符：%d（日期）、%m（月份）、%Y（四位数年份）、%y（两位数年份）
     * @param {string} format - 解析格式（如“%Y-%m-%d”“%d/%m/%y”）
     * @return {Date} 解析后的Date对象（基于UTC时间）
     */
    String.prototype.strptime = function(format) {
        const split_format = format.split(/[.\-/]/);
        const date = this.split(/[.\-/]/);
        let i = 0;
        let day, month, year;
        while (i < split_format.length) {
            switch (split_format[i]) {
            case "%d":
                day = date[i];
                break;
            case "%m":
                month = date[i] - 1;
                break;
            case "%Y":
                year = date[i];
                break;
            case "%y":
                // A %y value in the range of [00, 68] is in the current
                // century, while [69, 99] is in the previous century,
                // according to the Open Group Specification.
                if (parseInt(date[i], 10) >= 69) {
                    year = date[i];
                } else {
                    year = (new Date(Date.UTC(date[i], 0))).getUTCFullYear() + 100;
                }
                break;
            }
            ++i;
        }
        // Create Date object from UTC since the parsed value is supposed to be
        // in UTC, not local time. Also, the calendar uses UTC functions for
        // date extraction.
        return new Date(Date.UTC(year, month, day));
    };
}
