$(document).ready(function() {
    $("#UpdateButton").on("click", function() {
        let value = RemoveHTML($("#InputText").val()).split("\n");
        let html = [];
        let str = "";
        let creatingList = false;
        for (let _ = 0; _ < value.length; _++) {
            const trimChar = value[_].trim();
            let notAdded = false;
            // Finished creating the list
            if (trimChar[0] != "*" && creatingList) {
                creatingList = false;
                str = str.replaceAll("</ul><ul>", "");
                html.push(str);
                str = "";
            }
            switch (trimChar[0]) {
                // Headings
                case "#":
                    const headingSplit = value[_].split("# ");
                    let headingType = headingSplit[0].trim().length + 1;
                    let headingText = headingSplit[1];
                    if (headingSplit[1] != undefined) {
                        html.push(`<h${headingType}>${headingText}</h${headingType}><hr>`);
                    }
                    else {
                        notAdded = true;
                    }
                    break;
                // Unordered list
                case ">":
                    const listSplit = value[_].split("> ");
                    if (!listSplit[0].trim().split('').every(char => char === ">")) {
                        notAdded = true;
                        break;
                    }
                    let listIndent = listSplit[0].trim().length + 1;
                    if (listSplit[1] == undefined) {
                        notAdded = true;
                        break;
                    }
                    creatingList = true;
                    str += "<ul>";
                    for (let _index = 1; _index < listIndent; _index++) {
                        str += "<ul>";
                    }
                    str += "<li>" + listSplit[1] + "</li>";
                    for (let _index = 0; _index < listIndent; _index++) {
                        str += "</ul>";
                    }
                    break;
                // Table start - <table>
                case "{":
                    if (value[_][1] == "|" && value[_].length == 2) {
                        html.push("<table>");
                        break;
                    }
                    if (value[_][1] == "|" && value[_][2] == " ") {
                        let tableSplit = value[_].split(" style=\"");
                        let tableStyle = "";
                        let tableClasses = "";
                        if (tableSplit.length == 2) {
                            tableStyle = tableSplit[1].split("\"")[0];
                        }
                        tableSplit = value[_].split("borders");
                        if (tableSplit.length == 2) {
                            tableClasses = "borders";
                        }
                        html.push("<table style=\"" + tableStyle + "\" class=\"" + tableClasses + "\">");
                        break;
                    }
                    notAdded = true;
                    break;
                // Table end, cells, rows - </table> <td> <tr>
                case "|":
                    if (value[_][1] == "}" && value[_].length == 2) {
                        html.push("</tr></table>");
                        break;
                    }
                    if (value[_][1] == "|") {
                        const splitCell = value[_].split("|| ");
                        if (splitCell.length == 2) {
                            html.push("<td>" + splitCell[1] + "");
                            break;
                        }
                    }
                    if (value[_][1] == "-" && value[_].length == 2) {
                        html.push("<tr>");
                        break;
                    }
                    notAdded = true;
                    break;
                // Table headers
                case "!":
                    const splitHeader = value[_].split("!! ");
                    if (splitHeader.length == 2) {
                        let headerValues = splitHeader[1].split("} ");
                        if (headerValues.length == 2) {
                            html.push("<th style=\"width: " + headerValues[0].substring(1, headerValues[0].length).split(";")[0] + "\">" + headerValues[1] + "</th>");
                        }
                        else {
                            html.push("<th>" + splitHeader[1] + "</th>");
                        }
                    }
                    else {
                        notAdded = true;
                    }
                    break;
                // Paragraph
                default:
                    html.push("<p>" + value[_] + "</p>");
                    break;
            }
            // Finished creating the list
            if (_ + 1 == value.length && creatingList) {
                creatingList = false;
                str = str.replaceAll("</ul><ul>", "");
                html.push(str);
                str = "";
            }
            // If the value wasn't added, then it gets added as a paragraph
            if (notAdded && !creatingList) {
                html.push("<p>" + value[_] + "</p>");
                creatingList = false;
                str = "";
            }
        }
        $("#OutputHTML").html(FormatText(html));
    });
});

