document.body.style.overflowY = "scroll";

if (location.hash && location.hash.length > 0) {
    var initialQuery = location.hash;
    if (initialQuery[0] == "#") {
        initialQuery = initialQuery.slice(1);
    }
    document.getElementById("query").value = decodeURIComponent(initialQuery);
}

var indexControl = document.getElementById("cineraIndexControl");
var indexSort = indexControl.querySelector("#cineraIndexSort");
var indexSortChronological = true;

var filterMenu = indexControl.querySelector(".cineraIndexFilter");
if(filterMenu)
{
    var filterContainer = filterMenu.querySelector(".filter_container");
    //menuState.push(linkMenu);

    filterMenu.addEventListener("mouseenter", function(ev) {
        filterContainer.style.display = "block";
    });

    filterMenu.addEventListener("mouseleave", function(ev) {
        filterContainer.style.display = "none";
    });
}

function hideEntriesOfProject(ProjectElement)
{
    if(!ProjectElement.classList.contains("off"))
    {
        ProjectElement.classList.add("off");
    }
    var baseURL = ProjectElement.attributes.getNamedItem("data-baseURL").value;
    for(var i = 0; i < projects.length; ++i)
    {
        var ThisProject = projects[i];
        if(ThisProject.baseURL === baseURL)
        {
            ThisProject.filteredOut = true;
            if(ThisProject.entriesContainer != null)
            {
                ThisProject.entriesContainer.style.display = "none";
                disableSprite(ThisProject.entriesContainer.parentElement);
            }
        }
    }
}

function showEntriesOfProject(ProjectElement)
{
    if(ProjectElement.classList.contains("off"))
    {
        ProjectElement.classList.remove("off");
    }
    var baseURL = ProjectElement.attributes.getNamedItem("data-baseURL").value;
    for(var i = 0; i < projects.length; ++i)
    {
        var ThisProject = projects[i];
        if(ThisProject.baseURL === baseURL)
        {
            ThisProject.filteredOut = false;
            if(ThisProject.entriesContainer != null)
            {
                ThisProject.entriesContainer.style.display = "flex";
                enableSprite(ThisProject.entriesContainer.parentElement);
            }
        }
    }
}

function hideProjectSearchResults(baseURL)
{
    var cineraResults = document.getElementById("cineraResults");
    if(cineraResults)
    {
        var cineraResultsProjects = cineraResults.querySelectorAll(".projectContainer");
        for(var i = 0; i < cineraResultsProjects.length; ++i)
        {
            var resultBaseURL = cineraResultsProjects[i].attributes.getNamedItem("data-baseURL").value;
            if(baseURL === resultBaseURL)
            {
                cineraResultsProjects[i].style.display = "none";
                return;
            }
        }
    }
}

function showProjectSearchResults(baseURL)
{
    var cineraResults = document.getElementById("cineraResults");
    if(cineraResults)
    {
        var cineraResultsProjects = cineraResults.querySelectorAll(".projectContainer");
        for(var i = 0; i < cineraResultsProjects.length; ++i)
        {
            var resultBaseURL = cineraResultsProjects[i].attributes.getNamedItem("data-baseURL").value;
            if(baseURL === resultBaseURL)
            {
                cineraResultsProjects[i].style.display = "flex";
                return;
            }
        }
    }
}

