/*
 *
 *      記事編集画面用 フロントエンド処理
 *  
 */

//プレビュー並び替え中フラグ
previewMoved = false;

document.addEventListener("DOMContentLoaded", async () => {

    //画像右クリック時のコンテキストメニュー編集
    const contents = [
        {
            type: "item",
            label: "コメント編集",
            callback: (trigger) => {
                let e = { target: trigger };
                editImageComment(e);
            }
        },
        {
            type: "item",
            label: "画像編集",
            callback: (trigger) => {
                editImage(trigger.parentElement, 1);
            }
        },
        {
            type: "item",
            label: "複製して画像編集",
            callback: (tritter) => {
                editImage(trigger.parentElement, 2);
            }
        },
        {
            type: "item",
            label: "この画像からサムネイル作成",
            callback: (trigger) => {
                editImage(trigger.parentElement, 0);

            }
        },
        {
            type: "item",
            label: "記事に挿入",
            callback: (trigger) => {
                var field = Q('#contents');
                var items = QA('.preview_item_image');
                var index = Array.prototype.indexOf.call(items, trigger) + 1;
                insertAtCursor(field, `{${index}}`);
            }
        },
        {
            type: "item",
            label: "画像を削除",
            callback: (trigger) => {
                addRemoveImageList({ target: trigger });
                setUnloadCheck();
            }
        }
    ];
    const context = new Context("#preview_area", contents);
    context.filterTargetClass = "preview_item_image";

    //保存ボタン
    Q("#submit").addEventListener("click", async (e) => {
        e.preventDefault();
        await save();
    });
    Q("#submit2").addEventListener("click", async (e) => {
        e.preventDefault();
        await save();
    });


    //時刻リロードボタン
    const timeReloadBtn = Q("#time_reload");
    if (timeReloadBtn) {
        timeReloadBtn.addEventListener("click", (e) => {
            e.preventDefault();
            const now = new Date();
            const formatted = now.getFullYear() + '-' +
                String(now.getMonth() + 1).padStart(2, '0') + '-' +
                String(now.getDate()).padStart(2, '0') + ' ' +
                String(now.getHours()).padStart(2, '0') + ':' +
                String(now.getMinutes()).padStart(2, '0') + ':' +
                String(now.getSeconds()).padStart(2, '0');
            Q("#created_at").value = formatted;
            setUnloadCheck();
        });
    }

    //削除ボタン
    const deleteBtn = Q("#delete");
    if (deleteBtn) {
        deleteBtn.addEventListener("click", async (e) => {
            e.preventDefault();
            const dialog = new PppDialog();
            const result = await dialog.openConfirm({
                title: "記事の削除",
                message: "この記事を削除しますか？<br>この操作は取り消せません。",
                okText: "削除",
                cancelText: "キャンセル"
            });
            if (result.action === "ok") {
                const articleId = Q("#id").value;
                const csrfToken = Q("#csrf_token").value;
                try {
                    let headers = new Headers();
                    headers.append("X-CSRF-TOKEN", document.getElementById("csrf_token").value);

                    console.log(`${BASE_URL}/api/v2/articles/${id}`);
                    const response = await fetch(`${BASE_URL}/api/v2/articles/${articleId}`, {
                        method: 'DELETE',
                        headers: headers,
                    });

                    if (!response.ok) {
                        throw new Error('Network response was not ok');
                    }

                    if (response.ok) {
                        window.location.href = `${BASE_URL}/console/articles`;
                    } else {
                        const errDialog = new PppDialog();
                        await errDialog.openAlert({
                            title: "エラー",
                            message: "削除に失敗しました"
                        });
                    }
                } catch (error) {
                    console.error("Delete error:", error);
                    const errDialog = new PppDialog();
                    await errDialog.openAlert({
                        title: "エラー",
                        message: "削除に失敗しました"
                    });
                }
            }
        });
    }

    //ファイルドラッグエリア
    QA('.drop-zone').forEach(dropArea => {
        dropArea.addEventListener('dragover', dragOver);
        dropArea.addEventListener('dragleave', dragLeave);
        dropArea.addEventListener('drop', drop);
        dropArea.addEventListener('click', function () {
            Q("#file_select").click();
        });
    });

    //ファイル選択時処理
    Q("#file_select").addEventListener('change', async function (e) {
        Q("#drop_area").classList.add('hide');
        Q("#preview_area").classList.remove('hide');
        //let dialog = waitDialog('<img src="./resource/loading.gif"><br>処理中…');
        await createPreview(e.target.files);
        //dialog.close();
        e.target.files = null; //このファイル選択欄は選択専用のためNULL値セット
    });

    //クリップボードから画像ペースト処理
    document.addEventListener('paste', async function (e) {
        var items = e.clipboardData.items;
        for (var i = 0; i < items.length; i++) {
            if (items[i].type.indexOf('image') !== -1) {
                var blob = items[i].getAsFile();
                await createPreview([blob]);
                Q("#drop_area").classList.add('hide');
                Q("#preview_area").classList.remove('hide');
            }
        }
    });

    //テキストドラッグエリア
    QA('.text_drop_area').forEach(textDropArea => {
        textDropArea.addEventListener('drop', dropText);
    });

    //テキストエリアへのテキストファイルドロップ対応
    const contentsTextarea = Q("#contents");
    if (contentsTextarea) {
        contentsTextarea.addEventListener('dragover', (e) => {
            // テキストファイルの場合のみドロップを許可
            if (e.dataTransfer.types.includes('Files')) {
                e.preventDefault();
                e.stopPropagation();
                contentsTextarea.classList.add('textarea-dragover');
            }
        });
        contentsTextarea.addEventListener('dragleave', (e) => {
            e.preventDefault();
            contentsTextarea.classList.remove('textarea-dragover');
        });
        contentsTextarea.addEventListener('drop', async (e) => {
            e.preventDefault();
            e.stopPropagation();
            contentsTextarea.classList.remove('textarea-dragover');

            const files = e.dataTransfer.files;
            for (let i = 0; i < files.length; i++) {
                const file = files[i];
                if (file.type.startsWith('text/') ||
                    file.name.endsWith('.txt') ||
                    file.name.endsWith('.md') ||
                    file.name.endsWith('.html') ||
                    file.name.endsWith('.css') ||
                    file.name.endsWith('.js') ||
                    file.name.endsWith('.json') ||
                    file.name.endsWith('.xml') ||
                    file.name.endsWith('.csv')) {
                    await uploadText(file);
                }
            }
        });
    }

    //プレビューアイテムにファイルドラッグの受け入れとスマホ用ボタン追加
    QA(".preview_item").forEach(item => {
        item.addEventListener('dragover', dragOver);
        item.addEventListener('dragleave', dragLeave);
        item.addEventListener('drop', drop);

        if (('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0)) {
            const rightLink = createElement('i', { class: 'fa-regular fa-circle-right mover' });

            rightLink.addEventListener('click', () => moveRight(li));
            item.append(rightLink);

            const leftLink = createElement('i', { class: 'fa-regular fa-circle-left movel' });
            leftLink.addEventListener('click', () => moveLeft(li));
            item.append(leftLink);

            const ctm = createElement('i', { class: 'fa-solid fa-bars contextmenubutton', style: 'inline-block' });
            ctm.addEventListener('click', function (e) {
                e.preventDefault();
                // 独自のコンテキストメニューを表示
                console.log(e.target);
                context.manualOpen(e);

            });
            item.append(ctm);
        }
    });

    //D&Dによるプレビューの順序入れ替えに対応する
    const sortElement = document.getElementById('preview_list');
    Sortable.create(sortElement, {
        ghostClass: 'ghost',
        animation: 200,
        forceAutoScrollFallback: true,
        direction: 'horizontal',
        filter: "#drop_area2_root",
        forceFallback: true,
        preventOnFilter: false,
        onStart: function (evt) {
            previewMoved = true;
        },
        onEnd: function (evt) {
            previewMoved = false;
        },
    });

    //画像編集の確定ボタン
    Q("#image_edit_accept").addEventListener('click', async () => {
        await acceptImageEdit();
    });

    //Ctrl + Sによる保存に対応
    document.addEventListener("keydown", function (e) {
        if (e.ctrlKey && (e.key == "s")) {
            e.preventDefault();
            Q('#submit').click();
        }
    });

    //コマンドパレット
    Q("#show_command_palette").addEventListener('click', function (e) {
        e.preventDefault();
        var palette_wait = window.waitDialog(Q('.command_palette').innerHTML);
        QA(".dialog_box .insert_item").forEach(item => {
            item.addEventListener('click', function (e) {
                var myField = document.getElementById('contents');
                var myValue = this.innerText;
                insertAtCursor(myField, myValue);
                palette_wait.close();
            });
        });
        Q(".dialog_box .command_palette_close").addEventListener('click', function () {
            console.log(Q(".command_palette_close").innerHTML);
            palette_wait.close();
        });


    });
    function insertAtCursor(myField, myValue) {
        // IE support
        if (document.selection) {
            myField.focus();
            sel = document.selection.createRange();
            sel.text = myValue;
        }
        // MOZILLA/NETSCAPE support
        else if (myField.selectionStart || myField.selectionStart == '0') {
            var startPos = myField.selectionStart;
            var endPos = myField.selectionEnd;
            myField.value = myField.value.substring(0, startPos)
                + myValue
                + myField.value.substring(endPos, myField.value.length);
        } else {
            myField.value += myValue;
        }
        // シンタックスハイライトを更新
        if (window.updateSyntaxHighlight) {
            window.updateSyntaxHighlight(myField.id);
        }
    }

    //ファイルドラッグエリア
    QA('.tag').forEach(tag => {
        tag.addEventListener('click', function () {
            let tagString = tag.innerText.replace("#", "");
            if (!Q("#tags").value.includes(tagString)) {
                Q("#tags").value += (Q("#tags").value ? " " : "") + tagString;
            }

        });
    });
});

// ドラッグ&ドロップエリア イベント
function dragOver(e) {
    if (previewMoved) {
        return;
    }

    e.stopPropagation();
    e.preventDefault();
    this.classList.add("dragover");
}

function dragLeave(e) {
    if (previewMoved) {
        return;
    }

    e.stopPropagation();
    e.preventDefault();
    this.classList.remove("dragover");
    this.style.border = "";
}

async function drop(e) {
    if (previewMoved) {
        return;
    }
    console.log(e);
    e.preventDefault();
    document.getElementById("drop_area").classList.add("hide");
    document.getElementById("preview_area").classList.remove("hide");
    //let dialog = waitDialog(`<img src="${SITE_URL}/resource/loading.gif"><br>処理中…`);
    this.classList.remove("dragover");
    if (this.classList.contains("drop-zone")) {
        await createPreview(e.dataTransfer.files);
    } else {
        await createPreview(e.dataTransfer.files, this);
    }
    //dialog.close();

}

async function dropText(e) {
    e.preventDefault();
    document.getElementById("drop_area").classList.add("hide");
    document.getElementById("preview_area").classList.remove("hide");
    this.style.border = "";
    //let dialog = waitDialog(`<img src="${SITE_URL}/resource/loading.gif"><br>処理中…`);
    await createPreview(e.dataTransfer.files);
    dialog.close();
}

//ドラッグ or 選択されたファイルのプレビュー生成
async function createPreview(files, insertTarget = null) {
    setUnloadCheck();
    for (let i = 0; i < files.length; i++) {
        let file = files[i];
        if (file.type.startsWith('image/')) {
            //画像
            await createImagePreview(file, insertTarget);
        } else if (file.type.startsWith('video/')) {
            //動画
            await createMoviePreview(file, insertTarget);
        } else if (file.type.startsWith('text/')) {
            await uploadText(file);
        }
    }
}

//テキストファイルの内容をテキストエリアに挿入
async function uploadText(file) {
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onload = (event) => {
            const textContent = event.target.result;
            const textarea = Q("#contents");

            if (textarea) {
                // カーソル位置に挿入
                if (textarea.selectionStart !== undefined) {
                    const startPos = textarea.selectionStart;
                    const endPos = textarea.selectionEnd;
                    const beforeText = textarea.value.substring(0, startPos);
                    const afterText = textarea.value.substring(endPos);
                    textarea.value = beforeText + textContent + afterText;
                    // カーソルを挿入したテキストの後ろに移動
                    const newPos = startPos + textContent.length;
                    textarea.setSelectionRange(newPos, newPos);
                } else {
                    // カーソル位置が不明な場合は末尾に追加
                    textarea.value += textContent;
                }

                // シンタックスハイライトを更新
                if (window.updateSyntaxHighlight) {
                    window.updateSyntaxHighlight(textarea.id);
                }

                setUnloadCheck();
            }
            resolve();
        };
        reader.onerror = () => {
            console.error("テキストファイルの読み込みに失敗しました");
            reject(reader.error);
        };
        reader.readAsText(file);
    });
}