// Function returns formatted text that has converted special characters into HTML tags
function FormatText(html) {
    let completeHTML = "";
    // Replaces ``` with <pre>
    html = ConvertToPreformatted(html);
    for (let _ = 0; _ < html.length; _++) {
        let preparedText = html[_];
        if (!html[_].startsWith("<pre>")) {
            // Bold
            preparedText = ReplaceSymbols(preparedText, "**");
            // Italic
            preparedText = ReplaceSymbols(preparedText, "''");
            // Underlined
            preparedText = ReplaceSymbols(preparedText, "__");
            // Crossed out
            preparedText = ReplaceSymbols(preparedText, "~~");
            // Redacted
            preparedText = ReplaceSymbols(preparedText, "==");
            // Styled
            preparedText = CreateStyledElement(preparedText);
            // Media
            preparedText = CreateMedia(preparedText);
        }
        completeHTML += preparedText;
    }
    return completeHTML.replaceAll("<p></p>", "<br>");
}

// Transforms ```text``` into <pre>text</pre> (preformatted text)
function ConvertToPreformatted(html) {
    let text = "";
    for (let _ = 0; _ < html.length; _++) {
        text += html[_] + "\n";
    }
    let splitText = text.split("```");
    let result = "";
    if (splitText.length > 2) {
        result = splitText[0];
        for (let _ = 1; _ < splitText.length; _ += 2) {
            if (_ + 2 > splitText.length) {
                result += "```" + splitText[_];
                result = result.split("\n");
                result.pop();
                return result;
            }
            if (!splitText[_ - 1].endsWith("\n<p>")) {
                result += "</p>\n";
            }
            else {
                result = result.substring(0, result.length - 3);
            }
            result += "<pre>" + splitText[_].replaceAll("<p>", "<br>").replaceAll("</p>", "").replaceAll("\n", "");
            if (splitText[_ + 1].startsWith("</p>\n")) {
                result += "</pre>" + splitText[_ + 1].replace("</p>\n", "\n");
            }
            else {
                result += "</pre>\n<p>" + splitText[_ + 1];
            }
        }
        result = result.split("\n");
        result.pop();
        return result;
    }
    else {
        return html;
    }
}

// Function returns text line with HTML tags
function ReplaceSymbols(text, tag) {
    let result = "";
    let splitText = text.split(tag);
    let tagName = "p";
    // Selects html tag
    switch (tag) {
        case "**":
            tagName = "b";
            break;
        case "''":
            tagName = "i";
            break;
        case "__":
            tagName = "u";
            break;
        case "~~":
            tagName = "del";
            break;
        case "==":
            tagName = "span";
            break;
    }
    // Replaces special characters with html tags
    for (let _ = 1; _ < splitText.length; _ += 2) {
        if (_ == 1) {
            result += splitText[0];
        }
        if (splitText[_ + 1] != undefined) {
            if (tag == "==") {
                // For redacted
                let giveText = "";
                for (let _index = 0; _index < splitText[_].length; _index++) {
                    giveText += "█";
                }
                result += `<${tagName}>${giveText}</${tagName}>${splitText[_ + 1]}`;
            }
            else {
                result += `<${tagName}>${splitText[_]}</${tagName}>${splitText[_ + 1]}`;
            }
        }
        else {
            result += tag + splitText[_];
        }
    }
    // If nothing was changed, then returns unchanged text
    if (result == "") {
        return text;
    }
    return result;
}

// Creates an element with style attached to it
function CreateStyledElement(givenText) {
    // Creates an array from all words in the givenText
    let text = givenText.split("{{");
    let words = [];
    for (let _ = 1; _ < text.length; _++) {
        text[_] = "{{" + text[_];
    }
    words.push(text[0]);
    for (let _ = 1; _ < text.length; _++) {
        let splitText = text[_].split("}}");
        words.push(splitText[0] + "}}");
        words.push(splitText[1]);
    }
    // Replaces special characters with HTML tags and add attributes to them
    let html = "";
    for (let _ = 0; _ < words.length; _++) {
        if (words[_][0] + words[_][1] == "{{") {
            const splitMedia = words[_].substring(2, words[_].length - 2);
            if (splitMedia[0] != "{" && splitMedia[splitMedia.length - 1] != "}" && splitMedia.length > 0) {
                try {
                    const values = splitMedia.split("|");
                    let mediaURL = values[0].split("\"");
                    // Gives text and style inputted values
                    let style = values[0].split("style=\"")[1];
                    let text = values[1].split("text=\"")[1];
                    console.log(text);
                    html += "<span style=\"" + style.split("\"")[0] + "\">" + text.split("\"")[0] + "</span>";
                    continue;
                }
                catch {
                    // If it fails and catches an error, then return unmodified word
                    html += words[_];
                    continue;
                }
            }
            else {
                // If there is, then return unmodified word
                html += words[_];
                continue;
            }
        }
        else {
            // Inserts the word without any modifications made to it, if it doesn't start with special characters
            html += words[_];
            continue;
        }
    }
    // Returns string with HTML elements
    return html;
}