function toggleEntriesOfProjectAndChildren(ProjectFilterElement)
{
    var baseURL = ProjectFilterElement.attributes.getNamedItem("data-baseURL").value;
    var shouldShow = ProjectFilterElement.classList.contains("off");
    if(shouldShow)
    {
        ProjectFilterElement.classList.remove("off");
        enableSprite(ProjectFilterElement);
    }
    else
    {
        ProjectFilterElement.classList.add("off");
        disableSprite(ProjectFilterElement);
    }

    for(var i = 0; i < projects.length; ++i)
    {
        var ThisProject = projects[i];
        if(ThisProject.baseURL === baseURL)
        {
            if(shouldShow)
            {
                ThisProject.filteredOut = false;
                enableSprite(ThisProject.projectTitleElement.parentElement);
                if(ThisProject.entriesContainer != null)
                {
                    ThisProject.entriesContainer.style.display = "flex";
                }
                showProjectSearchResults(projects[i].baseURL);
            }
            else
            {
                ThisProject.filteredOut = true;
                disableSprite(ThisProject.projectTitleElement.parentElement);
                if(ThisProject.entriesContainer != null)
                {
                    ThisProject.entriesContainer.style.display = "none";
                }
                hideProjectSearchResults(ThisProject.baseURL);
            }
        }
    }

    var indexChildFilterProjects = ProjectFilterElement.querySelectorAll(".cineraFilterProject");

    for(var j = 0; j < indexChildFilterProjects.length; ++j)
    {
        var ThisElement = indexChildFilterProjects[j];
        if(shouldShow)
        {
            var baseURL = ThisElement.attributes.getNamedItem("data-baseURL").value;
            showEntriesOfProject(ThisElement);
            showProjectSearchResults(baseURL);
        }
        else
        {
            var baseURL = ThisElement.attributes.getNamedItem("data-baseURL").value;
            hideEntriesOfProject(ThisElement);
            hideProjectSearchResults(baseURL);
        }
    }
}

var indexFilter = indexControl.querySelector(".cineraIndexFilter");
if(indexFilter)
{
    var indexFilterProjects = indexFilter.querySelectorAll(".cineraFilterProject");
    for(var i = 0; i < indexFilterProjects.length; ++i)
    {
        indexFilterProjects[i].addEventListener("mouseover", function(ev) {
            ev.stopPropagation();
            this.classList.add("focused");
            focusSprite(this);
        });
        indexFilterProjects[i].addEventListener("mouseout", function(ev) {
            ev.stopPropagation();
            this.classList.remove("focused");
            unfocusSprite(this);
        });
        indexFilterProjects[i].addEventListener("click", function(ev) {
            ev.stopPropagation();
            toggleEntriesOfProjectAndChildren(this);
        });
    }
}

var resultsSummary = document.getElementById("cineraResultsSummary");
var resultsContainer = document.getElementById("cineraResults");

var indexContainer = document.getElementById("cineraIndex");

var projectsContainer = indexContainer.querySelectorAll(".cineraIndexProject");

var projectContainerPrototype = document.createElement("DIV");
projectContainerPrototype.classList.add("projectContainer");

var dayContainerPrototype = document.createElement("DIV");
dayContainerPrototype.classList.add("dayContainer");

var dayNamePrototype = document.createElement("SPAN");
dayNamePrototype.classList.add("dayName");
dayContainerPrototype.appendChild(dayNamePrototype);

var markerListPrototype = document.createElement("DIV");
markerListPrototype.classList.add("markerList");
dayContainerPrototype.appendChild(markerListPrototype);

var markerPrototype = document.createElement("A");
markerPrototype.classList.add("marker");
if(resultsContainer.getAttribute("data-single") == 0)
{
    markerPrototype.setAttribute("target", "_blank");
}

function prepareToParseIndexFile(project)
{
    project.xhr.addEventListener("load", function() {
        var contents = project.xhr.response;
        var lines = contents.split("\n");
        var mode = "none";
        var episode = null;
        for (var i = 0; i < lines.length; ++i) {
            var line = lines[i];
            if (line.trim().length == 0) { continue; }
            if (line == "---") {
                if (episode != null && episode.name != null && episode.title != null) {
                    episode.filename = episode.name;
                    episode.day = getEpisodeName(episode.filename + ".html.md");
                    episode.dayContainerPrototype = project.dayContainerPrototype;
                    episode.markerPrototype = markerPrototype;
                    episode.playerURLPrefix = project.playerURLPrefix;
                    project.episodes.push(episode);
                }
                episode = {};
                mode = "none";
            } else if (line.startsWith("name:")) {
                episode.name = line.slice(6);
            } else if (line.startsWith("title:")) {
                episode.title = line.slice(7).trim().slice(1, -1);
            } else if (line.startsWith("markers")) {
                mode = "markers";
                episode.markers = [];
            } else if (mode == "markers") {
                var match = line.match(/"(\d+)": "(.+)"/);
                if (match == null) {
                    console.log(name, line);
                } else {
                    var totalTime = parseInt(line.slice(1));
                    var marker = {
                        totalTime: totalTime,
                        prettyTime: markerTime(totalTime),
                        text: match[2].replace(/\\"/g, "\"")
                    }
                    episode.markers.push(marker);
                }
            }
        }
        document.querySelector(".spinner").classList.remove("show");
        project.parsed = true;
        runSearch(true);
    });
    project.xhr.addEventListener("error", function() {
        console.error("Failed to load content");
    });
}