//ファイルリード処理
function fileRead(file) {
    const promise = new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onload = (event) => {
            resolve(event);
        }
        reader.readAsDataURL(file);
    });
    return promise;
}

//イメージリード処理
function imageRead(buffer) {
    const promise = new Promise((resolve, reject) => {
        const image = new Image();
        image.onload = (event) => {
            resolve(event)
        }
        image.targetFile = buffer.target;
        image.src = buffer.target.result;
    });
    return promise;
}

//EXIF取得
function exifRead(image) {
    const promise = new Promise((resolve, reject) => {
        EXIF.getData(image, function () {
            var exifData = EXIF.getAllTags(this);
            var result = {};
            //Exifライブラリのバグ対応
            if ("undefined" in exifData && !("Lens" in exifData)) {
                exifData["Lens"] = exifData["undefined"];
            }

            //露出時間から1/n表記取得
            if ("ExposureTime" in exifData) {
                if (exifData["ExposureTime"] > 1) {
                    exifData["SS"] = exifData["ExposureTime"] + "sec";
                }
                else {
                    exifData["SS"] = "1/" + (1 / exifData["ExposureTime"]);
                }
            }
            result.image = image;
            result.exif = exifData;

            resolve(result);
        });
    });
    return promise;
}

function formatExif(exifData) {
    return replaceVariables(EXIF_TEMPLATE, exifData);
}

