"use strict";
const EQUAL_SIZE_EMPTY_FOLDER = 10;
const BrowserFeatures = {
    hasFileSystemAPI: () => {
        return 'showOpenFilePicker' in window &&
            'showDirectoryPicker' in window &&
            'showSaveFilePicker' in window;
    },
    hasSaveFilePicker: () => {
        return 'showSaveFilePicker' in window;
    },
    hasDirectoryPicker: () => {
        return 'showDirectoryPicker' in window;
    },
    hasWebkitDirectory: () => {
        const input = document.createElement('input');
        input.type = 'file';
        return 'webkitdirectory' in input || 'webkitDirectory' in input;
    },
    hasAnything: () => {
        return BrowserFeatures.hasFileSystemAPI() || BrowserFeatures.hasWebkitDirectory();
    }
};
class CProgressBar {
    constructor(ind, num, control, p = {}) {
        this.nAlready = BigInt(0);
        this.domInd = ind;
        this.domNum = num;
        this.oControl = control;
        if (!p.accuracy) {
            this.accuracy = 0;
        }
        else if (p.accuracy < 0) {
            this.accuracy = -p.accuracy;
        }
        else {
            this.accuracy = p.accuracy;
        }
        this.nSize = p.size || BigInt(-1);
    }
    UpdatePB(n) {
        if (this.nSize <= 0)
            return -1;
        this.nAlready += BigInt(Math.round(n));
        const percent = BigIntToNum(this.nAlready * BigInt(100) / this.nSize);
        const sPercent = percent.toFixed(this.accuracy) + "%";
        this.domNum.innerHTML = sPercent;
        this.domInd.style.width = sPercent;
        return percent;
    }
    DidDownloadStop() {
        return this.oControl.bStopFlag;
    }
}
class CShowFileOperation {
    constructor(sTitle, sText1, sText2, bNoModal = true) {
        this.bStopFlag = false;
        this.sProblemFiles = "";
        this.nStartTime = -1;
        this.nLastTime = -1;
        this.nFiltSpeed = -1;
        this.nCurrSize = 0;
        this.sPath = "";
        let fm1FileDownload = {
            "title": sTitle,
            bottom_box: [{ title: "Btn_Cancel", id: "BtnCancel", "close": true },],
            cont: [{ title: "", cont: [
                        { type: "row", "h": "10px" },
                        { type: "text", "title": sText1, id: "text1" },
                        { type: "text", "title": "Str_TotalProgress" },
                        { type: "progressbar", id: "file_download_pb" },
                        { type: "text", "title": "", id: "speed_and_rest" },
                        { type: "text", "title": sText2, id: "text2", class: "load_text2" },
                    ] }]
        };
        let icon = "";
        if (sTitle.includes("Download")) {
            icon = "download";
        }
        else if (sTitle.includes("Upload")) {
            icon = "upload";
        }
        const { x, y } = oMenuRegister.GetFreeCoords((document.documentElement.clientWidth - 600) / 2, document.documentElement.clientHeight / 5, 40);
        const oFloatMenu = CreateFloatMenu(fm1FileDownload, { width: "600px", top: y + "px", left: x + "px" }, null, { bNoModal, icon, fToMinScreen: () => { this.ShortFopInfo(sTitle, this.fm, this.sPath); }, sRedCrossQst: GetLocaleText("Ask_OpInterrupt") });
        oFloatMenu.promise.then(() => { }).catch(() => { });
        this.fm = oFloatMenu.oMenu;
        if (this.fm) {
            this.SetDoms(document.getElementById("text1_" + this.fm.id), document.getElementById("text2_" + this.fm.id), document.getElementById("pb_row_" + this.fm.id), document.getElementById("speed_and_rest_" + this.fm.id), document.getElementById("file_download_pb_" + this.fm.id));
        }
    }
    async Confirm(sBtnName) {
        return new Promise((resolve, reject) => {
            if (!this.fm)
                throw null;
            const btnCancel = document.getElementById("BtnCancel_" + this.fm.id);
            if (!btnCancel || !btnCancel.parentElement)
                throw null;
            let btn = document.createElement("button");
            btn.innerHTML = GetLocaleText(sBtnName);
            btn.className = "nonselect flt_menu_btn_as_def";
            if (btnCancel.style.fontSize)
                btn.style.fontSize = btnCancel.style.fontSize;
            btn.addEventListener('click', () => {
                btn.remove();
                resolve();
            });
            btnCancel.parentElement.insertBefore(btn, btnCancel);
            const TmpCancelListener = () => {
                btnCancel.removeEventListener('click', TmpCancelListener);
                reject();
            };
            btnCancel.addEventListener('click', TmpCancelListener);
        });
    }
    fClear() {
        delete this.oDTP;
        delete this.oBranch;
        this.sProblemFiles = "";
        this.nStartTime = -1;
        this.nLastTime = -1;
        this.nFiltSpeed = -1;
    }
    SetDoms(domText, domText2, domPbRow, domSaR, oPB) {
        if (domText)
            this.text = domText;
        if (domText2)
            this.text2 = domText2;
        if (domPbRow)
            this.pb_row = domPbRow;
        if (domSaR)
            this.speedAndRest = domSaR;
        if (oPB) {
            this.domPb = oPB;
            this.pb = new CProgressBar(oPB.children[1].children[0], oPB.children[0], this, { accuracy: 1 });
        }
    }
    SetPbDysplay(s) {
        if (this.domPb)
            this.domPb.style.display = s;
    }
    TextInner(htmlText, bAdd) {
        if (this.text) {
            if (bAdd) {
                this.text.innerHTML += htmlText;
            }
            else {
                this.text.innerHTML = htmlText;
            }
        }
    }
    Text2Inner(htmlText, bAdd) {
        if (this.text2) {
            if (!htmlText) {
                this.text2.style.display = "none";
            }
            else if (bAdd) {
                this.text2.style.display = "";
                this.text2.innerHTML += htmlText;
            }
            else {
                this.text2.style.display = "";
                this.text2.innerHTML = htmlText;
            }
        }
    }
    Text2append(htmlEl) {
        if (this.text2)
            this.text2.append(htmlEl);
    }
    PbRowDisp(html) {
        if (this.pb_row)
            this.pb_row.innerHTML = html;
    }
    SpeedAndRestDisplay(sDisplay) {
        if (this.speedAndRest)
            this.speedAndRest.style.display = sDisplay;
    }
    SetPbSize(nSize) {
        if (this.pb)
            this.pb.nSize = nSize;
    }
    SetPbInner(nBufSize) {
        let ret = false;
        if (this.pb) {
            if (this.pb.DidDownloadStop()) {
                return false;
            }
            let percent = this.pb.UpdatePB(nBufSize);
            if (percent > 100) {
                percent = 100;
            }
            if (this.domShortPB && percent >= 0) {
                this.domShortPB.innerHTML = "";
                this.domShortPB.append(CreateShortPB(percent));
            }
            const nCurrTime = GetCurrTime();
            if (this.nStartTime > 0 && nCurrTime > this.nStartTime && this.speedAndRest) {
                this.nCurrSize += nBufSize;
                const nDeltaTime = nCurrTime - this.nLastTime;
                const nAllTime = nCurrTime - this.nStartTime;
                if (nDeltaTime > 1000 && nAllTime > 1000) {
                    ret = true;
                    this.nLastTime = nCurrTime;
                    const nDlAverageSpeed = (this.pb.nAlready / BigInt(Math.round(nAllTime / 1000))) + "";
                    const nDlCurrSpeed = (this.nCurrSize / nDeltaTime) * 1000;
                    this.nCurrSize = 0;
                    if (this.nFiltSpeed <= 0) {
                        this.nFiltSpeed = nDlCurrSpeed;
                    }
                    else {
                        this.nFiltSpeed += (nDlCurrSpeed - this.nFiltSpeed) / 10;
                    }
                    if (this.nFiltSpeed > 1) {
                        const oSpeed = ConvertBytes(nDlAverageSpeed, this.nFiltSpeed.toFixed(0));
                        const nRestTime = BigIntToNum(this.pb.nSize - this.pb.nAlready) / this.nFiltSpeed * 1000 + 1;
                        this.speedAndRest.innerHTML = GetLocaleText("Str_DlAverageSpeed") + " <b>" + oSpeed.nSpace1 + "</b> " + oSpeed.unit + "/sec.</br>"
                            + GetLocaleText("Str_DlSpeed") + " <b>" + oSpeed.nSpace2 + "</b> " + oSpeed.unit + "/sec.</br>"
                            + GetLocaleText("Str_TimeElapsed") + FormatTimeDifference(nAllTime, " h ", " m ", " sec. ") + "</br>"
                            + GetLocaleText("Str_DlRestTime") + FormatTimeDifference(nRestTime, " h ", " m ", " sec ");
                    }
                    this.speedAndRest.style.display = "";
                }
            }
        }
        return ret;
    }
    ShortFopInfo(sCommand, oConfirm, sPath) {
        const id = ged ? ged.GetExprolerWinId() : glob ? glob.GetExprolerWinId() : "";
        const domFileOpsPanel = document.getElementById("min_file_ops_" + id);
        if (domFileOpsPanel) {
            if (!this.domMinInfo) {
                this.domMinInfo = document.createElement("div");
                this.domMinInfo.className = "file_op_short_info flex_gor_center";
                this.domMinInfo.onclick = () => {
                    oConfirm.style.display = "";
                };
                const sCommInfo = (sCommand == "Str_DownloadFile" || sCommand == "Str_DownloadFolder") ? "Str_DownloadShortInfo" : "Str_UploadShortInfo";
                this.domMinInfo.innerHTML = GetLocaleText(sCommInfo, [sPath]);
                this.domShortPB = document.createElement("div");
                this.domShortPB.className = "fop_short_bg";
                this.domMinInfo.prepend(this.domShortPB);
                this.domFopMsg = document.createElement("div");
                this.domFopMsg.className = "fop_short_text";
                this.domMinInfo.append(this.domFopMsg);
                const imgStop = SetImg("stop", "1rem");
                if (imgStop) {
                    imgStop.onclick = () => {
                        CloseFloatMenu(oConfirm);
                        this.domMinInfo.remove();
                    };
                    imgStop.classList.add("fltmn_icon");
                    imgStop.classList.add("fop_short_cancel");
                    this.domMinInfo.append(imgStop);
                }
            }
            domFileOpsPanel.append(this.domMinInfo);
            oConfirm.style.display = "none";
            oConfirm.fOnClose = () => {
                if (this.domMinInfo)
                    this.domMinInfo.remove();
            };
        }
    }
}
const FS_HANDLE_LIFE_TIME = 90000;
class CFsHadle {
    constructor() {
        this.oFsHadle = {};
    }
    async get(oBranch, bRefrech) {
        this.delAllOld();
        if (!oBranch)
            return;
        const oData = oBranch.fGetData();
        if (!oData.fGetFsHandle)
            return;
        const sFsHandle = oData.fGetFsHandle(oBranch);
        if (this.oFsHadle[sFsHandle]) {
            if (this.oFsHadle[sFsHandle].branch === oBranch || GetCurrTime() - this.oFsHadle[sFsHandle].time > FS_HANDLE_LIFE_TIME) {
                this.oFsHadle[sFsHandle].time = GetCurrTime();
                return sFsHandle;
            }
            const sAcctKeyA = oData.fGetAccKey ? oData.fGetAccKey() : "";
            const conn = oData.oConn || oBranch.pParent.fGetData().oConn;
            if (!conn)
                return;
            const oParams = { folder_coords: { conn, sAcctKeyA } };
            if (oData.oBookmark && !oData.bIgnoreBookmark) {
                oParams.folder_coords.opts = oData.oBookmark.Opts;
                oParams.folder_coords.conn = CopyObject(conn);
                oParams.folder_coords.conn.sUrlA = oData.oBookmark.BmkKey || oData.oBookmark.sServerDirA;
            }
            try {
                const oFsData = await SendRecivePostApiWithRetry("ConnectFS", oParams);
                this.oFsHadle[oFsData.filesys_handle] = { time: GetCurrTime(), disconnect: true };
                return oFsData.filesys_handle;
            }
            catch (oErr) {
                throw oErr;
            }
        }
        this.oFsHadle[sFsHandle] = { time: GetCurrTime(), branch: oBranch };
        return sFsHandle;
    }
    async getNew(oBranch, bNoDisconnect) {
        let path, bm_path;
        if (!oBranch)
            return { fs_handle: "", path, bm_path };
        const oData = oBranch.fGetData();
        const oConn = CopyObject(oData.oConn || oBranch.pParent.fGetData().oConn);
        const folder_coords = { "conn": oConn, "sAcctKeyA": oData.fGetAccKey ? oData.fGetAccKey() : "" };
        let oBM = GetBM(oBranch);
        if (oBM) {
            bm_path = oBM.sServerDirA || oBM.BmkKey;
            oConn.sUrlA = oData.fGetUrl() + bm_path;
            folder_coords.opts = oBM.Opts;
            path = oData.fGetPathAndName(oBranch);
        }
        try {
            const fs_data = await SendRecivePostApiWithRetry("ConnectFS", { folder_coords });
            this.oFsHadle[fs_data.filesys_handle] = { time: GetCurrTime(), disconnect: !bNoDisconnect };
            return { fs_handle: fs_data.filesys_handle, path, bm_path, fs_data };
        }
        catch (oErr) {
            throw oErr;
        }
    }
    del(sFsHandle) {
        if (!sFsHandle || !this.oFsHadle[sFsHandle])
            return;
        if (this.oFsHadle[sFsHandle].disconnect) {
            DisconnectFsRequest(sFsHandle);
        }
        delete this.oFsHadle[sFsHandle];
    }
    delAllOld() {
        for (const key of Object.keys(this.oFsHadle)) {
            const nCurrTime = GetCurrTime();
            if (nCurrTime - this.oFsHadle[key].time > FS_HANDLE_LIFE_TIME) {
                if (this.oFsHadle[key].disconnect) {
                    DisconnectFsRequest(key);
                }
                delete this.oFsHadle[key];
            }
        }
    }
}
const oFsHandle = new CFsHadle;
class CUpOrDownData {
    constructor() {
        this.oDTP = null;
        this.oBranch = null;
    }
    fClear() {
        this.oDTP = null;
        this.oBranch = null;
    }
}
const oUpOrDownData = new CUpOrDownData;
class CUpload {
    constructor(oDTP, oBranch, oSP) {
        this.root = { cont: [] };
        this.nFullSize = BigInt(0);
        this.nFilesNumb = 0;
        this.nPreferredBufSize = 1024;
        this.sFsHandle = "";
        this.sBasePath = "";
        this.DTP = oDTP;
        this.branch = oBranch;
        this.oShowProcess = oSP;
        const oData = oBranch.fGetData();
        this.oShowProcess.sPath = oData.fGetUrl() + oData.fGetPathAndName(oBranch);
    }
    async processDrop(dataTransfer) {
        const items = dataTransfer.items;
        if (!items || items.length === 0)
            return;
        this.nFullSize = BigInt(0);
        this.nFilesNumb = 0;
        this.root = { cont: [] };
        let hasFolder = false;
        for (let i = 0; i < items.length; i++) {
            if (items[i].kind === 'file') {
                const entry = items[i].webkitGetAsEntry?.() || null;
                if (entry?.isDirectory) {
                    hasFolder = true;
                    break;
                }
            }
        }
        if (hasFolder) {
            await this.processDropWithFolders(items);
        }
        else {
            await this.processDropFilesOnly(items);
        }
        await this.StreamReadAndUpload(this.root.cont, "Cmd_Upload");
    }
    async processDropFilesOnly(items) {
        for (let i = 0; i < items.length; i++) {
            const item = items[i];
            if (item.kind === 'file') {
                const file = item.getAsFile();
                if (file) {
                    const fileWithPath = file;
                    if (!fileWithPath.webkitRelativePath) {
                        Object.defineProperty(fileWithPath, 'webkitRelativePath', {
                            value: file.name,
                            writable: false
                        });
                    }
                    this.root.cont.push({ file: fileWithPath });
                    this.nFullSize += BigInt(file.size);
                    this.nFilesNumb++;
                }
            }
        }
    }
    async processDropWithFolders(items) {
        const entries = [];
        for (let i = 0; i < items.length; i++) {
            const item = items[i];
            if (item.kind === 'file') {
                const entry = item.webkitGetAsEntry?.() || null;
                if (entry) {
                    entries.push({ entry, path: '' });
                }
                else {
                    const file = item.getAsFile();
                    if (file) {
                        const fileWithPath = file;
                        if (!fileWithPath.webkitRelativePath) {
                            Object.defineProperty(fileWithPath, 'webkitRelativePath', {
                                value: file.name,
                                writable: false
                            });
                        }
                        this.root.cont.push({ file: fileWithPath });
                        this.nFullSize += BigInt(file.size);
                        this.nFilesNumb++;
                    }
                }
            }
        }
        if (entries.length > 0) {
            await this.processDroppedEntries(entries);
        }
    }
    async processDroppedEntries(entries, parentFolder) {
        for (const { entry, path } of entries) {
            const fullPath = path ? `${path}/${entry.name}` : entry.name;
            if (entry.isDirectory) {
                const folder = {
                    folder: fullPath,
                    cont: []
                };
                if (parentFolder) {
                    parentFolder.cont.push(folder);
                }
                else {
                    this.root.cont.push(folder);
                    if (!this.root.folder && path === '') {
                        this.root.folder = entry.name;
                    }
                }
                const dirReader = entry.createReader();
                const childEntries = await this.readAllDirectoryEntries(dirReader);
                const childEntriesWithPath = childEntries.map(childEntry => ({
                    entry: childEntry,
                    path: fullPath
                }));
                await this.processDroppedEntries(childEntriesWithPath, folder);
            }
            else if (entry.isFile) {
                const file = await this.getFileFromEntry(entry);
                const fileWithPath = file;
                Object.defineProperty(fileWithPath, 'webkitRelativePath', {
                    value: fullPath,
                    writable: false
                });
                if (parentFolder) {
                    parentFolder.cont.push({ file: fileWithPath });
                }
                else {
                    this.root.cont.push({ file: fileWithPath });
                }
                this.nFullSize += BigInt(file.size);
                this.nFilesNumb++;
            }
        }
    }
    readAllDirectoryEntries(dirReader) {
        return new Promise((resolve, reject) => {
            const allEntries = [];
            const readBatch = () => {
                dirReader.readEntries((entries) => {
                    if (entries.length === 0) {
                        resolve(allEntries);
                    }
                    else {
                        allEntries.push(...entries);
                        readBatch();
                    }
                }, reject);
            };
            readBatch();
        });
    }
    getFileFromEntry(fileEntry) {
        return new Promise((resolve, reject) => {
            fileEntry.file(resolve, reject);
        });
    }
    async pickFilesUniversal(bMultiple) {
        if (BrowserFeatures.hasFileSystemAPI()) {
            try {
                const fileHandles = await window.showOpenFilePicker({
                    multiple: bMultiple,
                    types: [{ description: 'All Files', accept: { '*/*': [] } }],
                });
                const files = await Promise.all(fileHandles.map(async (handle) => {
                    const file = await handle.getFile();
                    Object.defineProperty(file, 'webkitRelativePath', {
                        value: file.name,
                        writable: false
                    });
                    return file;
                }));
                return files;
            }
            catch (oErr) {
                throw oErr;
            }
        }
        else {
            return new Promise((resolve, reject) => {
                const input = document.createElement('input');
                input.type = 'file';
                input.multiple = bMultiple;
                input.style.display = 'none';
                const cleanup = () => {
                    input.remove();
                };
                input.onchange = () => {
                    const files = Array.from(input.files || []).map(file => {
                        if (!file.webkitRelativePath) {
                            Object.defineProperty(file, 'webkitRelativePath', {
                                value: file.name,
                                writable: false
                            });
                        }
                        return file;
                    });
                    cleanup();
                    if (files.length === 0) {
                        reject('canceled');
                    }
                    else {
                        resolve(files);
                    }
                };
                input.oncancel = () => {
                    cleanup();
                    reject('canceled');
                };
                document.body.appendChild(input);
                input.click();
            });
        }
    }
    async pickFolderUniversal() {
        if (BrowserFeatures.hasDirectoryPicker()) {
            try {
                const folderHandle = await window.showDirectoryPicker();
                const files = await this.processDirectoryHandle(folderHandle, folderHandle.name);
                return { files, folderName: folderHandle.name };
            }
            catch (oErr) {
                throw oErr;
            }
        }
        else if (BrowserFeatures.hasWebkitDirectory()) {
            return new Promise((resolve, reject) => {
                const input = document.createElement('input');
                input.type = 'file';
                input.webkitdirectory = true;
                input.multiple = true;
                input.style.display = 'none';
                const cleanup = () => {
                    input.remove();
                };
                input.onchange = () => {
                    const files = Array.from(input.files || []);
                    if (files.length === 0) {
                        cleanup();
                        reject('canceled');
                        return;
                    }
                    const firstPath = files[0].webkitRelativePath || files[0].name;
                    const folderName = firstPath.split('/')[0] || 'Upload';
                    cleanup();
                    resolve({ files, folderName });
                };
                input.oncancel = () => {
                    cleanup();
                    reject('canceled');
                };
                document.body.appendChild(input);
                input.click();
            });
        }
        else {
            throw new Error('Folder upload is not supported in this browser');
        }
    }
    async processDirectoryHandle(dirHandle, currentPath) {
        const files = [];
        const entries = dirHandle.values();
        for await (const entry of entries) {
            const fullPath = currentPath ? `${currentPath}/${entry.name}` : entry.name;
            if (entry.kind === 'file') {
                const file = await entry.getFile();
                Object.defineProperty(file, 'webkitRelativePath', {
                    value: fullPath,
                    writable: false
                });
                files.push(file);
            }
            else if (entry.kind === 'directory') {
                const subFiles = await this.processDirectoryHandle(entry, fullPath);
                files.push(...subFiles);
            }
        }
        return files;
    }
    async PickFiles() {
        try {
            const files = await this.pickFilesUniversal(true);
            this.nFullSize = BigInt(0);
            this.nFilesNumb = 0;
            this.root.cont = [];
            for (const file of files) {
                this.root.cont.push({ file });
                this.nFullSize += BigInt(file.size);
                this.nFilesNumb++;
            }
        }
        catch (oErr) {
            if (oErr !== 'canceled') {
                CatchErrProcess(oErr);
            }
        }
    }
    async PickFolder() {
        try {
            const result = await this.pickFolderUniversal();
            this.root.folder = result.folderName;
            this.nFullSize = BigInt(0);
            this.nFilesNumb = 0;
            this.root.cont = [];
            const folderMap = new Map();
            for (const file of result.files) {
                const pathParts = file.webkitRelativePath.split('/');
                let currentPath = '';
                for (let i = 0; i < pathParts.length - 1; i++) {
                    const parentPath = currentPath;
                    currentPath = currentPath ? `${currentPath}/${pathParts[i]}` : pathParts[i];
                    if (!folderMap.has(currentPath)) {
                        const newFolder = {
                            folder: currentPath,
                            cont: []
                        };
                        folderMap.set(currentPath, newFolder);
                        if (parentPath) {
                            const parent = folderMap.get(parentPath);
                            if (parent?.cont) {
                                parent.cont.push(newFolder);
                            }
                        }
                        else {
                            this.root.cont.push(newFolder);
                        }
                    }
                }
                const parentPath = pathParts.slice(0, -1).join('/');
                const parent = parentPath ? folderMap.get(parentPath) : this.root;
                if (parent?.cont) {
                    parent.cont.push({ file });
                }
                else {
                    this.root.cont.push({ file });
                }
                this.nFullSize += BigInt(file.size);
                this.nFilesNumb++;
            }
        }
        catch (oErr) {
            if (oErr !== 'canceled') {
                CatchErrProcess(oErr);
            }
        }
    }
    async ReadChunk(file, start, end) {
        const blob = file.slice(start, end);
        const arrayBuffer = await blob.arrayBuffer();
        return new Uint8Array(arrayBuffer);
    }
    async UploadFolderOrFiles(oFoldStruct) {
        let nFile = 0;
        for (const item of oFoldStruct) {
            if (this.oShowProcess.fm.bSelfDeleted) {
                throw "canceled by user";
            }
            if (item.folder) {
                try {
                    await SendRecivePostApiWithRetry("MakeFolder", { "filesys_handle": this.sFsHandle, "path": this.sBasePath + "/" + item.folder });
                }
                catch { }
                await this.UploadFolderOrFiles(item.cont);
            }
            else if (item.file) {
                nFile++;
                if (this.oShowProcess.domFopMsg) {
                    this.oShowProcess.domFopMsg.innerHTML = GetLocaleText("Str_ShortCurrFileInfo", [item.file.webkitRelativePath, "" + nFile, "" + this.nFilesNumb, GetSizeAndUnit(item.file.size, true)]);
                }
                const oParams = {
                    "filesys_handle": this.sFsHandle,
                    "path": this.sBasePath + "/" + item.file.webkitRelativePath,
                    "file_info": { "size": item.file.size + "", "sNameA": this.sBasePath + "/" + item.file.webkitRelativePath }
                };
                try {
                    const oAns = await SendRecivePostApiWithRetry("OpenUpload", oParams);
                    let start = 0;
                    while (start < item.file.size) {
                        if (this.oShowProcess.fm.bSelfDeleted)
                            throw "canceled by user";
                        const end = Math.min(start + oAns.preferred_buf_size, item.file.size);
                        const chunk = await this.ReadChunk(item.file, start, end);
                        const buf = encodeBase64(Array.from(chunk));
                        await SendRecivePostApiWithRetry("UploadBuf", { "filesys_handle": this.sFsHandle, "buf_size": chunk.length, buf });
                        start = end;
                        this.oShowProcess.SetPbInner(chunk.length);
                        this.oShowProcess.Text2Inner(GetLocaleText("Str_CurrFile", ["" + nFile, "" + this.nFilesNumb, GetSizeAndUnit(item.file.size, true)]));
                        const percent = ((item.file.size > 0) ? (end * 100 / item.file.size).toFixed(1) : "100") + "%";
                        const pbConteiner = document.createElement('div');
                        pbConteiner.classList.add("load_current_pb_cont");
                        CreateSlimProgressBar(pbConteiner, "", percent);
                        this.oShowProcess.Text2append(pbConteiner);
                        this.oShowProcess.Text2Inner(item.file.webkitRelativePath, true);
                    }
                }
                catch (catchErr) {
                    if (catchErr == "canceled by user") {
                        throw "canceled by user";
                    }
                    else if (catchErr && catchErr.error && catchErr.error.message == "Failed to fetch") {
                        throw catchErr;
                    }
                    const sPathAndName = this.sBasePath + "/" + item.file.webkitRelativePath;
                    if (catchErr.message) {
                        ErrorMsgShow(sPathAndName + " download:" + catchErr.message, { sErrType: "Folders download", eGoal: "console", bNoCurrJobName: true });
                    }
                    else if (catchErr.error && catchErr.error.message) {
                        ErrorMsgShow(sPathAndName + " download:" + catchErr.error.message, { sErrType: "Folders download", eGoal: "console", bNoCurrJobName: true });
                    }
                    this.oShowProcess.sProblemFiles += "<br/>" + sPathAndName;
                }
                try {
                    await SendRecivePostApiWithRetry("CloseUpload", { "filesys_handle": this.sFsHandle, "commit": true });
                }
                catch { }
            }
            else {
                await this.UploadFolderOrFiles(item.cont);
            }
        }
    }
    async StreamReadAndUpload(oFoldStruct, sConfirmBtn) {
        const oData = this.branch.fGetData();
        const { fs_handle, path, bm_path } = await oFsHandle.getNew(this.branch);
        this.sFsHandle = fs_handle;
        this.sBasePath = path === undefined ? oData.fGetPathAndName(this.branch, true) : path;
        console.log(`Full size for upload: ${this.nFullSize}`);
        this.oShowProcess.nStartTime = GetCurrTime();
        this.oShowProcess.nLastTime = this.oShowProcess.nStartTime;
        this.oShowProcess.SetPbSize(this.nFullSize);
        let sText1 = GetSizeAndUnit(this.nFullSize, true) + " (" + GetLocalNumber(this.nFullSize) + " bytes)";
        if (this.root.folder) {
            sText1 = this.root.folder + ", " + sText1;
        }
        else if (this.root.cont) {
            sText1 = this.root.cont.length + " files, total size " + sText1;
        }
        if (bm_path) {
            this.oShowProcess.sPath = oData.fGetUrl() + bm_path + path;
        }
        sText1 = GetLocaleText("Str_UploadShortInfo", [this.oShowProcess.sPath]) + "<br>" + sText1;
        this.oShowProcess.TextInner(sText1);
        if (sConfirmBtn) {
            this.oShowProcess.SetPbDysplay("none");
            this.oShowProcess.Text2Inner(GetLocaleText("Ask_AreUsure"));
            await this.oShowProcess.Confirm(sConfirmBtn);
            this.oShowProcess.SetPbDysplay("");
        }
        this.oShowProcess.Text2Inner("");
        if (this.oShowProcess.fm && this.oShowProcess.fm.fToMinScreen) {
            this.oShowProcess.fm.fToMinScreen();
        }
        try {
            await this.UploadFolderOrFiles(oFoldStruct);
        }
        catch (oErr) {
            throw oErr;
        }
        finally {
            RefreshBrowseBranch("", { Branch: this.branch, DTP: this.DTP });
            this.branch.fMarkAndShow(this.DTP);
        }
        if (this.oShowProcess.sProblemFiles) {
            ErrorMsgShow(GetLocaleText("Err_ProblemWithFiles") + this.oShowProcess.sProblemFiles, { sTitle: "Upload item(s)", eGoal: "msgbox", bNoCurrJobName: true });
        }
    }
}
class CDownload {
    constructor(sFSH, oDLC) {
        this.nFiles = 0;
        this.nFolders = 0;
        this.nSize = BigInt(0);
        this.root = { sName: "", cont: [] };
        this.nCurrFile = 0;
        this.sFsHandle = sFSH;
        this.oShowProcess = oDLC;
    }
    async Download1File(sPath, sFileName) {
        const oFileOpenData = await SendRecivePostApiWithRetry("OpenDownload", { "filesys_handle": this.sFsHandle, "path": sPath + "/" + sFileName });
        bStopNewsPolling = true;
        let writableStream;
        let chunks = [];
        let isFirefoxFallback = false;
        if (BrowserFeatures.hasSaveFilePicker()) {
            const fileHandle = await window.showSaveFilePicker({ suggestedName: this.root.sName });
            writableStream = await fileHandle.createWritable();
        }
        else {
            isFirefoxFallback = true;
            writableStream = {
                write: async (blob) => {
                    const arrayBuffer = await blob.arrayBuffer();
                    chunks.push(new Uint8Array(arrayBuffer));
                },
                close: async () => {
                    const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
                    const result = new Uint8Array(totalLength);
                    let offset = 0;
                    for (const chunk of chunks) {
                        result.set(chunk, offset);
                        offset += chunk.length;
                    }
                    const blob = new Blob([result]);
                    const url = URL.createObjectURL(blob);
                    const a = document.createElement('a');
                    a.href = url;
                    a.download = this.root.sName;
                    document.body.appendChild(a);
                    a.click();
                    document.body.removeChild(a);
                    setTimeout(() => URL.revokeObjectURL(url), 1000);
                }
            };
        }
        let nPrefSize = Number(oFileOpenData.preferred_buf_size);
        if (isNaN(nPrefSize) || !nPrefSize) {
            nPrefSize = 0x400000;
        }
        const nSize = BigInt(oFileOpenData.info.size);
        this.oShowProcess.SetPbSize(nSize);
        this.oShowProcess.TextInner(", " + GetSizeAndUnit(nSize, true), true);
        this.oShowProcess.nStartTime = GetCurrTime();
        if (this.oShowProcess.fm && this.oShowProcess.fm.fToMinScreen) {
            this.oShowProcess.fm.fToMinScreen();
            if (this.oShowProcess.domFopMsg) {
                this.oShowProcess.domFopMsg.innerHTML = sFileName + GetSizeAndUnit(oFileOpenData.info.size, true);
            }
        }
        for (;;) {
            if (this.oShowProcess.fm.bSelfDeleted)
                throw "canceled by user";
            const sBuffContents = await SendRecivePostApiWithRetry("DownloadBuf", { "filesys_handle": this.sFsHandle, "size": nPrefSize });
            if (!sBuffContents || sBuffContents.buf_size === 0)
                break;
            await writableStream.write(new Blob([new Uint8Array(decodeBase64(sBuffContents.buf))]));
            this.oShowProcess.SetPbInner(sBuffContents.buf_size);
        }
        await writableStream.close();
        console.log("============================================================");
        console.log(`File "${this.root.sName}" downloaded successfully.`);
        await SendRecivePostApiWithRetry("CloseDownload", { "filesys_handle": this.sFsHandle, "commit": true });
    }
    async GetFolderStructAndSize(sPathAndName, sub, oBr) {
        try {
            if (oBr && oBr.cont && oBr.cont.length > 0 && !oBr.oIsWaiting && !oBr.bError) {
                for (const it of oBr.cont) {
                    if (this.oShowProcess.fm.bSelfDeleted) {
                        throw "canceled by user";
                    }
                    if (it.cont) {
                        this.nFolders++;
                        const oFolder = { sName: it.pathEl, cont: [], oBranch: it };
                        sub.push(oFolder);
                    }
                    else {
                        const oData = it.fGetData();
                        sub.push(oData.sName);
                        this.nFiles++;
                        this.nSize += BigInt(oData.size || EQUAL_SIZE_EMPTY_FOLDER);
                    }
                }
            }
            else {
                const oParams = { "filesys_handle": this.sFsHandle, "path": sPathAndName, "max_items": LIST_DIR_MAX_ITEM };
                const oListDir = await SendRecivePostApiWithRetry("ListDir", oParams, { domMenu: this.oShowProcess.fm, oMultiPageArrs: { items: [] } });
                const oFolderData = SetBrowsTreeFolders(oListDir.items, sPathAndName, oBr, []);
                oBr.fAddDataArr(oFolderData.aData, { oFunc: oFolderData.aFunc, fDataProcessor: ProcessFolderBranchForTable, "sPathFieldName": "sName" });
                for (const it of oListDir.items) {
                    if (this.oShowProcess.fm.bSelfDeleted) {
                        throw "canceled by user";
                    }
                    this.oShowProcess.SpeedAndRestDisplay(sPathAndName + "/" + it.sNameA);
                    if (it.bIsFolder) {
                        this.nFolders++;
                        const oFolder = { sName: it.sNameA, cont: [], oBranch: oBr.fFindEl(it.sNameA, "sName") };
                        sub.push(oFolder);
                    }
                    else {
                        sub.push(it.sNameA);
                        this.nFiles++;
                        this.nSize += BigInt(it.size || EQUAL_SIZE_EMPTY_FOLDER);
                    }
                }
            }
            for (const it of sub) {
                if (this.oShowProcess.fm.bSelfDeleted) {
                    throw "canceled by user";
                }
                if (typeof it != 'string') {
                    await this.GetFolderStructAndSize(sPathAndName + "/" + it.sName, it.cont, it.oBranch);
                }
            }
        }
        catch (catchErr) {
            throw catchErr;
        }
    }
    async DownloadFiles(curr, sPath, dirHandle) {
        const isFirefoxFallback = !BrowserFeatures.hasFileSystemAPI() || !dirHandle?.getDirectoryHandle;
        for (const it of curr.cont) {
            if (this.oShowProcess.fm.bSelfDeleted) {
                throw "canceled by user";
            }
            if (typeof it == 'string') {
                const sIt = it.startsWith("\/") ? it.slice(1) : it;
                try {
                    if (isFirefoxFallback) {
                        await this.DownloadSingleFileFirefox(sPath, sIt);
                    }
                    else {
                        await this.CopyFileFromGsToDisk(dirHandle, sPath, sIt);
                    }
                }
                catch (catchErr) {
                    if (catchErr == "canceled by user") {
                        throw "canceled by user";
                    }
                    else if (catchErr && catchErr.error && catchErr.error.message == "Failed to fetch") {
                        throw catchErr;
                    }
                    const sPathAndName = sPath + "/" + sIt;
                    if (catchErr.message) {
                        ErrorMsgShow(sPathAndName + " download:" + catchErr.message, { sErrType: "Folders download", eGoal: "console", bNoCurrJobName: true });
                    }
                    else if (catchErr.error && catchErr.error.message) {
                        ErrorMsgShow(sPathAndName + " download:" + catchErr.error.message, { sErrType: "Folders download", eGoal: "console", bNoCurrJobName: true });
                    }
                    this.oShowProcess.sProblemFiles += "<br/>" + sPathAndName;
                    continue;
                }
            }
            else {
                const sPathAndName = sPath + "/" + it.sName;
                try {
                    let subDirHandle;
                    if (isFirefoxFallback) {
                        subDirHandle = { name: it.sName, isFirefoxFallback: true };
                    }
                    else {
                        subDirHandle = await dirHandle.getDirectoryHandle(it.sName, { create: true });
                    }
                    await this.DownloadFiles(it, sPathAndName, subDirHandle);
                }
                catch (catchErr) {
                    if (catchErr == "canceled by user") {
                        throw "canceled by user";
                    }
                    else if (catchErr && catchErr.error && catchErr.error.message == "Failed to fetch") {
                        throw catchErr;
                    }
                    if (catchErr.message) {
                        ErrorMsgShow(sPathAndName + " download:" + catchErr.message, { sErrType: "Folders download", eGoal: "console", bNoCurrJobName: true });
                    }
                    else if (catchErr.error && catchErr.error.message) {
                        ErrorMsgShow(sPathAndName + " download:" + catchErr.error.message, { sErrType: "Folders download", eGoal: "console", bNoCurrJobName: true });
                    }
                    this.oShowProcess.sProblemFiles += "<br/>" + sPathAndName;
                    continue;
                }
            }
        }
    }
    async DownloadSingleFileFirefox(sFilePath, sFileName) {
        try {
            const oParams = { "filesys_handle": this.sFsHandle, "path": sFilePath + "/" + sFileName };
            const oFileOpenData = await SendRecivePostApiWithRetry("OpenDownload", oParams);
            this.sFsHandle = oParams.filesys_handle;
            if (!oFileOpenData)
                return null;
            let nPrefSize = Number(oFileOpenData.preferred_buf_size);
            if (isNaN(nPrefSize) || !nPrefSize) {
                nPrefSize = 0x400000;
            }
            const chunks = [];
            let nAlreadyDownload = 0;
            this.nCurrFile++;
            this.oShowProcess.Text2Inner(GetLocaleText("Str_CurrFile", ["" + this.nCurrFile, "" + this.nFiles, GetSizeAndUnit(oFileOpenData.info.size, true)]));
            if (this.oShowProcess.domFopMsg) {
                this.oShowProcess.domFopMsg.innerHTML = GetLocaleText("Str_ShortCurrFileInfo", [sFileName, "" + this.nCurrFile, "" + this.nFiles, GetSizeAndUnit(oFileOpenData.info.size, true)]);
            }
            const nTotalSize = Number(oFileOpenData.info.size);
            for (;;) {
                if (this.oShowProcess.fm.bSelfDeleted)
                    throw "canceled by user";
                const sBuffContents = await SendRecivePostApiWithRetry("DownloadBuf", { "filesys_handle": this.sFsHandle, "size": nPrefSize });
                if (!sBuffContents || sBuffContents.buf_size === 0)
                    break;
                chunks.push(new Uint8Array(decodeBase64(sBuffContents.buf)));
                const bWasCurrInfo = this.oShowProcess.SetPbInner(sBuffContents.buf_size);
                if (nTotalSize) {
                    nAlreadyDownload += sBuffContents.buf_size;
                    if (bWasCurrInfo) {
                        this.oShowProcess.Text2Inner(GetLocaleText("Str_CurrFile", ["" + this.nCurrFile, "" + this.nFiles, GetSizeAndUnit(oFileOpenData.info.size, true)]));
                        const percent = (nAlreadyDownload * 100 / nTotalSize).toFixed(1) + "%";
                        const pbConteiner = document.createElement('div');
                        pbConteiner.classList.add("load_current_pb_cont");
                        CreateSlimProgressBar(pbConteiner, "", percent);
                        this.oShowProcess.Text2append(pbConteiner);
                        this.oShowProcess.Text2Inner(sFileName, true);
                    }
                }
            }
            const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
            const result = new Uint8Array(totalLength);
            let offset = 0;
            for (const chunk of chunks) {
                result.set(chunk, offset);
                offset += chunk.length;
            }
            const blob = new Blob([result]);
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = sFileName;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            setTimeout(() => URL.revokeObjectURL(url), 1000);
            try {
                await SendRecivePostApiWithRetry("CloseDownload", { "filesys_handle": this.sFsHandle, "commit": true });
            }
            catch { }
        }
        catch (oErr) {
            throw oErr;
        }
    }
    async CopyFileFromGsToDisk(dirHandle, sFilePath, sFileNname) {
        try {
            const oParams = { "filesys_handle": this.sFsHandle, "path": sFilePath + "/" + sFileNname };
            const oFileOpenData = await SendRecivePostApiWithRetry("OpenDownload", oParams);
            this.sFsHandle = oParams.filesys_handle;
            if (!oFileOpenData)
                return null;
            const fileHandle = await dirHandle.getFileHandle(GetFileNameOfPath(sFileNname), { create: true });
            const writableStream = await fileHandle.createWritable();
            let nPrefSize = Number(oFileOpenData.preferred_buf_size);
            if (isNaN(nPrefSize) || !nPrefSize) {
                nPrefSize = 0x400000;
            }
            let nAlreadeDownload = 0;
            this.nCurrFile++;
            this.oShowProcess.Text2Inner(GetLocaleText("Str_CurrFile", ["" + this.nCurrFile, "" + this.nFiles, GetSizeAndUnit(oFileOpenData.info.size, true)]));
            if (this.oShowProcess.domFopMsg) {
                this.oShowProcess.domFopMsg.innerHTML = GetLocaleText("Str_ShortCurrFileInfo", [sFileNname, "" + this.nCurrFile, "" + this.nFiles, GetSizeAndUnit(oFileOpenData.info.size, true)]);
            }
            const nTotalSize = Number(oFileOpenData.info.size);
            for (;;) {
                if (this.oShowProcess.fm.bSelfDeleted)
                    throw "canceled by user";
                const sBuffContents = await SendRecivePostApiWithRetry("DownloadBuf", { "filesys_handle": this.sFsHandle, "size": nPrefSize });
                if (!sBuffContents || sBuffContents.buf_size === 0)
                    break;
                await writableStream.write(new Blob([new Uint8Array(decodeBase64(sBuffContents.buf))]));
                const bWasCurrInfo = this.oShowProcess.SetPbInner(sBuffContents.buf_size);
                if (nTotalSize) {
                    nAlreadeDownload += sBuffContents.buf_size;
                    if (bWasCurrInfo) {
                        this.oShowProcess.Text2Inner(GetLocaleText("Str_CurrFile", ["" + this.nCurrFile, "" + this.nFiles, GetSizeAndUnit(oFileOpenData.info.size, true)]));
                        const percent = (nAlreadeDownload * 100 / nTotalSize).toFixed(1) + "%";
                        const pbConteiner = document.createElement('div');
                        pbConteiner.classList.add("load_current_pb_cont");
                        CreateSlimProgressBar(pbConteiner, "", percent);
                        this.oShowProcess.Text2append(pbConteiner);
                        this.oShowProcess.Text2Inner(sFileNname, true);
                    }
                }
            }
            await writableStream.close();
            try {
                await SendRecivePostApiWithRetry("CloseDownload", { "filesys_handle": this.sFsHandle, "commit": true });
            }
            catch { }
        }
        catch (oErr) {
            throw oErr;
        }
    }
    async GetSummStructAndSize(oBr) {
        const oData = oBr.fGetData();
        const sPath = oData.fGetPathAndName(oBr);
        if (oData.bIsFile) {
            this.root.cont.push(oData.sName);
            this.nFiles++;
            this.nSize += BigInt(oData.size || 0);
        }
        else {
            this.oShowProcess.TextInner("Measurement of <b>" + sPath + "</b> folder size");
            this.root.cont.push({ sName: oData.sName, cont: [] });
            await this.GetFolderStructAndSize(sPath, this.root.cont[this.root.cont.length - 1].cont, oBr);
            const oFolderSize = ConvertBytes("" + this.nSize);
            this.oShowProcess.TextInner("Download from " + oData.fGetUrl() + sPath.slice(0, -oData.sName.length));
            this.oShowProcess.SpeedAndRestDisplay("");
            this.oShowProcess.SetPbSize(this.nSize);
        }
    }
}
async function StreamUploadFiles() {
    if (!oUpOrDownData.oBranch || !oUpOrDownData.oDTP)
        return;
    const oShowProcess = new CShowFileOperation("Title_UploadFiles", "", "<span class='waiting_box'></span>");
    oShowProcess.SpeedAndRestDisplay("none");
    let oBr = oUpOrDownData.oBranch;
    let oDTP = oUpOrDownData.oDTP;
    if (oDTP.oParentBr && oDTP.oParentDTP) {
        const sName = oBr.fGetData().display_name;
        if (!sName)
            return;
        oBr = oDTP.oParentBr.fFindEl(sName, "display_name");
        if (!oBr)
            return;
        oDTP = oDTP.oParentDTP;
    }
    oUpOrDownData.fClear();
    const oFop = new CUpload(oDTP, oBr, oShowProcess);
    bStopNewsPolling = true;
    try {
        await oFop.PickFiles();
        await oFop.StreamReadAndUpload(oFop.root.cont);
    }
    catch (oErr) {
        if (oErr.name == "AbortError") {
            ErrorMsgShow(oErr.message, { sErrType: "Files upoad", eGoal: "console", bNoCurrJobName: true });
        }
        else if (oErr == "canceled by user") {
            ErrorMsgShow(oErr, { sErrType: "Files upoad", eGoal: "console", bNoCurrJobName: true });
        }
        else {
            CatchErrProcess(oErr, "Files upoad", { eGoal: "both" });
        }
    }
    oFsHandle.del(oFop.sFsHandle);
    bStopNewsPolling = false;
    if (oShowProcess.fm) {
        oShowProcess.fm.fCloseMenu();
    }
}
async function StreamUploadFolder() {
    if (!oUpOrDownData.oBranch || !oUpOrDownData.oDTP)
        return;
    const oShowProcess = new CShowFileOperation("Title_UploadFolder", "", "<span class='waiting_box'></span>");
    oShowProcess.SpeedAndRestDisplay("none");
    let oBr = oUpOrDownData.oBranch;
    let oDTP = oUpOrDownData.oDTP;
    if (oDTP.oParentBr && oDTP.oParentDTP) {
        const sName = oBr.fGetData().display_name;
        if (!sName)
            return;
        oBr = oDTP.oParentBr.fFindEl(sName, "display_name");
        if (!oBr)
            return;
        oDTP = oDTP.oParentDTP;
    }
    oUpOrDownData.fClear();
    const oFop = new CUpload(oDTP, oBr, oShowProcess);
    bStopNewsPolling = true;
    try {
        await oFop.PickFolder();
        await oFop.StreamReadAndUpload([oFop.root]);
    }
    catch (oErr) {
        if (oErr.name == "AbortError") {
            ErrorMsgShow(oErr.message, { sErrType: "Folder upoad", eGoal: "console", bNoCurrJobName: true });
        }
        else if (oErr == "canceled by user") {
            ErrorMsgShow(oErr, { sErrType: "Folder upoad", eGoal: "console", bNoCurrJobName: true });
        }
        else {
            CatchErrProcess(oErr, "Folder upoad", { eGoal: "both" });
        }
    }
    oFsHandle.del(oFop.sFsHandle);
    bStopNewsPolling = false;
    if (oShowProcess.fm) {
        oShowProcess.fm.fCloseMenu();
    }
}
function GetWaitingBox(sTitle, sText1, sText2, oShowProcess, bNoModal, bNoClose) {
    let fm1FileDownload = {
        "title": sTitle,
        bottom_box: [{ title: "Btn_Cancel", id: "BtnCancel", "close": true },],
        cont: [
            {
                title: "", cont: [
                    { type: "row", "h": "10px" },
                    { type: "text", "title": sText1, id: "text1" },
                    { type: "progressbar", id: "file_download_pb" },
                    { type: "text", "title": "", id: "speed_and_rest" },
                    { type: "text", "title": sText2, id: "text2", class: "flex_gor" },
                ]
            }
        ]
    };
    const ret = CreateFloatMenu(fm1FileDownload, { width: "600px", top: "30%" }, null, { bNoModal, bNoClose });
    oShowProcess.SetDoms(document.getElementById("text1_" + ret.oMenu.id), document.getElementById("text2_" + ret.oMenu.id), document.getElementById("pb_row_" + ret.oMenu.id), document.getElementById("speed_and_rest_" + ret.oMenu.id), document.getElementById("file_download_pb_" + ret.oMenu.id));
    ret.promise.then(() => { }).catch(() => { });
    return ret;
}
async function StreamDownloadFile() {
    if (!oUpOrDownData.oDTP || !oUpOrDownData.oBranch)
        return;
    if (oUpOrDownData.oDTP.fGetSelTabLen() > 1) {
        StreamDownloadFolder();
        return;
    }
    let oBr = oUpOrDownData.oBranch;
    let oData = oBr.fGetData();
    let oParentBr = oUpOrDownData.oBranch.pParent;
    if (oUpOrDownData.oDTP.oParentBr) {
        const sName = oData.display_name;
        if (!sName)
            return;
        oBr = oParentBr.fFindEl(sName, "display_name");
        if (!oBr)
            return;
        oData = oBr.fGetData();
        oParentBr = oUpOrDownData.oDTP.oParentBr;
    }
    oUpOrDownData.fClear();
    const oParentData = oParentBr.fGetData();
    const sParentPath = oParentData.fGetPathAndName(oParentBr, true);
    const oShowProcess = new CShowFileOperation("Str_DownloadFile", "", "<span class='waiting_box'></span>");
    let oDownload;
    try {
        const { fs_handle, path, bm_path } = await oFsHandle.getNew(oParentBr);
        oDownload = new CDownload(fs_handle, oShowProcess);
        oDownload.root.sName = oData.sName;
        oShowProcess.TextInner("From " + sParentPath + "<br> file <b>" + oData.sName + "</b>");
        oShowProcess.Text2Inner("");
        oShowProcess.sPath = oParentData.fGetUrl() + (path === undefined ? sParentPath : bm_path + path);
        await oDownload.Download1File(path === undefined ? sParentPath : path, oData.sName);
    }
    catch (oErr) {
        if (oErr.name == "AbortError") {
        }
        else if (oErr.message) {
            ErrorMsgShow(oErr.message, { sErrType: "Files download", eGoal: "both", bNoCurrJobName: true });
        }
        else if (oErr.error && oErr.error.message) {
            ErrorMsgShow(oErr.error.message, { sErrType: "Files download", eGoal: "both", bNoCurrJobName: true });
        }
        else {
            if (oErr == "canceled by user") {
                ErrorMsgShow(oErr, { sErrType: "Files download", eGoal: "console", bNoCurrJobName: true });
            }
            else {
                ErrorMsgShow(JSON.stringify(oErr), { sErrType: "Files download", eGoal: "both", bNoCurrJobName: true });
            }
        }
    }
    bStopNewsPolling = false;
    if (oDownload) {
        oFsHandle.del(oDownload.sFsHandle);
    }
    if (oShowProcess.fm) {
        CloseFloatMenu(oShowProcess.fm);
    }
}
async function StreamDownloadFolder() {
    if (!oUpOrDownData.oDTP || oUpOrDownData.oDTP.fGetSelTabLen() < 1)
        return;
    bStopNewsPolling = true;
    const oDTP = oUpOrDownData.oDTP;
    oUpOrDownData.fClear();
    let fm = null;
    let oParentBr = oDTP.fGetSelBranch(0);
    if (oDTP.oParentBr) {
        oParentBr = oDTP.oParentBr;
    }
    else if (oParentBr.pParent) {
        oParentBr = oParentBr.pParent;
    }
    const oParentData = oParentBr.fGetData();
    let sParentPath = oParentData.fGetPathAndName ? oParentData.fGetPathAndName(oParentBr, true) : "";
    try {
        const { fs_handle, path, bm_path } = await oFsHandle.getNew(oParentBr);
        let dirHandle;
        if (BrowserFeatures.hasDirectoryPicker()) {
            dirHandle = await window.showDirectoryPicker({ mode: 'readwrite' });
        }
        else {
            dirHandle = { isFirefoxFallback: true, name: 'download' };
        }
        const oShowProcess = new CShowFileOperation("Str_DownloadFolder", "", "<span class='waiting_box'></span>");
        oShowProcess.SpeedAndRestDisplay("none");
        fm = oShowProcess.fm;
        const oDlFiles = new CDownload(fs_handle, oShowProcess);
        if (oDTP.oParentBr) {
            const aBrNames = [];
            for (let i = 0; i < oDTP.fGetSelTabLen(); i++) {
                const sName = oDTP.fGetSelBranch(i).fGetData().display_name;
                if (sName) {
                    aBrNames.push(sName);
                }
            }
            for (const sName of aBrNames) {
                const oBr = oDTP.oParentBr.fFindEl(sName);
                if (oBr) {
                    await oDlFiles.GetSummStructAndSize(oBr);
                }
            }
            oShowProcess.SetPbSize(oDlFiles.nSize);
        }
        else {
            for (let i = 0; i < oDTP.fGetSelTabLen(); i++) {
                const oBr = oDTP.fGetSelBranch(i);
                await oDlFiles.GetSummStructAndSize(oBr);
            }
            oShowProcess.SetPbSize(oDlFiles.nSize);
        }
        oShowProcess.SpeedAndRestDisplay("");
        oShowProcess.nStartTime = GetCurrTime();
        oShowProcess.nLastTime = oShowProcess.nStartTime;
        let sText1 = GetSizeAndUnit(oDlFiles.nSize, true) + " (" + GetLocalNumber(oDlFiles.nSize) + " bytes)";
        if (oDlFiles.root.cont.length === 1 && typeof oDlFiles.root.cont[0] !== "string") {
            sText1 = "Folder " + oDlFiles.root.cont[0].sName + ", total size " + sText1;
        }
        else if (oDlFiles.root.cont) {
            sText1 = oDlFiles.root.cont.length + " files, total size " + sText1;
        }
        oShowProcess.TextInner("<br>" + sText1, true);
        oShowProcess.sPath = oParentData.fGetUrl() + (path === undefined ? sParentPath : bm_path + path);
        if (oShowProcess.fm && oShowProcess.fm.fToMinScreen) {
            oShowProcess.fm.fToMinScreen();
        }
        await oDlFiles.DownloadFiles(oDlFiles.root, path === undefined ? sParentPath : path, dirHandle);
        if (oShowProcess.sProblemFiles) {
            ErrorMsgShow(GetLocaleText("Err_ProblemWithFiles") + oShowProcess.sProblemFiles, { sTitle: "Folder download", eGoal: "msgbox", bNoCurrJobName: true });
        }
    }
    catch (catchErr) {
        if (catchErr.name == "AbortError") {
        }
        else if (catchErr.message) {
            ErrorMsgShow(catchErr.message, { sErrType: "Folders download", eGoal: "both", bNoCurrJobName: true });
        }
        else if (catchErr.error && catchErr.error.message) {
            ErrorMsgShow(catchErr.error.message, { sErrType: "Folders download", eGoal: "both", bNoCurrJobName: true });
        }
        else {
            if (catchErr == "canceled by user") {
                ErrorMsgShow(catchErr, { sErrType: "Folders download", eGoal: "console", bNoCurrJobName: true });
            }
            else {
                ErrorMsgShow(JSON.stringify(catchErr), { sErrType: "Folders download", eGoal: "both", bNoCurrJobName: true });
            }
        }
    }
    if (fm) {
        fm.fCloseMenu();
    }
    bStopNewsPolling = false;
}
async function OpenFile(sFsHandle, sPath) {
    if (!sFsHandle || !sPath)
        return;
    async function DownloadFile(sFsHandle, nSize, ui8In, pb) {
        try {
            const fileData = await DownloadFleBufRequest(sFsHandle, nSize);
            if (fileData.buf_size) {
                if (pb) {
                    if (pb.DidDownloadStop()) {
                        throw "canceled by user";
                    }
                    pb.UpdatePB(fileData.buf_size);
                }
                const ui8New = new Uint8Array(decodeBase64(fileData.buf));
                const ui8Out = new Uint8Array(ui8In.length + ui8New.length);
                ui8Out.set(ui8In, 0);
                ui8Out.set(ui8New, ui8In.length);
                return await DownloadFile(sFsHandle, nSize, ui8Out, pb);
            }
            else {
                CloseFileRequest(sFsHandle);
                return ui8In;
            }
        }
        catch (err) {
            throw err;
        }
    }
    if (sPath.substring(0, 1) != '/') {
        sPath = '/' + sPath;
    }
    try {
        const oOpenData = await SendRecivePostApiWithRetry("OpenDownload", { "filesys_handle": sFsHandle, "path": sPath });
        const ui8Out = new Uint8Array(0);
        let nPrefSize = Number(oOpenData.preferred_buf_size);
        if (isNaN(nPrefSize) || nPrefSize == 0) {
            nPrefSize = 0x400000;
        }
        const ui8Resp = await DownloadFile(sFsHandle, nPrefSize, ui8Out);
        if (sPath.endsWith(CHK_ENC_PREFER_NAME1) || sPath.endsWith(CHK_ENC_PREFER_NAME2)) {
            const slicedArr = Array.from(ui8Resp.slice(0, 3));
            if (slicedArr[0] == 0x1f && slicedArr[1] == 0x8b && slicedArr[2] == 0x08) {
                return;
            }
            else {
                const err = { "error": { "code": -32603, "message": GetLocaleText("Err_BadGzipHeader"), "data": { "error_num": 6, "error_str": "local_err" } } };
                throw err;
            }
        }
        else {
            return;
        }
    }
    catch (err) {
        throw err;
    }
}
function CheckNewFileName(menu, resolve, reject) {
    if (menu.jsFloatMenuDescr.sNewName) {
        if (menu.jsFloatMenuDescr.sNewName == menu.jsFloatMenuDescr.sOldName) {
            menu.fCloseMenu();
        }
        else {
            resolve({ "command": "", "data": {}, "pMenu": menu });
        }
    }
    else {
        ErrorMsgShow(GetLocaleText("Err_EnterNewName"), { sTitle: "Err_BadName" });
    }
}
function FileOpCancel(menu, resolve, reject) {
    const domThisMinInfo = document.getElementById("this_min_info_" + menu.id);
    if (domThisMinInfo) {
        domThisMinInfo.remove();
    }
    reject();
    CloseFloatMenu(menu);
}
function OpenFileByLink(oBDE) {
    if (oBDE && oBDE.DTP) {
        _FsCommandExec("DownloadToLink", "File opening", "", "", "", false, oBDE.DTP);
    }
}
async function FileOpStatusPolling(oMenu, oAns, domWait_box, sCommand, aNames, oSrcDTP, oFOSP, nCurrTime, sTitle, sAsc, aDisplayNames, sBtn, sFromTo, sPath, sPathFrom, nStrBeforeSel, oDstBr, oSrcBr, oDstDTP, bRenameErr) {
    function Repeat() {
        setTimeout(async () => {
            FileOpStatusPolling(oMenu, oAns, domWait_box, sCommand, aNames, oSrcDTP, oFOSP, nCurrTime, sTitle, sAsc, aDisplayNames, sBtn, sFromTo, sPath, sPathFrom, nStrBeforeSel, oDstBr, oSrcBr, oDstDTP, bRenameErr);
        }, 1000);
    }
    try {
        if (oMenu && oMenu.bSelfDeleted && oAns.state <= 1) {
            oAns = await SendRecivePostApiWithRetry("CancelFileOp", { "fop_handle": oAns.fop_handle });
        }
        else {
            oAns = await SendRecivePostApiWithRetry("GetFileOpStatus", { "fop_handle": oAns.fop_handle });
        }
        if (oAns.state > 1) {
            if (!oMenu && oAns.errors.length > 0) {
                oMenu = _CreateMenuIfNoMenu(sCommand, oAns, sTitle, sAsc, aDisplayNames, sBtn, sFromTo, sPath, sPathFrom);
                domWait_box = document.getElementById("wait_box_" + oMenu.id);
            }
            if (domWait_box) {
                if (oAns.state == 2 && domWait_box) {
                    const domShortBG = document.getElementById("fop_short_bg_" + oMenu.id);
                    if (domShortBG) {
                        domShortBG.innerHTML = "";
                        domShortBG.append(CreateShortPB(100));
                    }
                    if (oAns.errors.length > 0) {
                        domWait_box.innerHTML = GetLocaleText("Err_OpComplWithErrors", [oAns.errors.join("<br>")]);
                        const img = SetImg("error", "1rem");
                        if (img) {
                            img.style.marginRight = "0.25rem";
                            domWait_box.prepend(img);
                        }
                        const domBtnCancel = document.getElementById("BtnCancel_" + oMenu.id);
                        if (domBtnCancel) {
                            domBtnCancel.innerHTML = GetLocaleText("Btn_Close");
                            domBtnCancel.classList.replace("flt_menu_btn", "flt_menu_btn_as_def");
                        }
                        oMenu.style.display = "";
                    }
                    else if (sCommand == "DownloadToLink") {
                        if (oAns.result_link) {
                            const link = document.createElement('a');
                            link.href = request_url + oAns.result_link;
                            link.target = '_blank';
                            link.rel = 'noopener noreferrer';
                            const aTmp = aNames[0].split("\/");
                            link.download = aTmp[aTmp.length - 1];
                            domWait_box.append(link);
                            link.click();
                            CloseFloatMenu(oMenu);
                        }
                    }
                    else {
                        const sSuccess = (sCommand == "CopyFiles") ? "Str_CopySuccess" :
                            (sCommand == "MoveFiles") ? "Str_MoveSuccess" :
                                (sCommand == "RenameFile") ? "Str_RenameSuccess" :
                                    "Str_DeleteSuccess";
                        domWait_box.innerHTML = GetLocaleText(sSuccess);
                        setTimeout(() => {
                            CloseFloatMenu(oMenu);
                        }, 1000);
                    }
                }
                else if (oAns.state == 4) {
                    if (oAns.errors.length === 0) {
                        domWait_box.innerHTML = GetLocaleText("Str_AuthSmthngWntWrng");
                        return;
                    }
                    const sSummary = oAns.errors[oAns.errors.length - 1];
                    domWait_box.innerHTML = "<span class='err_in_light_bg'><b>" + sSummary + "</b></span>";
                    oAns.errors.splice(oAns.errors.length - 1);
                    if (oAns.errors.length > 0) {
                        domWait_box.innerHTML += "<div class='err_list'>" + oAns.errors.join("<br>") + "</div>";
                    }
                    const img = SetImg("error", "1rem");
                    if (img) {
                        img.style.marginRight = "0.25rem";
                        domWait_box.prepend(img);
                    }
                    const domBtnCancel = document.getElementById("BtnCancel_" + oMenu.id);
                    if (domBtnCancel) {
                        domBtnCancel.innerHTML = GetLocaleText("Btn_Close");
                        domBtnCancel.classList.replace("flt_menu_btn", "flt_menu_btn_as_def");
                    }
                    oMenu.style.display = "";
                }
            }
            else if (sCommand == "DownloadToLink" && oAns.result_link) {
                const link = document.createElement('a');
                link.href = request_url + oAns.result_link;
                link.target = '_blank';
                link.rel = 'noopener noreferrer';
                const aTmp = aNames[0].split("\/");
                link.download = aTmp[aTmp.length - 1];
                domModal.append(link);
                link.click();
                setTimeout(() => { domModal.innerHTML = ""; }, 2000);
            }
            if (sCommand == "DeleteFiles" || sCommand == "MoveFiles" || sCommand == "RenameFile" && bRenameErr) {
                if (oSrcDTP) {
                    if (oSrcDTP.oParentBr) {
                        await RefreshBrowseBranch("", { DTP: oSrcDTP.oParentDTP, Branch: oSrcBr });
                        if (nStrBeforeSel >= 0) {
                            oSrcDTP.SetRowsAsSelect([nStrBeforeSel], true);
                        }
                    }
                    else {
                        await RefreshBrowseBranch("", { DTP: oSrcDTP, Branch: oSrcBr });
                        if (nStrBeforeSel < 0) {
                            await TableRowClick(oSrcDTP, oSrcBr, true);
                        }
                        else {
                            oSrcDTP.fSelTabClean();
                            oSrcDTP.SetRowsAsSelect([nStrBeforeSel], true);
                            await TableRowClick(oSrcDTP, oSrcDTP.fGetSelBranch(0), true);
                        }
                    }
                }
            }
            else if (sCommand == "RenameFile" && oSrcBr && oFOSP.sNewName) {
                const sName = aNames[0].startsWith("\/") ? aNames[0].slice(1) : aNames[0];
                const sNewName = oFOSP.sNewName.startsWith("\/") ? oFOSP.sNewName.slice(1) : oFOSP.sNewName;
                oSrcBr.fChangeOneField(sName, sNewName, "sName", true);
                oSrcBr.fChangeOneField(sName, sNewName, "display_name");
                if (oSrcDTP) {
                    if (oSrcDTP.oParentDTP) {
                        oSrcDTP.oParentDTP.ShowRows();
                        oSrcDTP.ShowRowsOrIcons();
                    }
                    else {
                        oSrcDTP.ShowRows();
                    }
                }
            }
            if (oDstBr && oDstDTP) {
                RefreshBrowseBranch("", { DTP: oDstDTP, Branch: oDstBr });
            }
        }
        else if (oAns.question && oAns.question.kind) {
            const sDstName = GetFileNameOfPath(oAns.question.dst_path);
            let obj = { sUserAct: "skip", bDontAskAgain: false };
            let sQst = GetLocaleText("Err_ProblemWithFiles") + "<br>" + GetPathForShow(oAns.question.src_path) +
                ":<br><span class='err_in_light_bg'>" + oAns.question.error + "</span>";
            let jsConf = { title: "Title_FileOpUserQuestion", bottom_box: [
                    { title: "Btn_Continue", "close": true, command: "continue", "default": true },
                    { title: "Btn_Cancel", "close": true }
                ], cont: [{ title: "", cont: [
                            { type: "text", title: sQst, class: "FileOpUserQuestionErr" },
                        ] }] };
            if (oAns.question.kind == "overwrite") {
                obj = { bDontAskAgain: false, sNewName: sDstName, sUserAct: "" };
                sTitle = GetLocaleText("Cmd_ShowToOverwrite") + " " + sDstName + "?";
                if (sCommand == "RenameFile") {
                    bRenameErr = true;
                    jsConf = { title: sTitle, bottom_box: [], cont: [
                            { title: "", cont: [
                                    { type: "place", title: "", id: "place_for_question" },
                                    { type: "separator", h: 30 },
                                    { type: "row", cont: [
                                            { type: "checkbox", title: "Explorer_Do_Same_For_Other_Conflicts", value: "bDontAskAgain", bNoControl: true },
                                            { type: "space", class: "width100" },
                                            { type: "button", title: "Btn_Overwrite", class: "FileOpUserQuestionBtn", command: "FileOpUserAnswer('overwrite')++" },
                                            { type: "button", title: "Btn_NewerWins", class: "FileOpUserQuestionBtn", command: "FileOpUserAnswer('take_newer')++" },
                                            { type: "button", title: "Cmd_Skip", class: "FileOpUserQuestionBtn", command: "FileOpUserAnswer('skip')++" },
                                            { type: "button", title: "Btn_Cancel", class: "FileOpUserQuestionBtn", command: "FileOpUserAnswer('')++" },
                                        ] },
                                ] }
                        ] };
                }
                else {
                    jsConf = { title: sTitle, bottom_box: [], cont: [
                            { title: "", cont: [
                                    { type: "place", title: "", id: "place_for_question" },
                                    { type: "separator", h: 30 },
                                    { type: "row", cont: [
                                            { type: "checkbox", title: "Explorer_Do_Same_For_Other_Conflicts", value: "bDontAskAgain", bNoControl: true },
                                            { type: "space", class: "width100" },
                                            { type: "button", title: "Btn_Overwrite", class: "FileOpUserQuestionBtn", command: "FileOpUserAnswer('overwrite')++" },
                                            { type: "button", title: "Btn_NewerWins", class: "FileOpUserQuestionBtn", command: "FileOpUserAnswer('take_newer')++" },
                                            { type: "button", title: "Cmd_Rename", class: "FileOpUserQuestionBtn", command: "FileOpUserAnswer('rename')++" },
                                            { type: "button", title: "Cmd_Skip", class: "FileOpUserQuestionBtn", command: "FileOpUserAnswer('skip')++" },
                                            { type: "button", title: "Btn_Cancel", class: "FileOpUserQuestionBtn", command: "FileOpUserAnswer('')++" },
                                        ] },
                                ] }
                        ] };
                }
                let svgSrc = DynamicSvg["folder"];
                if (oAns.question.src_info.bIsFile) {
                    svgSrc = '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" >'
                        + GetFileTypeSvg(GetFileExtension(oAns.question.src_path).slice(1)) + '</svg>';
                }
                else if (oAns.question.src_info.bIsLink) {
                    svgSrc = DynamicSvg["folder_link"];
                }
                svgSrc = svgSrc.replace("<svg", "<svg class='icon_for_fileop_qst'");
                let svgDst = DynamicSvg["folder"];
                if (oAns.question.dst_info.bIsFile) {
                    svgDst = '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" >'
                        + GetFileTypeSvg(GetFileExtension(oAns.question.dst_path).slice(1)) + '</svg>';
                }
                else if (oAns.question.dst_info.bIsLink) {
                    svgDst = DynamicSvg["folder_link"];
                }
                svgDst = svgDst.replace("<svg", "<svg class='icon_for_fileop_qst'");
                sQst = "<div><p>" + GetLocaleText("Explorer_DestFilePresent") + "<p>" + sDstName + "</div>" +
                    "<div class='flex_gor file_info_for_msg'>" +
                    "<div>" +
                    "<div>" + GetLocaleText("Str_Source") + "</div>" +
                    "<div class='flex_gor'>" +
                    svgSrc +
                    "<div>" +
                    GetLocaleText("sSize") + " " + GetSizeAndUnit(oAns.question.src_info.size) + "<br>" +
                    GetLocaleText("Explorer_DateModified", [GetDTString(oAns.question.src_info.tMod_s)]) +
                    "</div>" +
                    "</div>" +
                    "</div>" +
                    "<div>" +
                    "<div>" + GetLocaleText("Str_Destination") + "</div>" +
                    "<div class='flex_gor'>" +
                    svgDst +
                    "<div>" +
                    GetLocaleText("sSize") + " " + GetSizeAndUnit(oAns.question.dst_info.size) + "<br>" +
                    GetLocaleText("Explorer_DateModified", [GetDTString(oAns.question.dst_info.tMod_s)]) +
                    "</div>" +
                    "</div>" +
                    "</div>" +
                    "</div>";
            }
            const oUserAnswer = CreateFloatMenu(jsConf, { width: "700px", top: "20%" }, obj, { icon: "C_Ena_Que_Fil", sRightWinClass: "fop_user_answer" });
            const domPlace = document.getElementById("place_for_question_" + oUserAnswer.oMenu.id);
            if (domPlace) {
                domPlace.innerHTML = sQst;
            }
            oUserAnswer.promise.catch(() => { });
            try {
                await oUserAnswer.promise;
                oAns = await SendRecivePostApiWithRetry("PostFileOpAnswer", { "fop_handle": oAns.fop_handle, "action": obj.sUserAct,
                    "new_name": obj.sNewName, "do_not_ask_again": obj.bDontAskAgain });
            }
            catch (oErr) {
                if (!oErr) {
                    HtmlErrBox(GetLocaleText("Str_AuthSmthngWntWrng"), GetLocaleText("Title_FileOpError"));
                }
                else if (oErr && IsObject(oErr) && !("sUserAct" in oErr)) {
                    HtmlErrBox(JSON.stringify(oErr), GetLocaleText("Title_FileOpError"));
                }
                CloseFloatMenu(oMenu);
                await SendRecivePostApiWithRetry("CancelFileOp", { "fop_handle": oAns.fop_handle });
                if (oDstBr && oDstDTP) {
                    RefreshBrowseBranch("", { DTP: oDstDTP, Branch: oDstBr });
                }
                if (oSrcBr && oSrcDTP && sCommand == "DeleteFiles") {
                    RefreshBrowseBranch("", { DTP: oSrcDTP, Branch: oSrcBr });
                }
            }
            Repeat();
        }
        else if (oAns.message && domWait_box) {
            const domShortBG = document.getElementById("fop_short_bg_" + oMenu.id);
            const domShortText = document.getElementById("fop_short_wait_text_" + oMenu.id);
            if (sCommand != "DeleteFiles" && sCommand != "RenameFile") {
                const sItemInfo = (!!oAns.items_done && !!oAns.items_total) ? " (" + (+oAns.items_done + 1) + " of " + oAns.items_total + ")" : "";
                domWait_box.innerHTML = oAns.message + sItemInfo;
                if (domShortText)
                    domShortText.innerHTML = oAns.message + sItemInfo;
                if (typeof oAns.percent_complete == "number") {
                    const domStatistics = document.createElement("div");
                    domStatistics.style.height = "1.5rem";
                    domWait_box.append(domStatistics);
                    CreateProgressBar(domStatistics, { percent: oAns.percent_complete });
                    if (domShortBG) {
                        domShortBG.innerHTML = "";
                        domShortBG.append(CreateShortPB(oAns.percent_complete));
                    }
                }
                const oSize = ConvertBytes(oAns.bytes_total);
                if (oSize) {
                    domWait_box.innerHTML += "Total <b>" + oSize.nSpace1 + "</b> " + oSize.unit + "<br>";
                }
                const oSpeed = ConvertBytes(oAns.bytes_per_sec);
                if (!isNaN(oSpeed.nSpace1)) {
                    domWait_box.innerHTML += GetLocaleText("Str_DlSpeed") + " <b>" + oSpeed.nSpace1 + "</b> " + oSpeed.unit + "/sec.</br>";
                }
                const nDeltaSec = (GetCurrTime() - nCurrTime);
                if (!isNaN(nDeltaSec) && nDeltaSec > 0) {
                    domWait_box.innerHTML += GetLocaleText("Str_TimeElapsed") + " " + FormatTimeDifference(nDeltaSec, " h ", " m ", " sec. ") + "</br>";
                }
                const nSecRem = +oAns.seconds_remaining;
                if (!isNaN(nSecRem) && nDeltaSec > 0) {
                    domWait_box.innerHTML += FormatTimeDifference(nSecRem * 1000, " h ", " m ", " sec ") + GetLocaleText("Str_DlRestTime");
                }
            }
            else {
                const nTotal = +oAns.items_total;
                const nCurr = +oAns.items_done + 1;
                if (!isNaN(nTotal) && !isNaN(nCurr) && domShortBG && nTotal > 0) {
                    domShortBG.innerHTML = "";
                    domShortBG.append(CreateShortPB(nCurr * 100 / nTotal));
                }
                domWait_box.innerHTML = oAns.message;
                if (domShortText)
                    domShortText.innerHTML = oAns.message;
            }
            if (domWait_box.innerText === oFOSP.sPrevMsg) {
                oFOSP.sDots += ".";
                if (oFOSP.sDots.length > 10) {
                    oFOSP.sDots = " .";
                }
                domWait_box.innerHTML += oFOSP.sDots;
            }
            else {
                oFOSP.sDots = " ";
                oFOSP.sPrevMsg = domWait_box.innerText;
            }
            Repeat();
        }
        else if (!oMenu) {
            oFOSP.nCycleCnt++;
            if (oFOSP.nCycleCnt > 1) {
                oMenu = _CreateMenuIfNoMenu(sCommand, oAns, sTitle, sAsc, aDisplayNames, sBtn, sFromTo, sPath, sPathFrom);
                domWait_box = document.getElementById("wait_box_" + oMenu.id);
            }
            Repeat();
        }
    }
    catch (oErr) {
        const sErrTitle = GetLocaleText(sTitle).replace("%1", "");
        CatchErrProcess(oErr, sErrTitle, { bNoCurrJobName: true });
        if (oMenu) {
            CloseFloatMenu(oMenu);
        }
    }
}
async function FileOpUserAnswer(sText, oMenu) {
    if (sText == '') {
        oMenu.fCloseMenu(true);
        return;
    }
    if (sText == 'rename') {
        const obj = { sNewName: oMenu.jsFloatMenuDescr.sNewName };
        let sHint = "";
        while (obj.sNewName === "" || obj.sNewName === oMenu.jsFloatMenuDescr.sNewName) {
            const msgRename = CreateFloatMenu(jsFloatMenu.MsgBoxRename, { width: "600px", top: "20%" }, obj);
            const domHint = document.getElementById("hint_" + msgRename.oMenu.id);
            if (domHint)
                domHint.innerHTML = sHint;
            msgRename.promise.catch(() => { });
            try {
                await msgRename.promise;
            }
            catch {
                return;
            }
            sHint = GetLocaleText("Hint_NewNameNoEmptiAndDiff", [oMenu.jsFloatMenuDescr.sNewName]);
        }
        oMenu.jsFloatMenuDescr.sNewName = obj.sNewName;
        oMenu.jsFloatMenuDescr.sUserAct = 'rename';
    }
    else {
        oMenu.jsFloatMenuDescr.sUserAct = sText;
    }
    oMenu.fCloseMenuOk();
}
async function FsOperations(sCommand, oTables) {
    try {
        if (sCommand == "DeleteFiles") {
            if (!oTables || !oTables.oDTP1)
                return;
            await _FsCommandExec(sCommand, "Title_DeleteItem", "Ask_DeleteItem", "Btn_Delete", "Str_From", false, oTables.oDTP1);
        }
        else if (sCommand == "RenameFile") {
            if (!oTables || !oTables.oDTP1)
                return;
            await _FsCommandExec(sCommand, "Title_Rename", "", "Btn_Rename", "", false, oTables.oDTP1);
        }
        else {
            if (!oTables || !oTables.oDTP1 || !oTables.oDTP2)
                return;
            let oSrcDTP = oTables.oDTP1;
            let oDstDTP = oTables.oDTP2;
            if (sCommand == "copyR2L" || sCommand == "moveR2L") {
                oSrcDTP = oTables.oDTP2;
                oDstDTP = oTables.oDTP1;
            }
            if (!oSrcDTP || oSrcDTP.fGetSelTabLen() < 1) {
                ErrorMsgShow(GetLocaleText("Err_DontSelSrc"), { bNoCurrJobName: true });
                return;
            }
            if (!oDstDTP || oDstDTP.fGetSelTabLen() < 1) {
                ErrorMsgShow(GetLocaleText("Err_DontSelDst"), { bNoCurrJobName: true });
                return;
            }
            if (oDstDTP.fGetSelTabLen() > 1 || !oDstDTP.fGetSelBranch(0).cont) {
                ErrorMsgShow(GetLocaleText("Err_SelMultDst"), { bNoCurrJobName: true });
                return;
            }
            const oSrcData = oSrcDTP.fGetSelBranch(0).fGetData();
            if (oSrcData.bIsServer || oSrcData.sFs || oSrcData.sAccKey) {
                ErrorMsgShow(GetLocaleText("Err_CantBeSelectedAsSrcCopyMove", [oSrcData.display_name], { bBold: true }), { bNoCurrJobName: true });
                return;
            }
            const oDstBr = oDstDTP.fGetSelBranch(0);
            const oDstData = oDstBr.fGetData();
            if (oDstData.bContServList || oDstData.bAccReadOnly) {
                ErrorMsgShow(GetLocaleText("Err_SelMultDst"), { bNoCurrJobName: true });
                return;
            }
            const oSrcParentBr = oSrcDTP.fGetSelBranch(0).pParent;
            const sSrcParentPath = oSrcData.fGetUrl() + oSrcParentBr.fGetData().fGetPathAndName(oSrcParentBr);
            const sDstPath = oDstData.fGetUrl() + oDstData.fGetPathAndName(oDstBr);
            if (sSrcParentPath === sDstPath) {
                ErrorMsgShow(GetLocaleText("Err_CantCopyMoveFileToOwnFolder"));
                return;
            }
            else if (!oSrcData.bIsFile && DoJobPathsContainsOneAnother(sSrcParentPath + "/" + oSrcData.sName, sDstPath, true)) {
                ErrorMsgShow(GetLocaleText("Err_CantCopyMoveFolderToSubfolder"));
                return;
            }
            if (!("bCanCreateFolder" in oDstData) || !("bCanCreateFile" in oDstData)) {
                const { fs_handle } = await oFsHandle.getNew(oDstBr);
                await FolderInfoRequestForExplorer(fs_handle, { Branch: oDstBr }, oDstData);
                oFsHandle.del(fs_handle);
            }
            if (!oDstData.bCanCreateFolder && !oDstData.bCanCreateFile) {
                ErrorMsgShow(GetLocaleText("Err_DstCantGetItems"), { bNoCurrJobName: true });
                return;
            }
            let bIsFiles = false;
            let bIsFolders = false;
            for (let i = oSrcDTP.fGetSelTabLen() - 1; i >= 0; i--) {
                if (oSrcDTP.fGetSelBranch(i).cont) {
                    bIsFolders = true;
                }
                else {
                    bIsFiles = true;
                }
            }
            if (!oDstData.bCanCreateFolder && bIsFolders) {
                ErrorMsgShow(GetLocaleText("Err_DstCantGetFolders"), { bNoCurrJobName: true });
                return;
            }
            if (!oDstData.bCanCreateFile && bIsFiles) {
                ErrorMsgShow(GetLocaleText("Err_DstCantGetFiles"), { bNoCurrJobName: true });
                return;
            }
            if ((oSavedData.eExplorerMode == 'detal_mode' || oSavedData.eExplorerMode == 'med_icon_mode') && oSrcDTP.oFolderContTable && oSrcDTP.oFolderContTable.fGetSelTabLen() > 0) {
                oSrcDTP = oSrcDTP.oFolderContTable;
            }
            if (sCommand == "copyR2L" || sCommand == "copyL2R") {
                await _FsCommandExec("CopyFiles", "Title_CopyItems", "Ask_CopyItems", "Cmd_Copy", "Str_FromTo", sCommand == "copyR2L", oSrcDTP, oDstDTP);
            }
            else {
                await _FsCommandExec("MoveFiles", "Title_MoveItems", "Ask_MoveItems", "Cmd_Move", "Str_FromTo", sCommand == "moveR2L", oSrcDTP, oDstDTP);
            }
        }
    }
    catch (oErr) {
        const sErrTitle = ((sCommand == "copyR2L" || sCommand == "copyL2R") ? GetLocaleText("Title_CopyItems") : GetLocaleText("Title_MoveItems")).replace("%1", "");
        CatchErrProcess(oErr, sErrTitle, { bNoCurrJobName: true });
    }
}
async function _FsCommandExec(sCommand, sTitle, sAsc, sBtn, sFromTo, bR_L, oSrcDTP, oDstDTP) {
    let oMenu = null;
    try {
        const aNames = [];
        const aDisplayNames = [];
        let oSrcBr = undefined;
        if (oSrcDTP.oParentBr) {
            oSrcBr = oSrcDTP.oParentBr;
        }
        else {
            oSrcBr = oSrcDTP.fGetSelBranch(0).pParent;
        }
        const nSelTabLen = oSrcDTP.fGetSelTabLen();
        const oSrcData = oSrcBr.fGetData();
        const oSrcConn = CopyObject(oSrcData.oConn);
        let oBM = GetBM(oSrcBr);
        if (oBM) {
            oSrcConn.sUrlA = oSrcData.fGetUrl() + (oBM.sServerDirA || oBM.BmkKey);
            const sPathToFiles = oSrcData.fGetPathAndName(oSrcBr);
            for (let i = 0; i < nSelTabLen; i++) {
                const itemData = oSrcDTP.fGetSelBranch(i).fGetData();
                aNames.push(sPathToFiles + "/" + itemData.sName);
                aDisplayNames.push(itemData.display_name);
            }
        }
        else {
            oSrcConn.sUrlA = oSrcData.fGetUrl() + oSrcData.fGetPathAndName(oSrcBr);
            for (let i = 0; i < nSelTabLen; i++) {
                const itemData = oSrcDTP.fGetSelBranch(i).fGetData();
                aNames.push("/" + itemData.sName);
                aDisplayNames.push(itemData.display_name);
            }
        }
        let sPathFrom = oSrcConn.sUrlA;
        let nStrBeforeSel = oSrcDTP.fGetSelRowNum(0) - 1;
        let oParams;
        let sPath = "";
        let oDstBr = null;
        if (oDstDTP) {
            if (oDstDTP.oParentBr) {
                oDstBr = oDstDTP.oParentBr;
            }
            else {
                oDstBr = oDstDTP.fGetSelBranch(0);
            }
            const oDstData = oDstBr.fGetData();
            const oDstConn = CopyObject(oDstData.oConn);
            let oBM2 = GetBM(oDstBr);
            let sPathToFiles = "";
            if (oBM2) {
                oDstConn.sUrlA = oDstData.fGetUrl() + (oBM2.sServerDirA || oBM2.BmkKey);
                sPathToFiles = oDstData.fGetPathAndName(oDstBr);
            }
            else {
                if (sCommand === "MoveFiles") {
                    const tmpDstUrl = oDstData.fGetUrl() + oDstData.fGetPathAndName(oDstBr);
                    oDstConn.sUrlA = GsGetPrefixOfUrlA(tmpDstUrl);
                    sPathToFiles = tmpDstUrl.slice(oDstConn.sUrlA.length);
                }
                else {
                    oDstConn.sUrlA = oDstData.fGetUrl() + oDstData.fGetPathAndName(oDstBr);
                }
            }
            oParams = {
                src_folder_coords: { conn: oSrcConn, sAcctKeyA: oSrcData.fGetAccKey(), opts: oBM ? oBM.Opts : undefined },
                dst_folder_coords: { conn: oDstConn, sAcctKeyA: oDstData.fGetAccKey(), opts: oBM2 ? oBM2.Opts : undefined },
                src_path_list: aNames, dst_folder_path: sPathToFiles
            };
            sPath = oDstConn.sUrlA + sPathToFiles;
        }
        else if (sCommand === "DownloadToLink" || sCommand === "RenameFile") {
            oParams = { folder_coords: { conn: oSrcConn, sAcctKeyA: oSrcData.fGetAccKey(), opts: oBM ? oBM.Opts : undefined }, path: aNames[0], };
        }
        else {
            sPath = oSrcData.fGetUrl() + oSrcData.fGetPathAndName(oSrcBr);
            oParams = { folder_coords: { conn: oSrcConn, sAcctKeyA: oSrcData.fGetAccKey(), opts: oBM ? oBM.Opts : undefined }, path_list: aNames, };
        }
        let domWait_box = null;
        const oFOSP = { sPrevMsg: "", sDots: " ", nCycleCnt: 0 };
        if (sCommand !== "DownloadToLink") {
            const { js, obj } = _GetFsOperationDialog(sTitle, sAsc, aDisplayNames, sBtn, sFromTo, sPath, sPathFrom, false);
            const { x, y } = oMenuRegister.GetFreeCoords((document.documentElement.clientWidth - 600) / 2, document.documentElement.clientHeight / 5, 40);
            let domThisMinInfo = null;
            const sIcon = sCommand == "CopyFiles" ? (bR_L ? "L_Dis_Arr_Fill" : "R_Dis_Arr_Fill") :
                sCommand == "MoveFiles" ? (bR_L ? "L_Dis_Arr_Nofl" : "R_Dis_Arr_Nofl") :
                    sCommand == "DeleteFiles" ? "delete" : "rename";
            const oConfirm = CreateFloatMenu(js, { width: "600px", top: y + "px", left: x + "px" }, obj, {
                icon: sIcon, bNoModal: true, fToMinScreen: () => {
                    _ShortFileOpInfo(sCommand, oConfirm, domThisMinInfo, GetPathForShow(sPath), GetPathForShow(sPathFrom));
                }
            });
            oMenu = oConfirm.oMenu;
            oConfirm.promise.catch(() => { });
            try {
                await oConfirm.promise;
                const domBtnOk = document.getElementById("BtnOk_" + oConfirm.oMenu.id);
                if (domBtnOk) {
                    domBtnOk.remove();
                }
                const domInput = document.getElementById("sNewName_" + oConfirm.oMenu.id);
                if (domInput) {
                    domInput.readOnly = true;
                    domInput.classList.add("input_readonly");
                }
                domWait_box = document.getElementById("wait_box_" + oConfirm.oMenu.id);
                if (oConfirm.oMenu.fToMinScreen)
                    oConfirm.oMenu.fToMinScreen();
            }
            catch {
                return;
            }
            if (obj && obj.sNewName) {
                oParams.dst_path = obj.sNewName.startsWith("\/") ? obj.sNewName : "\/" + obj.sNewName;
                oFOSP.sNewName = obj.sNewName;
            }
        }
        let oAns = await SendRecivePostApiWithRetry(sCommand, oParams);
        const nCurrTime = GetCurrTime();
        FileOpStatusPolling(oMenu, oAns, domWait_box, sCommand, aNames, oSrcDTP, oFOSP, nCurrTime, sTitle, sAsc, aDisplayNames, sBtn, sFromTo, sPath, sPathFrom, nStrBeforeSel, oDstBr, oSrcBr, oDstDTP);
    }
    catch (oErr) {
        const sErrTitle = GetLocaleText(sTitle).replace("%1", "");
        CatchErrProcess(oErr, sErrTitle, { bNoCurrJobName: true });
        if (oMenu) {
            CloseFloatMenu(oMenu);
        }
    }
}
function _GetFsOperationDialog(sTitle, sQst, aArgs, sBtn, sFromTo, sPath, sPathFrom, bDefCancel) {
    let js;
    if (sTitle === "Title_Rename") {
        js = {
            title: GetLocaleText(sTitle), bottom_box: [
                { title: "Btn_Rename", id: "BtnOk", default: true, command: "CheckNewFileName+" },
                { title: "Btn_Cancel", id: "BtnCancel", "close": true, default: bDefCancel },
            ], cont: [
                {
                    "title": "", cont: [
                        { type: "text", title: GetLocaleText("Str_OldName", [aArgs[0]]) },
                        { type: "textfield", title: "Str_NewName", value: "sNewName", id: "sNewName" },
                        { type: "text", title: "", id: "wait_box", class: "width100" },
                    ]
                }
            ]
        };
        return { js, obj: { sNewName: aArgs[0], sOldName: aArgs[0] } };
    }
    const sAdd = GetLocaleText(sFromTo, [GetPathForShow(sPath), GetPathForShow(sPathFrom)]);
    if (!sBtn) {
        js = {
            title: GetLocaleText(sTitle), bottom_box: [
                { title: "Btn_Cancel", id: "BtnCancel", "close": true, default: bDefCancel },
            ], cont: [
                {
                    "title": "", cont: [
                        { type: "text", title: "Str_PreparingLink", id: "wait_box", class: "width100" },
                    ]
                }
            ]
        };
    }
    else {
        js = {
            title: GetLocaleText(sTitle, [aArgs.length + ""]), bottom_box: [
                { title: sBtn, id: "BtnOk", default: !bDefCancel, command: sBtn },
                { title: "Btn_Cancel", id: "BtnCancel", default: bDefCancel, command: "FileOpCancel+" },
            ], cont: [
                {
                    "title": "", cont: [
                        { type: "text", title: GetLocaleText(sQst, [aArgs.length + "", aArgs.join("<br>")]), class: "width100" },
                        { type: "text", title: sAdd, id: "wait_box", class: "width100" },
                    ]
                }
            ]
        };
    }
    return { js, obj: null };
}
function _ShortFileOpInfo(sCommand, oConfirm, domThisMinInfo, sPath, sPathFrom) {
    const id = ged ? ged.GetExprolerWinId() : glob ? glob.GetExprolerWinId() : "";
    const domFileOpsPanel = document.getElementById("min_file_ops_" + id);
    if (domFileOpsPanel) {
        domThisMinInfo = document.getElementById("this_min_info_" + oConfirm.oMenu.id);
        if (!domThisMinInfo) {
            domThisMinInfo = document.createElement("div");
            domThisMinInfo.id = "this_min_info_" + oConfirm.oMenu.id;
            domThisMinInfo.className = "file_op_short_info flex_gor_center";
            domThisMinInfo.onclick = () => {
                oConfirm.oMenu.style.display = "";
            };
            const sCommInfo = (sCommand == "CopyFiles") ? "Str_CopyShortInfo" :
                (sCommand == "MoveFiles") ? "Str_MoveShortInfo" :
                    (sCommand == "RenameFile") ? "Str_RenameShortInfo" :
                        (sCommand == "DownloadToLink") ? "Str_OpenShortInfo" :
                            "Str_DeleteShortInfo";
            domThisMinInfo.innerHTML = GetLocaleText(sCommInfo, [sPath, sPathFrom]);
            const domShortPB = document.createElement("div");
            domShortPB.id = "fop_short_bg_" + oConfirm.oMenu.id;
            domShortPB.className = "fop_short_bg";
            domThisMinInfo.prepend(domShortPB);
            const domFopMsg = document.createElement("div");
            domFopMsg.id = "fop_short_wait_text_" + oConfirm.oMenu.id;
            domFopMsg.className = "fop_short_text";
            domThisMinInfo.append(domFopMsg);
            const imgStop = SetImg("stop", "1rem");
            if (imgStop) {
                imgStop.onclick = () => {
                    CloseFloatMenu(oConfirm.oMenu);
                    domThisMinInfo.remove();
                };
                imgStop.classList.add("fltmn_icon");
                imgStop.classList.add("fop_short_cancel");
                domThisMinInfo.append(imgStop);
            }
        }
        domFileOpsPanel.append(domThisMinInfo);
        oConfirm.oMenu.style.display = "none";
        oConfirm.oMenu.fOnClose = () => {
            if (domThisMinInfo)
                domThisMinInfo.remove();
        };
    }
}
function _CreateMenuIfNoMenu(sCommand, oAns, sTitle, sAsc, aDisplayNames, sBtn, sFromTo, sPath, sPathFrom) {
    const { js } = _GetFsOperationDialog(sTitle, sAsc, aDisplayNames, sBtn, sFromTo, sPath, sPathFrom, false);
    const { x, y } = oMenuRegister.GetFreeCoords((document.documentElement.clientWidth - 600) / 2, document.documentElement.clientHeight / 5, 40);
    if (sCommand == "DownloadToLink") {
        sPath = oAns.description.src_url;
    }
    const sIcon = sCommand == "CopyFiles" ? "R_Dis_Arr_Fill" :
        sCommand == "MoveFiles" ? "R_Dis_Arr_Nofl" :
            sCommand == "DeleteFiles" ? "delete" :
                sCommand == "RenameFile" ? "rename" : "open_link";
    const oConfirm = CreateFloatMenu(js, { width: "600px", top: y + "px", left: x + "px" }, null, {
        icon: sIcon, bNoModal: true, fToMinScreen: () => {
            _ShortFileOpInfo(sCommand, oConfirm, null, GetPathForShow(sPath), GetPathForShow(sPathFrom));
        }
    });
    oConfirm.oMenu.fToMinScreen();
    oConfirm.promise.catch(() => { });
    return oConfirm.oMenu;
}
async function MakeFolderRequest(sfPathAndName, oBDE, sFolderName) {
    try {
        const oMakeFolderResp = await RequestWithReconnect("MakeFolder", { "path": sfPathAndName }, oBDE);
        if (!oBDE.Branch || !oBDE.DTP)
            return;
        if (oBDE.Branch.folder == FOLDER_OPEN) {
            oMakeFolderResp.info.sNameA = sFolderName;
            const oNewBranch = AddNewFolder(oBDE, sfPathAndName, sFolderName, oMakeFolderResp.info);
            if (oNewBranch) {
                oNewBranch.fMarkAndShow(oBDE.DTP);
                TableRowClick(oBDE.DTP, oNewBranch, true);
            }
        }
        else {
            oBDE.Branch.fClear();
            oBDE.Branch.folder = FOLDER_OPEN;
            await RefreshBrowseBranch("", oBDE);
            const oNewBranch = oBDE.Branch.fFindEl(sFolderName, "display_name");
            if (oNewBranch) {
                oNewBranch.fMarkAndShow(oBDE.DTP);
                TableRowClick(oBDE.DTP, oNewBranch, true);
            }
        }
    }
    catch (oErr) {
        CatchErrProcess(oErr, "", { sErrType: "MakeFolder response:", eGoal: "both" });
    }
}