var projects = [];
function prepareProjects()
{
    for(var i = 0; i < projectsContainer.length; ++i)
    {
        var ID = projectsContainer[i].attributes.getNamedItem("data-project").value;
        var baseURL = projectsContainer[i].attributes.getNamedItem("data-baseURL").value;
        var playerLocation = projectsContainer[i].attributes.getNamedItem("data-playerLocation").value;
        var theme = projectsContainer[i].classList.item(1);

        projects[i] =
            {
                baseURL: baseURL,
                playerURLPrefix: (baseURL ? baseURL + "/" : "") + (playerLocation ? playerLocation + "/" : ""),
                indexLocation: (baseURL ? baseURL + "/" : "") + ID + ".index",
                projectTitleElement: projectsContainer[i].querySelector(":scope > .cineraProjectTitle"),
                entriesContainer: projectsContainer[i].querySelector(":scope > .cineraIndexEntries"),
                dayContainerPrototype: dayContainerPrototype.cloneNode(true),
                filteredOut: false,
                parsed: false,
                searched: false,
                resultsToRender: [],
                resultsIndex: 0,
                theme: theme,
                episodes: [],
                xhr: new XMLHttpRequest(),
            }

        projects[i].dayContainerPrototype.classList.add(theme);
        projects[i].dayContainerPrototype.children[1].classList.add(theme);

        document.querySelector(".spinner").classList.add("show");
        projects[i].xhr.open("GET", projects[i].indexLocation);
        projects[i].xhr.setRequestHeader("Content-Type", "text/plain");
        projects[i].xhr.send();
        prepareToParseIndexFile(projects[i]);
    }
}
prepareProjects();

indexSort.addEventListener("click", function(ev) {
    if(indexSortChronological)
    {
        this.firstChild.nodeValue = "Sort: New to Old ⏷"
        for(var i = 0; i < projects.length; ++i)
        {
            if(projects[i].entriesContainer)
            {
                projects[i].entriesContainer.style.flexFlow = "column-reverse";
            }
        }
    }
    else
    {
        this.firstChild.nodeValue = "Sort: Old to New ⏶"
        for(var i = 0; i < projects.length; ++i)
        {
            if(projects[i].entriesContainer)
            {
                projects[i].entriesContainer.style.flexFlow = "column";
            }
        }
    }
    indexSortChronological = !indexSortChronological;
    runSearch(true);
});

var lastQuery = null;
var markerList = null;
var projectContainer = null;
var resultsMarkerIndex = -1;
var rendering = false;

var highlightPrototype = document.createElement("B");

function getEpisodeName(filename) {
    var day = filename;
    var dayParts = day.match(/([a-zA-Z_-]+)([0-9]+)?([a-zA-Z]+)?/);
    day = dayParts[1].slice(0, 1).toUpperCase() + dayParts[1].slice(1) + (dayParts[2] ? " " + dayParts[2] : "") + (dayParts[3] ? " " + dayParts[3].toUpperCase() : "");
    return day;
}

function markerTime(totalTime) {
    var markTime = "(";
    var hours = Math.floor(totalTime / 60 / 60);
    var minutes = Math.floor(totalTime / 60) % 60;
    var seconds = totalTime % 60;
    if (hours > 0) {
        markTime += padTimeComponent(hours) + ":";
    }

    markTime += padTimeComponent(minutes) + ":" + padTimeComponent(seconds) + ")";

    return markTime;
}

function padTimeComponent(component) {
    return (component < 10 ? "0" + component : component);
}