// 正規表現を使用して%～%で囲まれた変数名を抽出
function replaceVariables(input, values) {
    return input.replace(/%\w+%/g, match => {
        const variableName = match.slice(1, -1);
        return values[variableName] !== undefined ? values[variableName] : '---';
    });
}

function createElement(tag, attributes = {}) {
    const element = document.createElement(tag);

    for (const [key, value] of Object.entries(attributes)) {
        element.setAttribute(key, value);
    }
    return element;
};

async function createImagePreview(file, insertTarget = null) {
    const input = createElement('input', { type: 'file', class: 'hide upload_images', name: 'images[]' });
    const li = createElement('li', { class: 'preview_item', 'data-filename': file.name, 'draggable': 'false' });
    const img = createElement('img', { 'draggable': 'false', class: 'preview_item_image', id: `preview-${file.name}`, onmouseup: 'imageTap(event)', ontouchend: 'imageTap(event)' });
    const comment = createElement('input', { type: 'hidden', class: 'image_comment', name: 'image_comments[]', value: '' });
    const sort = createElement('input', { type: 'hidden', class: 'image_sort', name: 'image_sort[]', value: '' });
    const deleteLink = createElement('button', { class: 'delete_button' });
    deleteLink.textContent = '×';
    deleteLink.addEventListener('click', (e) => { e.preventDefault(); li.remove(); });


    li.addEventListener('dragover', dragOver);
    li.addEventListener('dragleave', dragLeave);
    li.addEventListener('drop', drop);

    li.append(img, deleteLink, input, comment, sort);

    if (('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0)) {
        const rightLink = createElement('i', { class: 'fa-regular fa-circle-rightmover' });
        rightLink.addEventListener('click', () => moveRight(li));
        li.append(rightLink);

        const leftLink = createElement('i', { class: 'fa-regular fa-circle-leftmovel' });
        leftLink.addEventListener('click', () => moveLeft(li));
        li.append(leftLink);
    }

    if (insertTarget) {
        insertTarget.before(li);
    } else {
        document.getElementById('drop_area2_root').before(li);
    }

    const result = await fileRead(file)
        .then(result => imageRead(result))
        .then(result => exifRead(result.target));

    if (result.exif?.Model) {
        comment.value = formatExif(result.exif);
    }

    const readingImg = result.image;
    let width, height;
    const maxSize = 0;

    if (maxSize !== 0 && (readingImg.width > maxSize || readingImg.height > maxSize)) {
        const ratio = readingImg.width > readingImg.height
            ? readingImg.height / readingImg.width
            : readingImg.width / readingImg.height;

        width = readingImg.width > readingImg.height ? maxSize : maxSize * ratio;
        height = readingImg.width > readingImg.height ? maxSize * ratio : maxSize;

        const canvas = document.createElement('canvas');
        canvas.width = width;
        canvas.height = height;
        const ctx = canvas.getContext('2d', { preserveDrawingBuffer: true });
        ctx.clearRect(0, 0, width, height);
        ctx.drawImage(readingImg, 0, 0, readingImg.width, readingImg.height, 0, 0, width, height);

        const base64 = canvas.toDataURL('image/jpeg');
        const bin = atob(base64.split('base64,')[1]);
        const barr = new Uint8Array(bin.length);
        for (let i = 0; i < bin.length; i++) {
            barr[i] = bin.charCodeAt(i);
        }

        const blob = new Blob([barr], { type: 'image/jpeg' });
        const nfile = new File([blob], file.name);
        const dt = new DataTransfer();
        dt.items.add(nfile);
        input.files = dt.files;
        input.dataset.filesize = nfile.size;

        console.log(`client resize: ${file.name}`);
        img.src = base64;
    } else {
        input.dataset.filesize = file.size;
        const dt = new DataTransfer();
        dt.items.add(file);
        input.files = dt.files;
        img.src = readingImg.src;
    }
}


// 非同期記事送信本体
async function postArticleBody(editMode, formData) {

    let url = `${BASE_URL}/api/v2/articles`;
    let method = "POST";
    if (GUEST_MODE) {
        url = `${BASE_URL}/api/v2/articles/guest`;
    }
    if (editMode) {
        url = url + '/' + formData.get('id');
        method = "POST"; //本来PATCHだが現時点ではPOSTを使用する
    }
    formData.append('csrf_token', document.getElementById("csrf_token").value);

    try {
        const response = await fetch(url, {
            method: method,
            body: formData
        });
        if (!response.ok) {
            throw new Error("Network response was not ok");
        }

        return await response.json();
    } catch (error) {

        console.error("Error:", error);
        throw error;
    }
}

//画像個別送信
async function asyncPostMedia(article_id, waitDialog, files, moviefiles, moviePreviews, use_rnd) {
    const totalCount = files.length + moviefiles.length;

    for (let i = 0; i < files.length; i++) {
        let fileData = files[i].files[0];
        let comment = findSiblingsWithClass(files[i], ".image_comment").value;
        let sort = findSiblingsWithClass(files[i], ".image_sort").value;
        console.log(comment, sort);
        if (fileData) {
            //waitDialog.update(`<div><img src="${SITE_URL}/resource/loading.gif" width=32 height=32><br>送信中… <br>${i} / ${totalCount}</div>`);
            let newFile = await postImageFile(article_id, sort, fileData, comment, use_rnd);
        }
    }

    for (let i = 0; i < moviefiles.length; i++) {
        let fileData = moviefiles[i].files[0];
        let previewData = moviePreviews[i].files[0];
        let comment = findSiblingsWithClass(movefiles[i], ".image_comment").value;
        let sort = findSiblingsWithClass(files[i], ".image_sort").value;
        if (fileData) {
            //waitDialog.update(`<div><img src="${SITE_URL}/resource/loading.gif" width=32 height=32><br>送信中… <br>${(i + files.length)} / ${totalCount}</div>`);
            let newFile = await postMovieFile(article_id, sort, fileData, previewData, comment, use_rnd);
        }
    }
}

//非同期 動画送信
async function postMovieFile(id, index, file, preview, comment, use_rnd) {
    let url = `${BASE_URL}/api/v2/articles/${id}/media`;

    let formData = new FormData();
    formData.append("movies[]", file);
    formData.append("movie_previews[]", preview);
    formData.append("image_comments[]", comment);
    formData.append("id", id);
    formData.append("image_sort[]", index);
    formData.append("use_rnd", use_rnd);
    formData.append('csrf_token', document.getElementById("csrf_token").value);

    try {
        const response = await fetch(url, {
            method: "POST",
            body: formData
        });
        if (!response.ok) {
            throw new Error("Network response was not ok");
        }

        return await response.json();

    } catch (error) {
        console.error("Error:", error);
        throw error;
    }
}
// 非同期 個別画像送信
async function postImageFile(id, sort, file, comment, use_rnd) {

    let url = `${BASE_URL}/api/v2/articles/${id}/media`;
    let formData = new FormData();
    formData.append("images[]", file);
    formData.append("image_comments[]", comment);
    formData.append("id", id);
    formData.append("image_sort[]", sort);
    formData.append("use_rnd", use_rnd);
    formData.append('csrf_token', document.getElementById("csrf_token").value);

    try {
        const response = await fetch(url, {
            method: "POST",
            body: formData
        });
        if (!response.ok) {
            throw new Error("Network response was not ok");
        }

        return await response.json();
    } catch (error) {
        console.error("Error:", error);
        throw error;
    }
}


// 保存ボタン押下時処理
async function save() {

    //内容確認
    validateMsg = validate();
    if (validateMsg != "") {
        await showDialog(validateMsg);
        return;
    }

    //新規モード or 更新モード分岐
    let msgTitle = "更新";
    let editMode = true;
    if (Q("#id").value === undefined || Q("#id").value == "") {
        msgTitle = "投稿";
        editMode = 0;
    }

    //処理中ダイアログを表示
    let dialog = new PppDialog();
    let waitDialog = dialog.openAlert({ message: `<div style="display: grid;place-content: center; place-items: center;"><img src=\"${SITE_URL}/system_resource/loading.gif\"  width=32 height=32><p>処理中…</p></div>`, noButtons: true });

    //ソート情報を入力
    idx = 1;
    sorts = QA(".image_sort");
    sorts.forEach(element => {
        element.value = idx++;
    });

    //投稿を実行
    try {
        const articleData = await postData(editMode, waitDialog);

        //完了メッセージ表示
        await showSuccessMessage(articleData, msgTitle);

        dialog.close();
        unsetUnloadCheck();
        if (msgTitle === '投稿' || articleData.newMedia) {
            //新規投稿時またはメディア追加時は画面をリフレッシュして編集モードへ移行
            if (GUEST_MODE) {
                location.href = `${BASE_URL}/guest_edit/${articleData.id}?delete_key=` + encodeURIComponent(Q("#delete_key").value);
            }
            else {
                location.href = `${BASE_URL}/edit/${articleData.id}`;
            }
        }

        //削除一覧をクリア
        Q("#remove_files").value = "";

    }
    catch (ex) {
        dialog.close();
        console.log(ex);
        let dialogText = `<p>${msgTitle}に失敗しました</p>`;
        await showDialog(dialogText, "OK");
        return;
    }
    finally {
        Qunloadcheck_suppression = false;
    }


}

function validate() {
    //ゲストモード時確認処理(guestModeはhtml側で定義される)
    if (GUEST_MODE) {
        deleteKey = Q("#delete_key").value.trim();
        if (deleteKey == "") {
            return "削除キーを指定してください";
        }
        Q("#delete_key").value = deleteKey;
    }

    //投稿日時の確認
    let datestring = Q("#created_at").value;
    if (datestring != "") {
        let date1 = new Date(datestring.replace(/-/g, "/"));
        let date2 = new Date(datestring);
        if (isNaN(date1.getDate()) && isNaN(date2.getDate())) {
            //投稿日時が正しくない
            return "投稿日時を正しく入力してください";
        }
    }

    //代替URLの確認
    let altUrl = Q("#alt_url").value.trim();
    if (altUrl.length > 0) {
        if (altUrl.endsWith("/")) {
            altUrl = altUrl.slice(0, -1);
        };
        if (altUrl.startsWith("/")) {
            altUrl = altUrl.slice(1);
        };
        Q("#alt_url").value = altUrl;

        if (altUrl != "") {
            if (altUrl.toLowerCase().indexOf("api/") >= 0) {
                return "api/から始まる固定URLは使用できません";
            }

            if (altUrl == "log") {
                return "logは固定URLとして使用できません";

            }

            let pattern = /^log\/\d+(\/.*)?Q/;
            if (pattern.test(alt_url)) {
                return "log/(数字)から始まる固定URLは使用できません";
            }
        }
    }

    //入力の確認
    const files = QA(".upload_images");
    const movies = QA(".upload_movies");
    const previewFiles = QA(".preview_item_image");
    const previewMovies = QA(".preview_item_movies");

    if (Q("#contents").value.trim() == ""
        && files.length == 0 && movies.length == 0
        && previewFiles.length == 0 && previewMovies.length == 0) {
        //空
        return "内容を入力してください";
    }

    return "";
}

async function postData(editMode, waitDialog) {

    //未入力値の変換
    if (Q("#title").value == "") {
        Q("#title").value = "無題";
    }

    //ファイルアップロード準備
    const files = QA(".upload_images");
    const movies = QA(".upload_movies");
    const moviePreviews = QA(".upload_movie_previews");

    //合計画像ファイルサイズからアップロードモードを確定
    const NORMAL_MODE = 0;
    const ASYNC_MODE = 1;

    let totalFileSize = 0;
    let uploadMode = NORMAL_MODE;
    if ((movies.length > 0 || files.length > 3) && !GUEST_MODE) {
        //動画を含むか、4枚以上は非同期送信(guestモードの時は同期送信のみ)
        uploadMode = ASYNC_MODE;
    }
    else {
        //容量計算を行い、サーバーのアップロード限界の9割を超えている場合は非同期送信とする
        files.forEach(function (item) {
            let fileSize = parseInt(item.files[0].fileSize);
            fileSize = 1;
            totalFileSize += fileSize;
        });
        if (totalFileSize > (Q("#file_select").dataset.maxsize * 0.9)) {
            uploadMode = ASYNC_MODE;
        }
    }
    let newMedia = false;
    if (files.length > 0 || movies.length > 0) {
        newMedia = true;
    }

    //送信準備
    let formData = new FormData(Q("#inputForm"));
    if (uploadMode == ASYNC_MODE) {
        //非同期送信モードでは画像アップロードは別処理とするため
        //フォームデータからファイル類を削除
        formData.delete("images[]");
    }

    //動画は常に別アップロードのためいったん削除
    formData.delete("movies[]");
    formData.delete("movie_previews[]");

    //WAF対策のため本文をBASE64エンコード
    const comment = Q("#contents").value ?? "";
    formData.set("contents", base64Encoding(comment));

    //ファイルのランダム化をするか。本文に{password}コマンドが含まれている場合はランダム化する。
    let useRnd = false;
    if (comment.indexOf("{password") >= 0 || USE_RND_FILENAME) {
        useRnd = true;
    }

    //本文の投稿を実行
    const postResult = await postArticleBody(editMode, formData);
    console.log(postResult);
    if (postResult.status != "success") {
        throw new Error(postResult.message);
    }
    const lastImageIndex = postResult.last_image_index; //最後の画像番号
    if (uploadMode == ASYNC_MODE) {
        //非同期画像送信
        await asyncPostMedia(postResult.id, waitDialog, files, movies, moviePreviews, useRnd);
    }
    unloadcheckSuppression = true;
    postResult.article_data.newMedia = newMedia; //新規メディアがあるかどうかの情報を記録
    return postResult.article_data;
}

function base64Encoding(str) {
    const bytes = new TextEncoder().encode(str);
    let binary = '';
    const chunkSize = 0x8000; // 32KB 程度

    for (let i = 0; i < bytes.length; i += chunkSize) {
        binary += String.fromCharCode(...bytes.slice(i, i + chunkSize));
    }

    return btoa(binary);
}

async function showSuccessMessage(articleData, msgtitle) {
    //Shereリンク生成
    let twitterintent = "";
    let dialogText = "";
    console.log(articleData);
    const mediaCount = articleData.media_count;
    var sharelinkHtml = "";
    for (var i = 0; i < SHARE_TEMPLATES.length; i++) {
        var snsUrl = SHARE_TEMPLATES[i].action;
        if (USE_CLIPBOARD && !GUEST_MODE && mediaCount > 0) {
            const clickAction = ` onClick='event.preventDefault();openURLWithClipboardCopy("${SITE_URL}/images/${articleData.media[0].sub_dir}${articleData.media[0].thumb_l_name}", "${snsUrl}");return false;'`;
            sharelinkHtml += `<a href="#" id="share_link_${i}" data-url="${snsUrl}">${SHARE_TEMPLATES[i].title}で共有</a><br>`;
        }
        else {
            sharelinkHtml += `<a target="_blank" href="${snsUrl}">${SHARE_TEMPLATES[i].title}で共有</a><br>`;
        }
    }
    sharelinkHtml = sharelinkHtml.replace(/%title%/g, Q("#title").value.replace(/<("[^"]*"|'[^']*'|[^'">])*>/g, ''));
    sharelinkHtml = sharelinkHtml.replace(/%site_title%/g, SITE_TITLE.replace(/<("[^"]*"|'[^']*'|[^'">])*>/g, ''));
    sharelinkHtml = sharelinkHtml.replace(/%url%/g, encodeURIComponent(SITE_URL + articleData.url));


    //通常モード
    dialogText = `<div style="text-align: center;"><p style="margin:3em">${msgtitle}しました！</p><a href="${SITE_URL}${articleData.url}" target="ppp_check">記事を確認</a>${sharelinkHtml}</div>`;
    result = await showDialog(dialogText, "", "OK");
    if (result === "OK") {
        if (USE_CLIPBOARD && !GUEST_MODE && mediaCount > 0) {
            for (var i = 0; i < SHARE_TEMPLATES.length; i++) {
                Q(`#share_link_${i}`).addEventListener("click", function (e) {
                    e.preventDefault();
                    openURLWithClipboardCopy(articleData, this.dataset.url);
                    return false;
                });
            }
        }
    };
}