// Generates link, image or audio HTML tag
function CreateMedia(givenText) {
    // Creates an array from all words in the givenText
    let text = givenText.split("[[");
    let words = [];
    for (let _ = 1; _ < text.length; _++) {
        text[_] = "[[" + text[_];
    }
    words.push(text[0]);
    for (let _ = 1; _ < text.length; _++) {
        let splitText = text[_].split("]]");
        words.push(splitText[0] + "]]");
        words.push(splitText[1]);
    }
    // Replaces special characters with HTML tags and add attributes to them
    let html = "";
    for (let _ = 0; _ < words.length; _++) {
        // Transforms the word into a link or a media, if features special characters
        if (words[_][0] + words[_][1] == "[[") {
            // Removes [] from the word
            const splitMedia = words[_].substring(2, words[_].length - 2);
            // Checks if there are any [] left
            if (splitMedia[0] != "[" && splitMedia[splitMedia.length - 1] != "]" && splitMedia.length > 0) {
                // Tries to create the <a>, <img> or <audio>
                try {
                    // Splits all media values
                    const values = splitMedia.split("|");
                    let mediaURL = values[0].split("\"");
                    // Gets the media type
                    let mediaType = "";
                    if (mediaURL[0] == "file=") {
                        mediaType = "file";
                    }
                    else if (mediaURL[0] == "link=") {
                        mediaType = "link";
                    }
                    else {
                        html += words[_];
                        continue;
                    }
                    // Creates the url or src
                    mediaURL = mediaURL[1];
                    // Gives text and style inputted values
                    let mediaText = "";
                    let mediaStyle = "";
                    for (let _index = 1; _index < 3; _index++) {
                        let selectValue = values[_index];
                        if (selectValue != undefined) {
                            let check = selectValue.split("\"")[0];
                            if (check == "text=") {
                                selectValue = selectValue.split("text=\"")[1];
                                selectValue = selectValue.split("\"")[0];
                                if (mediaType == "file") {
                                    mediaText = (selectValue.length > 0) ? selectValue : "";
                                }
                                else {
                                    mediaText = (selectValue.length > 0) ? selectValue : mediaURL;
                                }
                            }
                            if (check == "style=") {
                                selectValue = selectValue.split("style=\"")[1];
                                selectValue = selectValue.split("\"")[0];
                                mediaStyle = (selectValue.length > 0) ? selectValue : "";
                            }
                        }
                        else {
                            mediaText = (mediaText.length > 0) ? mediaText : mediaURL;
                        }
                    }
                    // Checks if there is any style to add
                    let addStyle = (mediaStyle.length > 0) ? "style=\"" + mediaStyle + "\"" : "";
                    if (mediaType == "file") {
                        // Checks the file type
                        let arr = mediaURL.split(".");
                        let fileType = arr[arr.length - 1];
                        if (fileType == "ogg" || fileType == "mp3" ||fileType == "wav") {
                            // Attaches the audio <audio></audio> to HTML as string
                            html += "<div>" + mediaText + "<br><audio " + addStyle + " controls><source src=\"" + mediaURL + "\"></audio></div>";
                            continue;
                        }
                        else {
                            // Attaches the image <img> to HTML as string
                            html += "<div><img src=\"" + mediaURL + "\" " + addStyle + "><br>" + mediaText + "</div>";
                            continue;
                        }
                    }
                    else {
                        // Attaches the link <a></a> to HTML as string
                        html += "<a href=\"" + mediaURL + "\" " + addStyle + ">" + mediaText + "</a>";
                        continue;
                    }
                }
                catch {
                    // If it fails and catches an error, then return unmodified word
                    html += words[_];
                    continue;
                }
            }
            else {
                // If there is, then return unmodified word
                html += words[_];
                continue;
            }
        }
        else {
            // Inserts the word without any modifications made to it, if it doesn't start with special characters
            html += words[_];
            continue;
        }
    }
    // Returns string with HTML elements
    return html;
}

// Removes all HTML tags from the inputted string
function RemoveHTML(HTMLString) {
    const parser = new DOMParser();
    const doc = parser.parseFromString(HTMLString, "text/html");
    const textContent = doc.body.textContent || "";
    return textContent;
}