function resetProjectsForSearch()
{
    for(var i = 0; i < projects.length; ++i)
    {
        var project = projects[i];
        project.searched = false;
        project.resultsToRender = [];
    }
}

var renderHandle;

function runSearch(refresh) {
    var queryStr = document.getElementById("query").value;
    if (refresh || lastQuery != queryStr) {
        var oldResultsContainer = resultsContainer;
        resultsContainer = oldResultsContainer.cloneNode(false);
        oldResultsContainer.parentNode.insertBefore(resultsContainer, oldResultsContainer);
        oldResultsContainer.remove();
        for(var i = 0; i < projects.length; ++i)
        {
            projects[i].resultsIndex = 0;
        }
        resultsMarkerIndex = -1;
    }
    lastQuery = queryStr;

    resetProjectsForSearch();

    var numEpisodes = 0;
    var numMarkers = 0;
    var totalSeconds = 0;

    // NOTE(matt):  Function defined within runSearch() so that we can modify numEpisodes, numMarkers and totalSeconds
    function runSearchInterior(resultsToRender, query, episode)
    {
        var matches = [];
        for (var k = 0; k < episode.markers.length; ++k) {
            query.lastIndex = 0;
            var result = query.exec(episode.markers[k].text);
            if (result && result[0].length > 0) {
                numMarkers++;
                matches.push(episode.markers[k]);
                if (k < episode.markers.length-1) {
                    totalSeconds += episode.markers[k+1].totalTime - episode.markers[k].totalTime;
                }
            }
        }
        if (matches.length > 0) {
            numEpisodes++;
            resultsToRender.push({
                query: query,
                episode: episode,
                matches: matches
            });
        }
    }

    if (queryStr && queryStr.length > 0) {
        indexContainer.style.display = "none";
        resultsSummary.style.display = "block";
        var shouldRender = false;
        var query = new RegExp(queryStr.replace("(", "\\(").replace(")", "\\)").replace(/\|+/, "\|").replace(/\|$/, "").replace(/(^|[^\\])\\$/, "$1"), "gi");

        // Visible
        for(var i = 0; i < projects.length; ++i)
        {
            var project = projects[i];
            if(project.parsed && !project.filteredOut && project.episodes.length > 0) {
                if(indexSortChronological)
                {
                    for(var j = 0; j < project.episodes.length; ++j) {
                        var episode = project.episodes[j];
                        runSearchInterior(project.resultsToRender, query, episode);
                    }
                }
                else
                {
                    for(var j = project.episodes.length; j > 0; --j) {
                        var episode = project.episodes[j - 1];
                        runSearchInterior(project.resultsToRender, query, episode);
                    }
                }

                shouldRender = true;
                project.searched = true;

            }
        }

        // Invisible
        for(var i = 0; i < projects.length; ++i)
        {
            var project = projects[i];
            if(project.parsed && project.filteredOut && !project.searched && project.episodes.length > 0) {
                if(indexSortChronological)
                {
                    for(var j = 0; j < project.episodes.length; ++j) {
                        var episode = project.episodes[j];
                        runSearchInterior(project.resultsToRender, query, episode);
                    }
                }
                else
                {
                    for(var j = project.episodes.length; j > 0; --j) {
                        var episode = project.episodes[j - 1];
                        runSearchInterior(project.resultsToRender, query, episode);
                    }
                }

                shouldRender = true;
                project.searched = true;

            }
        }

        if(shouldRender)
        {
            if (rendering) {
                clearTimeout(renderHandle);
            }
            renderResults();
        }
    }
    else
    {
        indexContainer.style.display = "block";
        resultsSummary.style.display = "none";
    }

    var totalTime = Math.floor(totalSeconds/60/60) + "h " + Math.floor(totalSeconds/60)%60 + "m " + totalSeconds%60 + "s ";

    resultsSummary.textContent = "Found: " + numEpisodes + " episodes, " + numMarkers + " markers, " + totalTime + "total.";
}