async function openURLWithClipboardCopy(articleData, url) {
    const img = new Image();
    try {
        // 画像ありの記事の場合はthmub_lサイズの画像をクリップボードにコピーしてURLを開く
        const imageUrl = SITE_URL + "/images/" + articleData.media[0].sub_dir + articleData.media[0].thumb_l_name;
        img.onload = async function () {
            const canvas = document.createElement('canvas');
            canvas.width = articleData.media[0].thumb_l_width;
            canvas.height = articleData.media[0].thumb_l_height;
            const ctx = canvas.getContext('2d');
            ctx.drawImage(img, 0, 0);
            canvas.toBlob(async (blob) => {
                const item = new ClipboardItem({ 'image/png': blob });
                await navigator.clipboard.write([item]);
                await new Promise(resolve => setTimeout(resolve, 500));
                window.open(url, "_blank");
            });
        };
        img.src = imageUrl;

    } catch (error) {
        window.open(url, "_blank");
    }
}


async function showShareMessageWithAPI(articleData, msgtitle, sharelinkHtml) {

}

function addRemoveImageList(event) {
    target = event.target.parentNode;
    Q("#remove_files").value = Q("#remove_files").value + target.dataset.filename + ";";
    target.remove();
}


let unloadcheckSuppression = false;

function setUnloadCheck() {
    if (!unloadcheckSuppression) {
        console.log("set");
        window.removeEventListener('beforeunload', handleBeforeUnload);
        window.addEventListener('beforeunload', handleBeforeUnload);
    }
}

