/// <reference path="./typings/currency.d.ts" />

const Application: ApplicationState = {
    keyboard: null,
    mode: [],
    languageVars: {}
}


/** Parses a language variable. */
const lang = (key: string, replacements?: string[] | string) => {
    let finalValue = Application.languageVars[key] || ''

    if (!replacements) return finalValue
    if (typeof replacements === 'string') replacements = [replacements]

    replacements.forEach((replacement, index) => {
        const correctIndex = index + 1
        finalValue = finalValue.replace(`[${correctIndex}]`, replacement)
    })

    return finalValue
}

/** Check if a variable is defined */
const defined = (variable: any) => {
    return typeof variable !== 'undefined'
}

/** Call an Ajax function asynchronously */
const ajax = (endpoint: string, data: any, method = 'POST', successFunction: Function, errorFunction: Function, beforeFunction: any) => {
    data = (data == null) ? data : JSON.stringify(data)
    return $.ajax({
        url: endpoint,
        method: method,
        data: data,
        success: (response: ajaxResult) => {
            if (successFunction && response.status == 'success')
                successFunction(JSON.parse(response.data))
            else if (errorFunction && response.status != 'success') {
                errorFunction(JSON.parse(response.data))
            }
        },
        error: (error) => console.log(error.statusCode),
        beforeSend: beforeFunction
    })
}
/*
    For the flow of the app, synchronous is commonly preferred
    though trying to keep its usage as low as possible.
 */
const ajaxSync = (endpoint: string, data?: any, method = 'POST') => {
    const response = JSON.parse(
        $.ajax({
            url: endpoint,
            method: method,
            data: JSON.stringify(data),
            async: false,
        }).responseText)

    if (response.data) {
        response.data = JSON.parse(response.data)
        return response.data
    }

    return response
}

/* Redirect to a specific URL */
const redirect = (url: string): void => location.assign(url)

const resize = () => {
    $('#pageContainer').height(window.innerHeight + "px");
}

const setupCore = (languageVars: Record<string, string>) => {
    Application.languageVars = languageVars
    const doc = $(document)
    doc.on('click', '#alertNo, #alertOk', hideAlerts)
    doc.on('click', '.toggle', toggle)
    window.addEventListener('resize', resize)
    resize()

    setElementVisibilityByMode()
}


const posAlert = (message: string, title = 'Message') => {
    const alertBox = $('#alert')
    alertBox.css('display', 'flex');
    alertBox.data('value', '');
    $('#alertHeading').text(title);
    $('#alertMessage').text(message);

    $('#alertOk').css('display', 'flex');
    $('#alertYes').css('display', 'none');
    $('#alertNo').css('display', 'none');
}

const confirmation = (message: string, data: any, title = 'Confirm', submitFunction = (data: any) => {hideAlerts()}) => {
    const alert = $('#alert')

    $(document).on('click', '#alert #alertYes', () => {
        hideAlerts()
        submitFunction(data)
        $(document).off('click', '#alert #alertYes')
    })

    alert.css('display', 'flex')
    $('#alertHeading').html(title)
    $('#alertMessage').html(message)

    $('#alertOk').css('display', 'none')
    $('#alertYes').css('display', 'flex')
    $('#alertNo').css('display', 'flex')
}


const hideAlerts = () => $('#alert').hide()

const turnOnMode = (mode: PosMode) => {
    Application.mode.push(mode)
    setElementVisibilityByMode()
}

const turnOffMode = (mode: PosMode) => {
    Application.mode = Application.mode.filter((value) => value != mode)
    setElementVisibilityByMode()
}

const toggleMode = (mode: PosMode) => {
    if (!isInMode(mode))
        turnOnMode(mode)
    else
        turnOffMode(mode)
}

const clearModes = () => {
    Application.mode = []
    setElementVisibilityByMode()
}

const isInMode = (mode: PosMode) => Application.mode.includes(mode)

const setElementVisibilityByMode = () => {
    const mode = Application.mode
    const elements = $('[data-visible-in-mode]')

    elements.each((index, elem) => {
        const element = $(elem)
        const visibleInModes: PosModes = element.data('visible-in-mode')

        const showElement = visibleInModes.every(visibleMode => {
            return mode.includes(visibleMode)
        });

        if (element.hasClass('useVisibility')) {
            if (showElement) {
                element.css('visibility', 'visible')
            } else element.css('visibility', 'hidden')
        } else element.toggle(showElement)
    })

    const invisibleElements = $('[data-invisible-in-mode]')
    invisibleElements.each((index, elem) => {
        const element = $(elem)
        const inVisibleInModes: PosModes = element.data('invisible-in-mode')
        const hideElement = inVisibleInModes.some(invisibleMode => {
            return mode.includes(invisibleMode)
        })
        element.toggle(!hideElement)
    })


    $('[data-active-in-mode]').each((index, elem) => {
        const button = $(elem)
        const activeInMode: PosMode = button.data('active-in-mode')

        mode.includes(activeInMode)
            ? button.addClass('active')
            : button.removeClass('active')

    })

}

const getPercentageOfPageContainerWidth = (pixels: number) => ( (pixels / $('#pageContainer').width()) * 100) + '%'

const pulseElement = (element: JQuery) => element.addClass('pulse').on('animationend', () => element.removeClass('pulse'))

Array.prototype.where = function<x>(this: x[], property: string, value: any) {
    return this.filter( item => (item as any)[property] === value)[0] || null
}

const money = (amount: number, fromCents=true) => currency(amount, {fromCents: fromCents})
const moneyFromString = (amount: string) => currency(amount)

const toggle = (e: JQuery.TriggeredEvent) => {
    const button = $(e.target)
    const toggleGroup =  button.closest('.toggleGroup')
    const input = toggleGroup.find('input.value')
    const isActive = button.hasClass('active')
        toggleGroup
            .find('.toggle')
            .removeClass('active')

    let value = !isActive
        ? button.addClass('active').data('value')
        : toggleGroup
            .find('.toggle.default')
            .addClass('active')
            .data('value')

    input.val(value).trigger('change')
}

const resetToggle = (input: JQuery) => {
    input
        .closest('.toggleGroup')
        .find('.toggle.default')
        .trigger('click')
}
//Id generator.
function* newestId(){
    let id = 0
    while(true){
        id++
        yield id
    }
}

const loadTemplate = (templateSelector: string) => {
    const content = $(templateSelector)
            .clone()
            .removeAttr('id')
            .prop('content')
    return $(content)
}


$(() => ajax('/ajax/languageVars', null, 'GET', setupCore, null, null))