function renderResults() {
    var maxItems = 42;
    var numItems = 0;
    for(var i = 0; i < projects.length; ++i)
    {
        var project = projects[i];
        if (project.resultsIndex < project.resultsToRender.length) {
            rendering = true;
            while (numItems < maxItems && project.resultsIndex < project.resultsToRender.length) {
                var query = project.resultsToRender[project.resultsIndex].query;
                var episode = project.resultsToRender[project.resultsIndex].episode;
                var matches = project.resultsToRender[project.resultsIndex].matches;
                if (resultsMarkerIndex == -1) {
                    if(project.resultsIndex == 0 || project.resultsToRender[project.resultsIndex - 1].episode.playerURLPrefix != episode.playerURLPrefix)
                    {
                        projectContainer = projectContainerPrototype.cloneNode(true);
                        for(var i = 0; i < projects.length; ++i)
                        {
                            if(projects[i].playerURLPrefix === episode.playerURLPrefix)
                            {
                                projectContainer.setAttribute("data-baseURL", projects[i].baseURL);
                                if(projects[i].filteredOut)
                                {
                                    projectContainer.style.display = "none";
                                }
                            }
                        }
                        resultsContainer.appendChild(projectContainer);
                    }
                    else
                    {
                        projectContainer = resultsContainer.lastElementChild;
                    }


                    var dayContainer = episode.dayContainerPrototype.cloneNode(true);
                    var dayName = dayContainer.children[0];
                    markerList = dayContainer.children[1];
                    dayName.textContent = episode.day + ": " + episode.title;
                    projectContainer.appendChild(dayContainer);
                    resultsMarkerIndex = 0;
                    numItems++;
                }        

                while (numItems < maxItems && resultsMarkerIndex < matches.length) {
                    var match = matches[resultsMarkerIndex];
                    var marker = episode.markerPrototype.cloneNode(true);
                    marker.setAttribute("href", episode.playerURLPrefix + episode.filename.replace(/"/g, "") + "/#" + match.totalTime);
                        query.lastIndex = 0;
                        var cursor = 0;
                        var text = match.text;
                        var result = null;
                        marker.appendChild(document.createTextNode(match.prettyTime + " "));
                        while (result = query.exec(text)) {
                            if (result.index > cursor) {
                                marker.appendChild(document.createTextNode(text.slice(cursor, result.index)));
                            }
                            var highlightEl = highlightPrototype.cloneNode();
                            highlightEl.textContent = result[0];
                            marker.appendChild(highlightEl);
                            cursor = result.index + result[0].length;
                        }

                    if (cursor < text.length) {
                        marker.appendChild(document.createTextNode(text.slice(cursor, text.length)));
                    }
                    markerList.appendChild(marker);
                    numItems++;
                    resultsMarkerIndex++;
                }

                if (resultsMarkerIndex == matches.length) {
                    resultsMarkerIndex = -1;
                    project.resultsIndex++;
                }
            }
            renderHandle = setTimeout(renderResults, 0);
        } else {
            rendering = false;
        }
    }
}

function IsVisible(el) {
    var xPos = 0;
    var yPos = 0;
    var Height = parseInt(getComputedStyle(el).height);

    while (el) {
        if (el.tagName == "BODY") {
            var xScroll = el.scrollLeft || document.documentElement.scrollLeft;
            var yScroll = el.scrollTop || document.documentElement.scrollTop;

            xPos += (el.offsetLeft - xScroll + el.clientLeft)
            yPos += (el.offsetTop - yScroll + el.clientTop)
        } else {
            xPos += (el.offsetLeft - el.scrollLeft + el.clientLeft);
            yPos += (el.offsetTop - el.scrollTop + el.clientTop);
        }

        el = el.offsetParent;
    }
    return ((xPos > 0 && xPos < window.innerWidth) && (yPos > 0 && yPos + Height < window.innerHeight));
}

var queryEl = document.getElementById("query");
if(document.hasFocus() && IsVisible(queryEl)) { queryEl.focus(); }
queryEl.addEventListener("input", function(ev) {
    history.replaceState(null, null, "#" + encodeURIComponent(queryEl.value));
    runSearch();
});

runSearch();

// Testing