function unsetUnloadCheck() {
    console.log("unset");
    window.removeEventListener('beforeunload', handleBeforeUnload);
}

function handleBeforeUnload(event) {
    event.preventDefault();
    event.returnValue = "ページを移動しようとしています。\n入力した内容が失われますがよろしいですか？";
}

function insertAtCursor(myField, myValue) {
    // IE support
    if (document.selection) {
        myField.focus();
        sel = document.selection.createRange();
        sel.text = myValue;
    }
    // MOZILLA/NETSCAPE support
    else if (myField.selectionStart || myField.selectionStart == '0') {
        var startPos = myField.selectionStart;
        var endPos = myField.selectionEnd;
        myField.value = myField.value.substring(0, startPos)
            + myValue
            + myField.value.substring(endPos, myField.value.length);
    } else {
        myField.value += myValue;
    }
    // シンタックスハイライトを更新
    if (window.updateSyntaxHighlight) {
        window.updateSyntaxHighlight(myField.id);
    }
}
function findSiblingsWithClass(element, className) {
    return element.parentElement.querySelectorAll(className)[0];
}


//画像コメント・編集関連操作
//イメージコメントの編集
async function editImageComment(e) {
    const parent = e.target.parentElement;
    const commentInput = parent.querySelectorAll(".image_comment")[0];

    const dialog = new PppDialog();
    const result = await dialog.openPrompt({
        title: "コメント編集",
        message: "画像のコメントを入力してください",
        defaultValue: commentInput.value,
        placeholder: "コメントを入力...",
        okText: "OK",
        cancelText: "キャンセル",
        multiline: true
    });

    if (result.action === "ok") {
        commentInput.value = result.value;
        setUnloadCheck();
    }
}


//画像編集
let $imageEditor = null;
async function editImage(target_li, mode) {

    const li = target_li;
    let file;

    if (li.dataset.hasOwnProperty('id')) {
        file = await urlToFile(SITE_URL + "/images/" + li.dataset.subdir + li.dataset.filename, li.dataset.filename);
    } else {
        file = li.querySelector(".upload_images").files[0];

    }

    if (!$imageEditor) {
        console.log(window.innerWidth * 0.8, window.innerHeight * 0.7);
        $imageEditor = await new ImageEditor(
            file,
            'temperatureInput',
            'tintInput',
            'brightnessInput',
            'canvas',
            window.innerWidth * 0.7,
            window.innerHeight * 0.7
        );
    } else {
        await $imageEditor.editImage(
            file,
            window.innerWidth * 0.7,
            window.innerHeight * 0.7
        );
    }

    $imageEditor.target = li;
    $imageEditor.fileName = file.name;
    $imageEditor.mode = mode;

    if (mode === 1) {
        document.querySelector(".image_edit_title").textContent = "-画像編集-";
        document.getElementById("image_edit_accept").textContent = "上書き保存";
    } else if (mode === 2) {
        document.querySelector(".image_edit_title").textContent = "-画像編集(複製)-";
        document.getElementById("image_edit_accept").textContent = "保存";
    } else {
        document.querySelector(".image_edit_title").textContent = "-サムネイル作成-";
        document.getElementById("image_edit_accept").textContent = "保存";
    }

    document.body.style.overflow = "hidden";
    document.querySelector(".image_edit_overlay").classList.remove("hide");

    const imageEditContents = document.querySelector(".image_edit_contents");
    imageEditContents.scrollLeft = 0;
    imageEditContents.scrollTop = 0;

    return;
}

async function acceptImageEdit() {

    if ($imageEditor.mode == 1 && $imageEditor.isEdit() == false) {
        cancelImageEdit();
        return;
    }
    const base64 = $imageEditor.getResultImage();

    const [dataTransfer, newFile] = base64ToFile(base64, $imageEditor.fileName + ".jpg");

    const comment = $imageEditor.target.querySelector(".image_comment").value;
    if ($imageEditor.mode === 1 || $imageEditor.mode === 2) {
        await createImagePreview(newFile, $imageEditor.target, comment);
        if ($imageEditor.mode === 1) {
            addRemoveImageList($imageEditor.target.dataset.id);
            $imageEditor.target.remove();
        }
    } else {
        //先頭に追加
        await createImagePreview(newFile, document.querySelector(".preview_item"));
        document.getElementById("thumbnail").value = "@user_thumbnail";
    }
    document.querySelector(".image_edit_overlay").classList.add("hide");
    document.body.style.overflow = "scroll";
}
function cancelImageEdit() {
    document.querySelector(".image_edit_overlay").classList.add("hide");
    document.body.style.overflow = "scroll";
}
async function urlToFile(url, fileName) {
    const response = await fetch(url);
    const blob = await response.blob();
    const file = new File([blob], fileName, { type: blob.type });
    return file;
}

function createFile(readingImg, width, height, fileName) {
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext('2d', { preserveDrawingBuffer: true });
    ctx.clearRect(0, 0, width, height);
    ctx.drawImage(readingImg, 0, 0, readingImg.width, readingImg.height, 0, 0, width, height);
    const base64 = canvas.toDataURL("image/jpeg");
    const [dataTransfer, newFile] = base64ToFile(base64, fileName);
    return [dataTransfer, newFile, base64];
}

function base64ToFile(base64, fileName) {
    const binary = atob(base64.split(",")[1]);
    const array = Uint8Array.from(binary, char => char.charCodeAt(0));
    const blob = new Blob([array], { type: "image/jpeg" });
    const newFile = new File([blob], fileName);
    const dataTransfer = new DataTransfer();
    dataTransfer.items.add(newFile);

    return [dataTransfer, newFile];
}


//画像ダブルクリックでコメント編集画面表示
let $tapCount = 0;
function imageTap(e) {
    if (e.target.classList.contains("delete_button")) {
        return;
    }
    if ($tapCount == 0) {
        ++$tapCount;
        setTimeout(function () {
            $tapCount = 0;
        }, 500);
    } else {
        e.preventDefault();
        $tapCount = 0;
        editImageComment(e);
    }
}