FW.Router.register(undefined, function (full, query) {
    HomePage.registerRoute(full, query);
});

FW.Router.register('^\/(?:(welcome)\/)?$', function (full, query) {
    HomePage.registerRoute(full, query);
});

(function (window) {
    var HomePage = {};

    HomePage.registerRoute = function (full, query) {
        var deferred = $.Deferred();
        FW.getPromise('accessToken').then(function (accessToken) {
            return accessToken;
        }, function () {
            return undefined;
        }).then(function (accessToken) {
            var extra = {};
            if (accessToken) {
                extra.token = accessToken;
            }
            $.when.apply($, [
                $.ajax({url: FW.Partial.global('backendApiUrl') + 'books/?' + Query.build(Object.assign(extra, window.filters[0]), '&')}),
                $.ajax({url: FW.Partial.global('backendApiUrl') + 'books/?' + Query.build(Object.assign(extra, window.filters[1]), '&')}),
                $.ajax({url: FW.Partial.global('backendApiUrl') + 'books/?' + Query.build(Object.assign(extra, window.filters[2]), '&')}),
                $.ajax({url: FW.Partial.global('backendApiUrl') + 'books/?' + Query.build(Object.assign(extra, window.filters[3]), '&')})
            ]).done(function (r1, r2, r3, r4) {
                var l1 = [], l2 = [], l3 = [], l4 = [];
                deferred.resolve(
                    {obj: [
                        _.filter(r1[0], function (book) {
                            return book.physical_ean ?
                                (l1.indexOf(book.physical_ean) >= 0 ? false : l1.push(book.physical_ean) > 0) :
                                true;
                        }),
                        _.filter(r2[0], function (book) {
                            return book.physical_ean ?
                                (l2.indexOf(book.physical_ean) >= 0 ? false : l2.push(book.physical_ean) > 0) :
                                true;
                        }),
                        _.filter(r3[0], function (book) {
                            return book.physical_ean ?
                                (l3.indexOf(book.physical_ean) >= 0 ? false : l3.push(book.physical_ean) > 0) :
                                true;
                        }),
                        _.filter(r4[0], function (book) {
                            return book.physical_ean ?
                                (l4.indexOf(book.physical_ean) >= 0 ? false : l4.push(book.physical_ean) > 0) :
                                true;
                        }),
                        accessToken
                    ]}
                );
            }).fail(function (error) {
                deferred.reject(error);
            });

        });

        FW.Partial.data('home', deferred.promise());
        FW.Partial.data('page-home', FW.getPromise('i18n'));

        FW.Partial.render('page-home', $('[data-placeholder="page"]')).then(function () {
            updateUI(); // FIXME TODO
            $('html, body').animate({scrollTop: 0}, 250);

            $('[data-book-id].favorite').click (function() {
                favorites.toggle(this);
            });

            // Welcome Modal
            if (query === 'welcome') {
                $('#js-welcomeMsg').modal('show');
            }
        });
    };

    window.HomePage = HomePage;

})(window);

FW.Router.register('^\/book\/([0-9]+)/?$', function (full, bookId) {
    const deferredBook = $.Deferred();
    const deferredSame = $.Deferred();

    FW.getPromise('accessToken').then(function (accessToken) {
        return accessToken;
    }, function () {
        return undefined;
    }).then(function (accessToken) {
        const extra = {};

        if (accessToken) {
            extra.token = accessToken;
        }

        function request(planInfo) {
            if ((planInfo || {}).fullAccess) {
                extra.full = 1;
            }
            $.ajax({url: FW.Partial.global('backendApiUrl') + 'book/' + bookId + '/?' + Query.build(Object.assign(extra, FW.Partial.global('browseFilters')), '&')}).done(function (data) {
                FW.getPromise('userInfo').catch(function () {
                    return undefined;
                }).then(function (user) {
                    deferredBook.resolve({
                        obj: data,
                        pageTitle: data.title,
                        user: user
                    });
                });

                extra.category = (data.categories.length > 0) ? data.categories[0].id : 652;
                extra.limit = 20;

                $.ajax({url: FW.Partial.global('backendApiUrl') + 'books/?' + Query.build(extra, '&')}).done(function (data) {
                    deferredSame.resolve({
                        same: data
                    });

                }).fail(function (error) {
                    deferredBook.reject(error);
                    deferredSame.reject(error);
                });
            }).fail(function (error) {
                deferredBook.reject(error);
                deferredSame.reject(error);
            });
        }

        if (accessToken) {
            FW.getPromise('customerInfo')
                .then(function (customerInfo) {
                    return Subscription.getCustomerPlan(customerInfo.subscriptions).id;
                }, function () {})
                .then(function (planId) {
                    FW.getPromise('planInfo', planId).then(request, function () {
                        request();
                    });
                });
        } else {
            request();
        }
    });

    FW.Partial.data('book', deferredBook.promise());
    FW.Partial.data('same-products', deferredSame.promise());
    FW.Partial.data('page-book', FW.getPromise('i18n'));

    FW.Partial.render('page-book', $('[data-placeholder="page"]')).then(function () {
        updateUI(); // FIXME TODO

        $('html, body').animate({scrollTop: 0}, 250);

        $('[data-book-id].favorite').click(function () {
            favorites.toggle(this);
        });

        $('.purchase-action').click(function() {
            const bookFormat = $(this).data('book-id');
            const formatName = $(this).data('format');
            const credits = parseFloat($(this).data('credits'));
            const price = parseFloat($(this).data('price')).toFixed(2);
            const currency = $(this).data('currency');
            const currencySign = $(this).data('currency-sign');

            $([
                '#modal-insufficient',
                '#modal-confirm-purchase',
                '#modal-purchase',
                '#modal-download',
                '#purchase-error-message'
            ].join(',')).addClass('d-none');
            $('#downloadConfirm').prop('disabled', false);

            FW.resetPromise('userInfo');
            FW.getPromise('userInfo').then(
                function (userInfo) {
                    $([
                        '#modal-credits-count-btn1',
                        '#modal-credits-count-btn2'
                    ].join(',')).html(userInfo.credits + ' Credits'); // FIXME
                    $('.modal-price').text(price);
                    $('.modal-currency').text(currency);
                    $('.modal-currency-sign').text(currencySign);

                    if (userInfo.daily_bonus > 0 || userInfo.credits >= credits) {
                        $('#modal-confirm-purchase').removeClass('d-none');
                    } else if (userInfo.daily_bonus === 0 && userInfo.credits === 0) {
                        FW.getPromise('customerInfo')
                            .then(function (customerInfo) {
                                const passCustomerInfo = function () {
                                    return customerInfo;
                                };
                                return GlobeData.loadAndRenderCountriesAndRegions(FW.Partial.global('language'))
                                    .then(passCustomerInfo, passCustomerInfo);
                            })
                            .then(function (customerInfo) {
                                const card = (customerInfo.cards || [])[0] || {};
                                const billing = card.billingAddress || {};

                                // validators
                                function updateForm() {
                                    const $invalidRequiredFields = $('#form *[required]:not(.success):not([disabled])'),
                                        $invalidOptionalFields = $('#form *:not([required]):not([disabled]).error'),
                                        valid = $invalidRequiredFields.length === 0 && $invalidOptionalFields.length === 0;

                                    $('#purchase').prop('disabled', !valid);
                                    return valid;
                                };

                                function toggleValid(that) {
                                    return function (valid) {
                                        $(that)[valid ? 'removeClass' : 'addClass']('error')[valid ? 'addClass' : 'removeClass']('success');
                                        updateForm();
                                    };
                                }
                                $('#first_name').on('blur change keyup', function () {
                                    Checkout.Customer.validateFirstName($('#first_name').val()).then(toggleValid('#first_name'));
                                });
                                $('#last_name').on('blur change keyup', function () {
                                    Checkout.Customer.validateLastName($('#last_name').val()).then(toggleValid('#last_name'));
                                });
                                $('#country').on('blur change keyup', function () {
                                    Checkout.Customer.validateCountry($('#country').val()).then(toggleValid('#country'));
                                });
                                $('#address').on('blur change keyup', function () {
                                    Checkout.Customer.validateAddress($('#address').val()).then(toggleValid('#address'));
                                });
                                $('#city').on('blur change keyup', function () {
                                    Checkout.Customer.validateCity($('#city').val()).then(toggleValid('#city'));
                                });
                                $('#region').on('blur change keyup', function () {
                                    Checkout.Customer.validateRegion($('#region').val()).then(toggleValid('#region'));
                                });
                                $('#postal_code').on('blur change keyup', function () {
                                    Checkout.Customer.validatePostalCode($('#postal_code').val()).then(toggleValid('#postal_code'));
                                });
                                $().off().on('blur change keyup', function () {
                                    if (card.status === 'active' && $('#card_number').val() === '') {
                                        toggleValid('#card_number')(true);
                                    } else {
                                        Checkout.Card.validateNumber($('#card_number').val()).then(toggleValid('#card_number'));
                                    }
                                });
                                $('#card_expirity_month,#card_expirity_year').on('blur change', function () {
                                    Checkout.Card.validateExpirity($('#card_expirity_month').val(), $('#card_expirity_year').val()).then(toggleValid('#card_expirity_month,#card_expirity_year'));
                                });
                                $('#card_number, #cvv').on('blur change keyup', function () {
                                    if (card.status === 'active' && $('#card_number').val() === '') {
                                        toggleValid('#card_number')(true);
                                        if ($('#cvv').val() === '') {
                                            toggleValid('#cvv')(true);
                                        } else {
                                            Checkout.Card.validateCVV($('#cvv').val()).then(toggleValid('#cvv'));
                                        }
                                    } else {
                                        Checkout.Card.validateNumber($('#card_number').val()).then(toggleValid('#card_number'));
                                        Checkout.Card.validateCVV($('#cvv').val()).then(toggleValid('#cvv'));
                                    }
                                });

                                $('#first_name').val(billing.firstName || customerInfo.firstName || '').change();
                                $('#last_name').val(billing.lastName || customerInfo.lastName || '').change();
                                $('#address').val(billing.address || customerInfo.address || '').change();
                                $('#city').val(billing.city || customerInfo.city || '').change();
                                $('#country').val(billing.country || customerInfo.counrty || '').change();
                                $('#region').val(billing.region || customerInfo.region || '').change();
                                $('#postal_code').val(billing.postalCode || customerInfo.postalCode || '').change();
                                if (card.status === 'active') {
                                    $('#card_expirity_month').val(('0' + card.expMonth).substr(-2)).change();
                                    $('#card_expirity_year').val(card.expYear).change();
                                    $('#card_number').attr('placeholder', card.bin.substr(0, 4) + ' ' + card.bin.substr(-2) + '** **** ' + card.last4).change();
                                    $('#cvv').attr('placeholder', '***').change();
                                }

                                $('#modal-purchase').removeClass('d-none');
                                $('#purchase').click(function () {
                                    TdsProcess.init();

                                    customerInfo.address = $('#address').val();
                                    customerInfo.city = $('#city').val();
                                    customerInfo.region = $('#region:not([disabled])').val(),
                                    customerInfo.country = $('#country').val();
                                    customerInfo.postalCode = $('#postal_code').val();

                                    const cardInfo = {
                                            number: $('#card_number').val(),
                                            expYear: $('#card_expirity_year').val(),
                                            expMonth: $('#card_expirity_month').val(),
                                            cvv: $('#cvv').val()
                                        },
                                        cardFailure = function () {
                                            userNotif('We were unable to charge your card', 'error');
                                            TdsProcess.hide();
                                        };
                                    let cardPromise, authToken;

                                    if (card.status !== 'active' || cardInfo.number !== '') {
                                        cardPromise = Checkout.Card.tokenize(customerInfo, cardInfo).then(function (cardToken) {
                                            return FW.getPromise('authToken').then(function (_authToken) {
                                                authToken = _authToken;
                                                return Checkout.Card.create(cardToken, _authToken);
                                            });
                                        });
                                    } else {
                                        cardPromise = $.Deferred().resolve(card).promise();
                                    }
                                    cardPromise.then(function (cardInfo) {
                                        window.addEventListener('message', TdsProcess.messageCallback);

                                        Checkout.Transaction.create(
                                            price,
                                            currency,
                                            $('#json_id').text() + ' ' + formatName,
                                            card.id,
                                            Hash.MD5.hex(card.id + ':' + customerInfo.id + ':' + bookFormat + ':' + parseInt(Date.now() / 60000))
                                        ).then(function (transaction) {
                                            window.removeEventListener('message', TdsProcess.messageCallback);
                                            FW.getPromise('accessToken').then(function (accessToken) {
                                                $.ajax({
                                                    url: FW.Partial.global('backendApiUrl') + 'user-purchase/' + accessToken + '/' + bookFormat + '/', type: 'POST',
                                                    data: transaction,
                                                    success: function (data) {
                                                        $('#modal-purchase').addClass('d-none');
                                                        TdsProcess.hide();
                                                        $('#modal-download').removeClass('d-none');
                                                    },
                                                    error: function (error) {
                                                        userNotif((error.responseJSON.error || {}).message || 'We were unable to process your request. Please, contact technical support.', 'error');
                                                        TdsProcess.hide();
                                                        $('#purchase').prop('disabled', false);
                                                    }
                                                });
                                            });
                                        }, function () {
                                            window.removeEventListener('message', TdsProcess.messageCallback);
                                            cardFailure();
                                        });
                                    }, cardFailure);
                                });
                            });
                    } else {
                        $('#modal-insufficient').removeClass('d-none');
                    }

                    $('#js-dwld-modal').modal('show');

                    // confirm purchase click-handler

                    $("#downloadConfirm").click(function () {
                        $('#downloadConfirm').prop('disabled', true);
                        FW.getPromise('accessToken').then(
                            function (accessToken) {
                                $.ajax({
                                    url: FW.Partial.global('backendApiUrl') + 'user-purchase/' + accessToken + '/' + bookFormat + '/', type: 'POST',
                                    success: function (data) {
                                        $('#modal-confirm-purchase').addClass('d-none');
                                        $('#modal-download').removeClass('d-none');
                                    },
                                    error: function (error) {
                                        $('#purchase-error-message').html(error.responseJSON.error.message).removeClass('d-none');
                                        $('#downloadConfirm').prop('disabled', false);
                                    }
                                });
                            },
                            function () {
                                window.location.hash = '#/signup/';
                            }
                        );
                    });
                },
                function () {
                    window.location.hash = '#/signup/';
                }
            );
        });
    });
});

FW.Router.register('^\/login\/$', function (full, query) {
    var deferred = $.Deferred();

    FW.getPromise('authToken').then(function () {
        deferred.reject();
        FW.resetPromise('authToken');
        window.location.hash = '#/';
    }, function () {
        deferred.resolve({pageTitle: 'Login'})
    });

    FW.Partial.data('login', deferred.promise());
    FW.Partial.data('page-login', FW.getPromise('i18n'));

    FW.Partial.render('page-login', $('[data-placeholder="page"]')).then(function () {
        creditsRangeSlider(); // FIXME TODO
        updateUI(); // FIXME TODO

        var $emailInput = $('#email');
        var $passwordInput = $('#password');
        var $loginErrorText = $('#login-error-text');
        var $resetPasswordBtn = $('#send-reset-password-btn');
        var $resetPasswordEmailInput = $('#email_resetpassword');
        var $submitLoginBtn = $('#submit-login-btn');

        $('html, body').animate({scrollTop: 0}, 250);
        $resetPasswordBtn.attr('disabled', 'disabled');

        var wrongInputs = function () {
            $submitLoginBtn.prop('disabled', false);
            $loginErrorText.html('Username/password combination is wrong').removeClass('d-none');
            $emailInput.addClass('red-border');
            $passwordInput.addClass('red-border');
        }

        $submitLoginBtn.click(function () {
            $loginErrorText.addClass('d-none');
            $emailInput.removeClass('red-border');
            $passwordInput.removeClass('red-border');
            $submitLoginBtn.prop('disabled', true);

            Checkout.Auth.loginByMode(window.themeSettings.checkout_auth_mode, $emailInput.val(), $passwordInput.val()).then(
                function () {
                    FW.resetPromise('authToken');
                    FW.getPromise('customerInfo').then(
                        function () {
                            FW.resetPromise('accessToken');
                            FW.Partial.data('header', FW.getPromise('accessToken').catch(function () {
                                    return undefined;
                                }).then(function (accessToken) {
                                    return {accessToken: accessToken};
                                })
                            );
                            window.location.hash = '#/';
                        },
                        function () {
                            Checkout.Customer.setToken(undefined);
                            FW.resetPromise('accessToken');
                            FW.Partial.data('header', FW.getPromise('accessToken').catch(function () {
                                    return undefined;
                                }).then(function (accessToken) {
                                    return {accessToken: accessToken};
                                })
                            );
                            wrongInputs();
                        }
                    );
                },
                wrongInputs
            );
        });

        // Reset password submit button click
        $resetPasswordBtn.click(function () {
            function onError(error) {
                userNotif(error || 'Error sending email, please try again later', 'error', false);
                $resetPasswordBtn.removeAttr('disabled');
            }

            $resetPasswordBtn.attr('disabled', 'disabled');
            Checkout.Customer.resetPassword($resetPasswordEmailInput.val()).then(function (result) {
                if (result.errorcode != 0) {
                    onError();
                } else {
                    $('.customer-password-reset').addClass('d-none');
                    $('.reset-password-success').removeClass('d-none');
                }
            }, function () {
                onError('The user with specified email does not exist');
            });
        });

        // Validate email
        $resetPasswordEmailInput.on('keyup', function () {
            var $selector = $(this);
            if (/(.+)@(.+){2,}\.(.+){2,}/.test($selector.val())) {
                Checkout.Customer.validateEmail($selector.val()).then(function (valid) {
                    if (valid && $selector.val() !== '') {
                        $selector.removeClass('error').addClass('success');
                        $resetPasswordBtn.removeAttr('disabled');
                    } else {
                        $selector.addClass('error').removeClass('success');
                        $resetPasswordBtn.attr('disabled', 'disabled');
                    }
                }, console.error);

            } else {
                $selector.addClass('error').removeClass('success');
                $resetPasswordBtn.attr('disabled', 'disabled');
            }
        });

        $('.js-reset-pass-btn').click(function () {
            $('.customer-login-register').addClass('d-none');
            $('.customer-password-reset').removeClass('d-none');
        });

        $('.js-show-login-btn').click(function () {
            $('.customer-password-reset').addClass('d-none');
            $('.customer-login-register').removeClass('d-none');
        });

        var submitByEnter = function (event) {
            if (event.keyCode === 13) {
                $submitLoginBtn.click();
                event.preventDefault();
            }
        };

        $emailInput.keypress(submitByEnter);
        $passwordInput.keypress(submitByEnter);

        $resetPasswordEmailInput.keypress(function (event) {
            if (event.keyCode === 13) {
                $resetPasswordBtn.click();
                event.preventDefault();
            }
        });
    });
});

FW.Router.register('^\/logout\/$', function (full, query) {
    FW.getPromise('authToken').then(function (authToken) {
        Checkout.Auth.logoutByMode(window.themeSettings.checkout_auth_mode, authToken).then(function () {
            FW.resetPromise('authToken');
            FW.resetPromise('accessToken');
            FW.Partial.data('header', FW.getPromise('accessToken').catch(function () {
                    return undefined;
                }).then(function (accessToken) {
                    return {accessToken: accessToken};
                })
            );
            window.location.hash = '#/';
        })
    });
});

FW.Router.register('^\/upselling\/$', function (full, query) {

    var deferred = $.Deferred();
    FW.getPromise('authToken').then(function () {
        deferred.resolve({pageTitle: 'Upselling'});
    }, function () {
        deferred.reject();
        window.location.hash = '#/login/';
    });

    FW.Partial.data('upselling', deferred.promise());
    FW.Partial.data('page-upselling', FW.getPromise('i18n'));

    FW.Partial.render('page-upselling', $('[data-placeholder="page"]')).then(function () {
        $('html, body').animate({scrollTop: 0}, 250);

        if (!Checkout.Storage.hasItem('upids') || !Checkout.Storage.hasItem('ugid')) {
            window.location.href = '#/summary/';
        }

        const $firstName = $('#first_name')
        const $lastName = $('#last_name')
        const $country = $('#country')
        const $region = $('#region')
        const $city = $('#city')
        const $address = $('#address')
        const $postalCode = $('#postal_code')
        const $cardNumber = $('#card_number')
        const $cvv = $('#cvv')

        let plansInfo = []
        const planIds = Checkout.Storage.getItem('upids').split(',')
        planIds.forEach(pid => {
            FW.getPromise('planInfo', pid).then(function (plan) {
                plansInfo.push(plan)
            });
        })

        GlobeData.loadAndRenderCountriesAndRegions(FW.Partial.global('language'))
            .done(GlobeData.detectCountryAndRegion)

        const finishUpsellingBtn = $('#finishUpsellingBtn');
        let cardNumber = FW.Partial.global('cardNumber');

        if (!cardNumber) {
            $('#cardNumberContainer').removeClass('d-none');
        }

        $('.js-qty-box button').on('click', function () {
            const qtyInput = $(this).closest('.js-qty-box').find('input');
            const type = $(this).data('type');
            let val = parseInt(qtyInput.val());
            qtyInput.val(type === 'plus' ? val + 1 : Math.max(0, val - 1));
        });

        $('#dismissUpsellingBtn').on('click', function () {
            if (typeof plausible !== 'undefined') {
                plausible('dismissUpsellingBtn');
            }
            window.location.href = Checkout.Storage.getItem('destination') || '#/summary/';
        });

        $('#approveUpsellingBtn').click(function () {
            if (typeof plausible !== 'undefined') {
                plausible('approveUpsellingBtn');
            }
            const plansForm = $('#plansUpsellingForm')
            const plans = objectifyForm(plansForm.serializeArray())
            let totalQty = 0
            for (const plan in plans) {
                totalQty += parseInt(plans[plan])
            }
            if (totalQty === 0) {
                notify('You must indicate a quantity greater than zero for at least one item')
                return false
            }
            plansForm.addClass('d-none');
            $('#upsellingShipping').removeClass('d-none');
        });

        $('#resetShippingFormBtn').on('click', function () {
            if (typeof plausible !== 'undefined') {
                plausible('resetShippingFormBtn');
            }
            $('#approveUpsellingShippingForm input').each(function() {
                $(this).removeAttr('readonly')
            })
            $country.attr('disabled', false)
            $region.attr('disabled', false)
        });

        function inputStateAfterValidation(valid, $selector) {
            if (!valid) {
                $selector.addClass('error').removeClass('success')
            } else {
                $selector.addClass('success').removeClass('error')
            }
        }

        $('#submitShippingFormBtn').on('click', function () {
            if (typeof plausible !== 'undefined') {
                plausible('submitShippingFormBtn');
            }
            $.when(
                Checkout.Customer.validateFirstName($firstName.val()),
                Checkout.Customer.validateLastName($lastName.val()),
                Checkout.Customer.validateCountry($country.val()),
                Checkout.Customer.validateRegion($region.val()),
                Checkout.Customer.validateCity($city.val()),
                Checkout.Customer.validateAddress($address.val()),
                Checkout.Customer.validatePostalCode($postalCode.val()),
            ).then(function (...args) {
                inputStateAfterValidation(args[0], $firstName)
                inputStateAfterValidation(args[1], $lastName)
                inputStateAfterValidation(args[2], $country)
                inputStateAfterValidation(args[3], $region)
                inputStateAfterValidation(args[4], $city)
                inputStateAfterValidation(args[5], $address)
                inputStateAfterValidation(args[6], $postalCode)
                if (args.some(v => !v)) {
                    notify('Please fill all fields with correct data')
                    return false
                }
                $('#confirmCvvModal').modal({backdrop: 'static', keyboard: false});
            })
        });

        function objectifyForm(formArray) {
            const returnArray = {};
            for (let i = 0; i < formArray.length; i++){
                returnArray[formArray[i]['name']] = formArray[i]['value'];
            }
            return returnArray;
        }

        function unfreezeForm() {
            finishUpsellingBtn.attr('disabled', false);
            $('#button-signup-preloader').addClass('d-none');
        }
        function freezeForm() {
            finishUpsellingBtn.attr('disabled', true);
            $('#button-signup-preloader').removeClass('d-none');
        }

        function notify(error) {
            const fallback = 'We were unable to process your request, please try again later';
            try {
                error = (typeof (error) === 'string' ? error : undefined) || fallback;
            } catch (e) {
                error = fallback;
            }
            userNotif(error, 'error', false);
        }

        let customerInfo = null;

        FW.getPromise('customerInfo')
            .then(function (customer) {
                finishUpsellingBtn.attr('disabled', false)
                customerInfo = customer
                $('#email').val(customerInfo.email)
                $firstName.val(customerInfo.firstName)
                $lastName.val(customerInfo.lastName)
                $('#phone').val(customerInfo.phoneNumber)
                $address.val(customerInfo.address)
                $city.val(customerInfo.city)
                $postalCode.val(customerInfo.postalCode)
                $country.val(customerInfo.country).trigger('change')
                $region.val(customerInfo.region).attr('disabled', true)
            })

        finishUpsellingBtn.click(function () {
            if (typeof plausible !== 'undefined') {
                plausible('finishUpsellingBtn');
            }
            $country.attr('disabled', false)
            $region.attr('disabled', false)
            const cardData = objectifyForm($('#finishUpsellingForm').serializeArray())
            cardNumber = cardNumber ? cardNumber : cardData.ccn;

            $.when(
                Checkout.Card.validateCVV($cvv.val()),
                Checkout.Card.validateNumber(cardNumber),
            ).then(function (v1, v2) {
                inputStateAfterValidation(v1, $cvv)
                inputStateAfterValidation(v2, $cardNumber)
                if (!v1 || !v2) {
                    notify('Please fill all fields with correct data')
                    return false
                }

                freezeForm()

                const cardInfo = {};
                const plans = objectifyForm($('#plansUpsellingForm').serializeArray())
                const orderItems = {}
                let amount = 0
                for (const plan in plans) {
                    const planId = plan.replace('plan[', '').replace('][qty]', '')
                    const qty= parseInt(plans[plan])
                    if (qty === 0) {
                        continue
                    }
                    orderItems[planId] = qty
                    const planInfo = plansInfo.find((plan) => plan.id === planId)
                    if (planInfo === undefined) {
                        notify(undefined)
                        console.log('Unexpected plan')
                        return false
                    }
                    // TODO: CHANGE AFTER BACKEND UPGRADE
                    amount += (planInfo.preauthorizeAmount || planInfo.recurringAmount || (planInfo.oneTimeSaleAmount !== undefined ? planInfo.oneTimeSaleAmount : 0)) * qty
                }

                if (Object.keys(orderItems).length === 0) {
                    notify(undefined)
                    console.log('No selected plans with quantity')
                    return false
                }

                const gatewayId = Checkout.Storage.getItem('ugid')

                if (!gatewayId) {
                    notify(undefined)
                    console.log('Missing gateway')
                    return false
                }

                const card = customerInfo.cards.find(c => c.id === customerInfo.cardId)

                if (card === undefined) {
                    notify(undefined)
                    console.log('Missing card')
                    return false
                }

                cardInfo.cvv = cardData.cvv;
                cardInfo.expYear = card.expYear;
                cardInfo.expMonth = card.expMonth;
                cardInfo.number = cardNumber;

                const deliveryAddress = objectifyForm($('#approveUpsellingShippingForm').serializeArray())

                function createTransaction(invoiceId) {
                    $('#finishUpsellingLeaveLink').addClass('d-none')
                    Checkout.Transaction.create(
                        amount,
                        plansInfo[0].currency,
                        'upselling',
                        customerInfo.cardId,
                        Hash.MD5.hex(customerInfo.cardId + plansInfo.toString()),
                        gatewayId,
                        undefined,
                        undefined,
                        [invoiceId]
                    ).then(() => {
                        Checkout.Storage.removeItem('uiid')
                        window.location.href = '#/summary/';
                    }).catch((err) => {
                        console.log('Transaction creation error')
                        notify('Sorry, but we couldn\'t process your card at this moment if you think CVV was incorrect you can try updating it again here');
                        $('#finishUpsellingLeaveLink').removeClass('d-none')
                    }).always(() => {
                        unfreezeForm()
                    });
                }

                Checkout.Card.tokenize(customerInfo, cardInfo)
                    .then(function (cardToken) {
                        if (Checkout.Storage.hasItem('uiid')) {
                            createTransaction(Checkout.Storage.getItem('uiid'))
                        } else {
                            Checkout.Customer.subscribe(orderItems, undefined, cardToken, undefined, undefined, gatewayId, deliveryAddress)
                                .then(function (subscription) {
                                    Checkout.Storage.setItem('uiid', subscription.invoiceId)
                                    createTransaction(subscription.invoiceId)
                                }).catch((err) => {
                                    console.log('Order creation error')
                                    notify(err)
                                    unfreezeForm()
                                })
                        }

                    }).catch((err) => {
                        console.log('Tokenize error')
                        notify(err)
                        unfreezeForm()
                    })
            });
        });
    });
});

(function (window) {
    const SignUp = {};

    SignUp.switchPlan = function () {
        $('#SignUpHeader').html('Select a Plan');
        $('.js-pricetable').removeClass('d-none');
        $('.js-signupform').addClass('d-none');

        // layout_azure changes
        $('.plans').removeClass('d-none');
        $('.billing-title-2 > .plans-item-price').removeClass('green blue orange');
        $('.billing').addClass('d-none');
        $('.billing-form').addClass('d-none');
        SignUp.clearSignUpPresets();
    };

    SignUp.selectPlan = function (planId, title) {
        const $selector = $('[data-plan-id-btn="' + planId + '"]'),
            pColor = $selector.data('plan-color'),
            pPrice = $selector.data('plan-price'),
            pName = $selector.data('plan-name'),
            pRecurringPeriodLimit = $selector.data('plan-recurring-period-limit');

        FW.getPromise('planInfo', planId).then(function (plan) {
            $('#currency-and-symbol').html(plan.currency + '(' + plan.currencySign + ')');
        });

        $('.js-pricetable').addClass('d-none');
        $('.js-signupform').removeClass('d-none');
        $('.js-selectedplanname').removeClass('green blue orange').addClass(pColor).html(pName);
        $('.js-selectedprice').html(pPrice);
        if (pRecurringPeriodLimit) {
            $('.js-selected-recurring-period-limit').html(pRecurringPeriodLimit);
        }
        $('#SignUpHeader').html(title);

        $('.js-recurring-charges')[pPrice ? 'removeClass' : 'addClass']('d-none');
        $('.js-payasyougo-plan')[pPrice ? 'addClass' : 'removeClass']('d-none');

        // layout_azure changes
        $('.billing-title-2 > .plans-item-price').addClass(pColor);
        $('.plans').addClass('d-none');
        $('.billing').removeClass('d-none');
        $('.billing-form').removeClass('d-none');

        // detectAdBlock();
    };

    SignUp.clearSignUpPresets = function () {
        Checkout.Storage.removeItem("pid");
        Checkout.Storage.removeItem("gid");
        Checkout.Storage.removeItem("wid");
        Checkout.Storage.removeItem("destination");
    };

    SignUp.submit = function () {
        const $subscribeBtn = $('#subscribe');

        if ($subscribeBtn.is(":disabled")) {
            return;
        }
        $subscribeBtn.attr('disabled', 'disabled');

        TdsProcess.init();

        const evSignUpSubmit = new Event("signUpSubmit", {bubbles: true});
        document.dispatchEvent(evSignUpSubmit);

        const customerInfo = {
            email: $('#email').val(),
            firstName: $('#first_name').val(),
            lastName: $('#last_name').val(),
            phoneNumber: $('#phone').val(),
            address: $('#address').val(),
            city: $('#city').val(),
            postalCode: $('#postal_code').val(),
            region: $('#region:not([disabled])').val(),
            country: $('#country').val(),
        };
        const cardFormInfo = {
            number: $('#card_number').val(),
            expYear: $('#card_expirity_year').val(),
            expMonth: $('#card_expirity_month').val(),
            cvv: $('#cvv').val(),
        };

        const websiteId = Checkout.Storage.getItem('wid');
        if (websiteId) {
            Checkout.Website.setId(websiteId);
        }

        const gatewayId = Checkout.Storage.getItem('gid');
        if (gatewayId) {
            Checkout.Gateway.setId(gatewayId);
        }

        const bin = cardFormInfo.number.substring(0, 6)

        Checkout.Auth.registerByMode(
            window.themeSettings.checkout_auth_mode,
            customerInfo,
            customerInfo.email,
            $('#password').val()
        ).then(function (regResponse) {
            var authToken = regResponse.user_access_token
            Checkout.Customer.get(authToken).then(function (customerInfo) {
                const planId = Checkout.Storage.getItem('pid');
                const planPromise = planId ? FW.getPromise('planInfo', planId) : $.Deferred().resolve();
                planPromise.then(function (planInfo) {
                    Checkout.Card.tokenize(customerInfo, cardFormInfo).then(function (cardToken) {
                        Checkout.Card.create(cardToken, authToken).then(function (cardInfo) {
                            window.addEventListener('message', TdsProcess.messageCallback);

                            Checkout.Card.authenticate(
                                cardInfo.id,
                                planInfo ? planInfo.preauthorizeAmount || planInfo.recurringAmount : 1,
                                planInfo ? planInfo.currency : FW.Partial.global('currency'),
                                undefined,
                                authToken
                            ).then(function (transactionInfo) {
                                window.removeEventListener('message', TdsProcess.messageCallback);

                                const evCardAuthenticate = new CustomEvent("cardAuthenticate", {
                                    bubbles: true,
                                    detail: {cf: cardInfo.customFields, tid: transactionInfo.id},
                                });
                                document.dispatchEvent(evCardAuthenticate);

                                const subscriptionPromise = planInfo
                                    ? Checkout.Customer.subscribe(planInfo.id, cardInfo.id, undefined, authToken)
                                    : $.Deferred().resolve();
                                subscriptionPromise.then(function () {
                                    const hasUpselling = Checkout.Storage.hasItem('upids') && Checkout.Storage.hasItem('ugid')
                                    const destination = Checkout.Storage.getItem('destination')
                                        || (hasUpselling ? '/#/upselling/' : '#/summary/');
                                    SignUp.clearSignUpPresets();
                                    Checkout.Customer.setToken(authToken);
                                    FW.resetPromise('authToken');
                                    FW.resetPromise('accessToken');

                                    if (hasUpselling) {
                                        FW.Partial.global('cardNumber', cardFormInfo.number);
                                    }

                                    window.location.href = destination;
                                }, notify);
                            }, function () {
                                window.removeEventListener('message', TdsProcess.messageCallback);
                                cardFailure(planInfo, bin);
                            });
                        }, function () {
                            cardFailure(planInfo, bin);
                        });
                    });
                }, notify);
            }, function () {
                Checkout.Customer.setToken(undefined);
                FW.resetPromise('authToken');
                FW.resetPromise('accessToken');
                notify('It seems you already have an account, please log in.');
                window.location.hash = '#/login/';
            });
        }, function (err) {
            if (err !== undefined && err.status !== undefined && err.status === 422) {
                handleValidationErrors(err.responseJSON)
            } else {
                console.log(err);
                Sentry.captureException(err);

                TdsProcess.hide();
                $subscribeBtn.attr('disabled', 'disabled');
                notify(undefined)
            }
        })
    };

    SignUp.registerValidators = function () {
        $('#first_name').on('blur change keyup', SignUp.validateFirstName);
        $('#last_name').on('blur change keyup', SignUp.validateLastName);
        $('#email').on('blur', SignUp.validateEmail);
        $('#password').on('blur change keyup', SignUp.validatePassword);
        $('#phone').on('blur change keyup', SignUp.validatePhoneNumber);
        $('#term_condition').on('click', SignUp.validateTerms);
        $('#country').on('blur change keyup', SignUp.validateCountry);
        $('#region').on('blur change keyup', SignUp.validateRegion);
        $('#city').on('blur change keyup', SignUp.validateCity);
        $('#address').on('blur change keyup', function () {
            Checkout.Customer.validateAddress($('#address').val()).then(function (valid) {
                switchInputState(valid, $('#address'))
                submitFormUpdate();
            }, console.error);
        });
        $('#postal_code').on('blur change keyup', SignUp.validatePostalCode);

        // validate card number
        $('#card_number').on('blur change keyup', function () {
            Checkout.Card.validateNumber($('#card_number').val()).then(function (valid) {
                switchInputState(valid, $('#card_number'))
                submitFormUpdate();
            }, console.error);
        });

        // validate card expiry month
        $('#card_expirity_month,#card_expirity_year').change(function () {
            Checkout.Card.validateExpirity($('#card_expirity_month').val(), $('#card_expirity_year').val()).then(function (valid) {
                if (valid) {
                    $('#card_expirity_month').removeClass('error').addClass('success');
                    $('#card_expirity_year').removeClass('error').addClass('success');
                } else {
                    $('#card_expirity_month').addClass('error').removeClass('success');
                    $('#card_expirity_year').addClass('error').removeClass('success');
                }
                submitFormUpdate();
            }, console.error);
        });

        // validate cvv2
        $('#cvv').on('blur change keyup', function () {
            Checkout.Card.validateCVV($('#cvv').val()).then(function (valid) {
                switchInputState(valid, $('#cvv'))
                submitFormUpdate();
            }, console.error);
        });
    };

    const submitFormUpdate = function () {
        const $invalidRequiredFields = $('#signup *[required]:not(.success):not([disabled])'),
            $invalidOptionalFields = $('#signup *:not([required]):not([disabled]).error'),
            $subscribeBtn = $('#subscribe');

        if ($invalidRequiredFields.length !== 0 || $invalidOptionalFields.length !== 0) {
            TdsProcess.hide();
            $subscribeBtn.attr('disabled', 'disabled');
            return false;
        }

        $subscribeBtn.removeAttr('disabled');
        return true;
    };

    function cardFailure(planInfo, bin) {
        if (planInfo && planInfo.redirectOnSignUpFail) {
            const params = {};
            const postbackParams = {};

            if (Checkout.Storage.hasItem('leadDP')) {
                params['dp'] = Checkout.Storage.getItem('leadDP');
            }
            if (Checkout.Storage.hasItem('email')) {
                params['email'] = Checkout.Storage.getItem('email');
            }
            if (Checkout.Storage.hasItem('password')) {
                params['password'] = Checkout.Storage.getItem('password');
            }
            if (Checkout.Storage.hasItem('leadSource')) {
                params['utm_source'] = Checkout.Storage.getItem('leadSource');
            }
            if (Checkout.Storage.hasItem('leadMedium')) {
                params['utm_medium'] = Checkout.Storage.getItem('leadMedium');
            }
            if (Checkout.Storage.hasItem('leadCampaign')) {
                params['utm_campaign'] = Checkout.Storage.getItem('leadCampaign');
            }
            if (Checkout.Storage.hasItem('leadTerm')) {
                params['utm_term'] = Checkout.Storage.getItem('leadTerm');
            }
            if (Checkout.Storage.hasItem('leadAffiliate')) {
                params['af'] = Checkout.Storage.getItem('leadAffiliate');
            }
            if (Checkout.Storage.hasItem('leadSubAffiliate')) {
                params['lf'] = Checkout.Storage.getItem('leadSubAffiliate');
            }
            if (Checkout.Storage.hasItem('leadClickId')) {
                params['cid'] = Checkout.Storage.getItem('leadClickId');
            }
            for (let i = 1; i <= 6; i++) {
                if (Checkout.Storage.hasItem('leadS' + i)) {
                    params['s' + i] = Checkout.Storage.getItem('leadS' + i);
                }
            }
            window.location.href = planInfo.redirectOnSignUpFail + '?nib=' + bin + '&' + Query.build(params, '&');
        } else {
            $('#tdsModal').addClass('d-none');
            notify('We were unable to verify your card');
        }
    }

    function handleValidationErrors(errors) {
        const keyField = [
            {id: 'email', key: 'primaryAddress.emails.0.value'},
            {id: 'first_name', key: 'primaryAddress.firstName'},
            {id: 'last_name', key: 'primaryAddress.lastName'},
            {id: 'address', key: 'primaryAddress.address'},
            {id: 'city', key: 'primaryAddress.city'},
            {id: 'region', key: 'primaryAddress.region'},
            {id: 'country', key: 'primaryAddress.country'},
            {id: 'postal_code', key: 'primaryAddress.postalCode'},
            {id: 'phone', key: 'primaryAddress.phoneNumbers.0.value'},
        ];
        keyField.forEach(el => {
            const error = errors.find(item => item.field === el.key);
            if (error !== undefined) {
                const $field = $('#' + el.id);
                switchInputState(false, $field)
            }
        })

        notify('Fill in the fields with valid data');
    }

    function notify(error) {
        const fallback = 'We were unable to process your request, please try again later';
        try {
            error = (typeof (error) === 'string' ? error : undefined) || fallback;
        } catch (e) {
            error = fallback;
        }
        userNotif(error, 'error', false);
        submitFormUpdate();
    }

    function notifyWith(error) {
        return function () {
            notify(error);
        };
    }

    function switchInputState(valid, $selector) {
        if (valid) {
            $selector.removeClass('error').removeClass('is-invalid').addClass('success');
        } else {
            $selector.parent().removeClass('d-none');
            $selector.addClass('error').addClass('is-invalid').removeClass('success');
        }
    }

    function isNotEmptyValidator(promise, $fieldSelector) {
        promise.then(function (valid) {
            switchInputState(valid, $fieldSelector)
            submitFormUpdate();
        }, console.error);
    }

    function isCheckedValidator($fieldSelector) {
        switchInputState($fieldSelector.is(':checked'), $fieldSelector)
        submitFormUpdate();
    }

    SignUp.validateCountry = function () {
        const $selector = $('#country');
        isNotEmptyValidator(Checkout.Customer.validateCountry($selector.val()), $selector);
    };

    SignUp.validateRegion = function () {
        const $selector = $('#region');
        isNotEmptyValidator(Checkout.Customer.validateRegion($selector.val()), $selector);
    };

    SignUp.validateCity = function () {
        const $selector = $('#city');
        isNotEmptyValidator(Checkout.Customer.validateCity($selector.val()), $selector);
    };

    SignUp.validatePostalCode =  function () {
        const $selector = $('#postal_code');
        isNotEmptyValidator(Checkout.Customer.validatePostalCode($selector.val()), $selector);
    };

    SignUp.validatePhoneNumber = function () {
        const $selector = $('#phone');
        if (typeof $selector.val() === 'string' && $selector.val().trim().length === 0) {
            $selector.removeClass(['error', 'success']);
            submitFormUpdate();
        } else {
            isNotEmptyValidator(Checkout.Customer.validatePhoneNumber($selector.val()), $selector);
        }
    };

    SignUp.validateFirstName = function () {
        const $selector = $('#first_name');
        isNotEmptyValidator(Checkout.Customer.validateFirstName($selector.val()), $selector);
    };

    SignUp.validateLastName = function () {
        const $selector = $('#last_name');
        isNotEmptyValidator(Checkout.Customer.validateLastName($selector.val()), $selector);
    };

    SignUp.validatePassword = function () {
        const $selector = $('#password');
        isNotEmptyValidator(Checkout.Customer.validatePassword($selector.val()), $selector);
    };

    SignUp.validateEmail = function () {
        const $selector = $('#email');
        Checkout.Customer.validateEmail($selector.val()).then(function (valid) {
            switchInputState(($selector.parent().hasClass('d-none') || valid) && $selector.val() !== '', $selector)
            submitFormUpdate();
        }, console.error);
    };

    SignUp.validateAcceptReoccurring = function () {
        isCheckedValidator($("#accept_reoccurring"));
    };

    SignUp.validateTerms = function () {
        isCheckedValidator($("#term_condition"));
    };

    SignUp.initProgressDialog = function (msg) {
        $('#tds-progress-message').html(msg);
        $('.tds-progress .progress-bar .track').removeClass('animate infinite');
        $('.tds-processing,.tds-img-icon.lock').show();
        $('.tds-img-icon.check').hide();
    };

    // // Function called if AdBlock is not detected
    // function adBlockNotDetected() {
    //     $('#aBOverlay').addClass('d-none');
    // }
    //
    // // Function called if AdBlock is detected
    // function adBlockDetected() {
    //     $('#aBOverlay').removeClass('d-none');
    // }

    // function detectAdBlock() {
    //     if (typeof fuckAdBlock === 'undefined' || typeof FuckAdBlock === 'undefined') {
    //         var importFAB = document.createElement('script');
    //         importFAB.onload = function () {
    //             // If all goes well, we configure FuckAdBlock
    //             fuckAdBlock.onDetected(adBlockDetected)
    //             fuckAdBlock.onNotDetected(adBlockNotDetected);
    //         };
    //         importFAB.onerror = function () {
    //             // If the script does not load (blocked, integrity error, ...)
    //             // Then a detection is triggered
    //             adBlockDetected();
    //         };
    //
    //         importFAB.src = 'https://cdnjs.cloudflare.com/ajax/libs/fuckadblock/3.2.1/fuckadblock.min.js';
    //         document.head.appendChild(importFAB);
    //     }
    // }

    function GlobeData () {
        const _this = this,
            countries = {},
            regions = {};
        let currentLanguage = null;

        this.loadCountriesAndRegions = function (lang) {
            return $.getJSON($('meta[property="theme:path"]').attr('content') + '/assets/map-regions/' + lang + '.json')
                .then(function (data) {
                    const countries = [],
                        regions = {};
                    $.each(data, function (_, countryData) {
                        const countryName = countryData[0],
                            countryCode = countryData[1],
                            regionsData = countryData[2];
                        countries.push([countryCode, countryName]);

                        regions[countryCode] = [];
                        $.each(regionsData, function (_, regionData) {
                            const regionName = regionData[0],
                                regionCode = regionData[1];
                            regions[countryCode].push([regionCode, regionName]);
                        });
                    });

                    const deferred = $.Deferred();
                    deferred.resolve(lang, countries, regions);
                    return deferred.promise();
                });
        };

        this.loadAndRenderCountriesAndRegions = function (lang) {
            const deferred = $.Deferred(),
                successFactory = function (lang) {
                    return function () {
                        fillCountryAndRegionSelectors();
                        deferred.resolve(lang);
                    };
                };

            $('#country').on('change', function () {
                fillRegionSelector($(this).val());
            });

            if (typeof countries[lang] !== 'undefined') {
                successFactory(lang)();
                return deferred.promise();
            }

            // TODO Enable loader
            this.loadCountriesAndRegions(lang)
                .done(
                    setInnerData,
                    successFactory(lang)
                )
                .fail(function () {
                    // Fallback if no translation found.
                    _this.loadCountriesAndRegions('en')
                        .done(
                            setInnerData,
                            fillCountryAndRegionSelectors,
                            successFactory('en')
                        )
                        .fail(function () {
                            deferred.reject();
                        });
                })
                .always(function () {
                    // TODO Disable loader
                });

            return deferred.promise();
        };

        const setInnerData = function (lang, countriesData, regionsData) {
            currentLanguage = lang;
            countries[lang] = countriesData;
            regions[lang] = regionsData;
        };

        const fillCountryAndRegionSelectors = function () {
            const $countrySelector = $('#country');

            $.each(countries[currentLanguage], function (_, countryData) {
                $countrySelector.append($('<option>', {
                    value: countryData[0],
                    text: countryData[1],
                }));
            });

            fillRegionSelector($countrySelector.val());
        };

        const fillRegionSelector = function (countryCode) {
            const $regionContainerSelector = $('#region_container'),
                $regionListSelector = $('#region'),
                $regionLabelSelector = $('#region_label'),
                countryRegions = (regions[currentLanguage] || [])[countryCode] || [];

            if (countryRegions.length === 0) {
                $regionListSelector.attr('disabled', true);
                return;
            }

            $regionContainerSelector.show();
            $regionLabelSelector.show();
            $regionListSelector.attr('disabled', false).show()
                .find('option[value != ""]')
                .remove()
                .end()
                .val('')
                .trigger('change');
            $.each(countryRegions, function (_, regionData) {
                $regionListSelector.append($('<option>', {
                    value: regionData[0],
                    text: regionData[1],
                }));
            });
        };

        this.detectCountryAndRegion = function () {
            return $.getJSON('https://api.host.sh/v2/lookup/')
                .then(function (response) {
                    const
                        countryCode = response.geo.country.code || null,
                        regionCode = response.geo.subdivision.code || null,
                        regionName = response.geo.subdivision.name || null,
                        $countrySelector = $('#country'),
                        $regionSelector = $('#region'),
                        $countryOption = $('> option[value="' + countryCode + '"]', $countrySelector),
                        countryExists = countryCode && $countryOption.length;

                    if (countryExists && $countrySelector.val() === "") {
                        $countrySelector.val(countryCode).trigger('change');
                    } else if($countrySelector.is(":hidden")) {
                        $countrySelector.removeAttr('hidden');
                    }

                    const $regionOption = $('> option[value="' + regionCode + '"]', $regionSelector);
                    if (countryExists && regionCode && $regionOption.length && $regionSelector.val() === "") {
                        $regionSelector.val(regionCode).trigger('change');
                    } else if($regionSelector.is(":hidden")) {
                        $regionSelector.removeAttr('hidden');
                    }

                    const deferred = $.Deferred();
                    deferred.resolve(countryCode, regionCode, regionName);
                    return deferred.promise();
                }).catch(function () {
                    const $countrySelector = $('#country'),
                          $regionSelector = $('#region');
                    if($countrySelector.is(":hidden")) {
                        $countrySelector.removeAttr('hidden');
                    }
                    if($regionSelector.is(":hidden")) {
                        $regionSelector.removeAttr('hidden');
                    }
              });
        };
    }

    const TdsProcess = {
        progressTimeout: null,
        init: function () {
            SignUp.initProgressDialog('Just a moment while we securely process & verify your credit card information...');
            $('#tdsModal').removeClass('d-none');

            // Starting progress bar
            $('.tds-progress .progress-bar .track').addClass('animate');
            const _this = this;
            this.progressTimeout = setTimeout(function () {
                $('.tds-img-icon.lock').fadeOut();
                $('.tds-img-icon.check').fadeIn('slow');
                // Hide tds processing div
                _this.progressTimeout = setTimeout(function () {
                    $('.tds-processing').fadeOut();
                }, 2000);
            }, 12000); //*IMPORTANT* this time delay needs to be the SAME as the .animate class tdsPrgress Animation in styles.scss
        },
        hide: function () {
            clearTimeout(this.progressTimeout);
            $('#tdsModal').addClass('d-none');
        },
        messageCallback: function (event) {
            if (event && event.data && event.data.callback) {
                clearTimeout(this.progressTimeout);
                SignUp.initProgressDialog('Thank you. We are processing your request.');
                $('.tds-progress .progress-bar .track').addClass('animate infinite');
                setTimeout(function () {
                    $('#tds-progress-message').html('We are still processing. Just a little longer!');
                }, 10000);
            }
        },
    };

    window.SignUp = SignUp;
    window.GlobeData = new GlobeData();
    window.TdsProcess = TdsProcess;
})(window);

FW.Router.register('^\/signup\/(.*)?$', function (full, query) {

    var deferred = $.Deferred();

    FW.getPromise('authToken').then(function () {
        deferred.reject();
        window.location.hash = '#/settings/';
    }, function () {
        deferred.resolve({pageTitle: 'Signup'});
        return undefined;
    });

    FW.Partial.data('signup', deferred.promise());
    FW.Partial.data('page-signup', FW.getPromise('i18n'));

    FW.Partial.render('page-signup', $('[data-placeholder="page"]')).then(function () {
        updateUI(); // FIXME TODO
        $('html, body').animate({scrollTop: 0}, 250);

        if (Checkout.Storage.hasItem('pid')) {
            SignUp.selectPlan(Checkout.Storage.getItem('pid'), 'Sign Up');
        } else {
            SignUp.switchPlan();
        }

        $('[data-plan-id-btn]').click(function () {
            var planId = $(this).data('plan-id-btn');
            if (planId !== '') {
                Checkout.Storage.setItem('pid', planId);
            } else {
                Checkout.Storage.removeItem('pid');
            }
            SignUp.selectPlan(planId, 'Sign Up');
        });

        $('[data-switch-plan]').click(function () {
            SignUp.switchPlan();
        });

        SignUp.registerValidators();

        Checkout.init().then(function () {
            GlobeData.loadAndRenderCountriesAndRegions(FW.Partial.global('language'))
                .done(GlobeData.detectCountryAndRegion);
        });

        $('#subscribe').click(function (event) {
            event.preventDefault();
            SignUp.submit();
        });
    });
});

FW.Router.register('^\/summary\/$', function (full, query) {
    if (Checkout.Storage.hasItem('showWelcome')) {
        return window.location.hash = '#/welcome/';
    }

    var deferred = $.Deferred();
    FW.getPromise('customerInfo').then(function (customerInfo) {
        var customerPlan = Subscription.getCustomerPlan(customerInfo.subscriptions);
        if (!jQuery.isEmptyObject(customerPlan)) {
            FW.getPromise('planInfo', customerPlan.id).then(function (plan) {
                deferred.resolve({
                    pageTitle: 'Order Summary',
                    customer: customerInfo,
                    customerPlan: {
                        status: customerPlan.status,
                        renewalTime: customerPlan.renewalTime,
                        plan: plan
                    }
                });
            }, function () {
                deferred.reject();
                window.location.hash = '#/login/';
            });
        } else {
            deferred.reject();
            window.location.hash = '#/login/';
        }
    }, function () {
        deferred.reject();
        window.location.hash = '#/login/';
    });

    FW.Partial.data('summary', deferred.promise());
    FW.Partial.data('page-summary', FW.getPromise('i18n'));

    FW.Partial.render('page-summary', $('[data-placeholder="page"]')).then(function () {
        updateUI(); // FIXME TODO
        $('html, body').animate({scrollTop: 0}, 250);
    });

});

FW.Router.register('^\/browse\/(.*)?$', function (full, query) {

    var deferred = $.Deferred();

    FW.getPromise('accessToken').then(function (accessToken) {
        return accessToken;
    }, function () {
        return undefined;
    }).then(function (accessToken) {
        var extra = {limit: FW.Partial.global('itemsPerPage')};
        if (accessToken) {
            extra.token = accessToken;
        }
        function request(planInfo) {
            if ((planInfo || {}).fullAccess) {
                extra.full = 1;
            } else if (window.categories) {
                extra.only = window.categories;
            }
            var url = FW.Partial.global('backendApiUrl') + 'books/?' + Query.build(Object.assign(extra, FW.Partial.global('browseFilters')), '&');
            $.ajax({url: url}).then(function (data) {
                FW.getPromise('userInfo').catch(function () {
                    return undefined;
                }).then(function (user) {
                    deferred.resolve({
                        data: data,
                        showNext: (data.length >= FW.Partial.global('itemsPerPage')),
                        pageTitle: 'Browse',
                        accessToken: accessToken,
                        user: user
                    });
                });
            }, function (error) {
                deferred.reject(error);
            });
        }
        if (accessToken) {
            FW.getPromise('customerInfo').then(function (customerInfo) {
                return Subscription.getCustomerPlan(customerInfo.subscriptions).id;
            }, function () {}).then(function (planId) {
                FW.getPromise('planInfo', planId).then(request, function () {
                    request();
                });
            });
        } else {
            request();
        }
    });

    FW.Partial.data('browse', deferred.promise());
    FW.Partial.data('page-browse', FW.getPromise('i18n'));
    var url = FW.Partial.global('backendApiUrl') + 'categories/?top=11&_include[]=subcategories';
    if (window.categories) {
        url += '&only=' + window.categories;
    }
    FW.Partial.data('sidebar-filter', $.ajax({url: url}).then(function (data) {
        return {obj: data};
    }));

    FW.Partial.render('page-browse', $('[data-placeholder="page"]')).then(function () {
        creditsRangeSlider(); // FIXME TODO
        updateUI(); // FIXME TODO

        $('[data-book-id].favorite').click(function () {
            favorites.toggle(this);
        });

        $('.pagination-box a.previous,.pagination-box a.next').click(function () {
            var filters = FW.Partial.global('browseFilters');
            filters.page = $(this).data('page');
            var query = Query.build(filters, '/');
            window.location.hash = '#/browse/' + (query ? query + '/' : '');
        });

        $('[data-action="browse:apply-filters"]').click(function () {
            var filters = {};
            var format = $('[name=product-format]:checked').map(function () {
                return $(this).val();
            }).get().join(',');
            if (format) {
                filters.format = format;
            }

            var language = $('[name=product-language]:checked').map(function () {
                return $(this).val();
            }).get().join(',');
            if (language) {
                filters.language = language;
            }

            var category = (function (elements) {
                if ($('#select-genres-search>option:selected').val()) {
                    var prev = $('#select-genres-search>option:selected').val().split(',');
                    for (var index = 0; index < prev.length; index++)
                        elements[prev[index]] = prev[index];
                }
                $('[name=product-catfilter]').each(function () {
                    var $this = $(this);
                    var value = $this.val();
                    elements[value] = $this.is(":checked") ? value : undefined;
                });
                return elements;
            })([]).filter(function (el) {
                return el != null;
            }).join(',');
            if (category) {
                filters.category = category;
            }

            var search = $('#search-bar').val();
            if (search) {
                filters.search = search;
            }

            var upper = parseInt(($('#slider-snap-value-upper').html() || '' + FW.Partial.global('creditsHighThreshold')).replace(',', '').replace('+', ''));
            if (FW.Partial.global('creditsHighThreshold') !== upper) {
                filters.creditsMax = upper;
            }

            var low = parseInt(($('#slider-snap-value-lower').html() || '' + FW.Partial.global('creditsLowThreshold')).replace(',', ''));
            if (FW.Partial.global('creditsLowThreshold') !== low) {
                filters.creditsMin = low;
            }


            var query = Query.build(filters, '/');
            window.location.hash = '#/browse/' + (query ? query + '/' : '');
        });

        $('html, body').animate({scrollTop: 0}, 250);

    });
});

FW.init().then(function (FW) {
    FW.Partial.data('header', FW.getPromise('accessToken').catch(function () {
            return undefined;
        }).then(function (accessToken) {
            return {accessToken: accessToken};
        })
    );
    $(document).on('click', '#submit-search-btn', function (event) {
        var filters = {};

        var category = $("#select-genres-search").val();
        if (category) {
            filters.category = category;
        }

        var search = $("#search-bar").val().trim();
        if (search) {
            filters.search = search;
        }

        var query = Query.build(filters, '/');
        window.location.hash = '#/browse/' + (query ? query + '/' : '');
        event.preventDefault();
    });
    $(document).on("keypress", "#search-form", function (event) {
        if (event.keyCode === 13) {
            $('#submit-search-btn').click();
            event.preventDefault();
        }
    });
});


FW.Router.register('^\/settings\/(.*)?$', function (full, query) {
    var deferredSettings = $.Deferred();
    var deferredTopMenu = $.Deferred();

    FW.getPromise('accessToken').then(function (accessToken) {
        FW.resetPromise('customerInfo');
        $.when.apply($, [
            $.ajax({url: FW.Partial.global('backendApiUrl') + 'user-info/?' + Query.build({token: accessToken}, '&')}),
            FW.getPromise('customerInfo')
        ]).then(function (r1, r2) {
            var customerPlan = Subscription.getCustomerPlan(r2.subscriptions);
            if (jQuery.isEmptyObject(customerPlan)) {
                deferredSettings.resolve({
                    pageTitle: 'Settings',
                    customer: r2,
                    customerPlan: customerPlan
                });
                deferredTopMenu.resolve({
                    user: r1[0],
                    customer: r2,
                    customerPlan: customerPlan
                });
            } else {
                FW.getPromise('planInfo', customerPlan.id).then(function (plan) {
                    customerPlan.name = plan.name;
                    deferredSettings.resolve({
                        pageTitle: 'Settings',
                        customer: r2,
                        customerPlan: customerPlan
                    });
                    deferredTopMenu.resolve({
                        user: r1[0],
                        customer: r2,
                        customerPlan: customerPlan
                    });
                }, function () {
                    deferredSettings.reject();
                    deferredTopMenu.reject();
                });
            }
        }, function () {
            deferredSettings.reject();
            deferredTopMenu.reject();
        });
    }, function () {
        deferredSettings.reject();
        deferredTopMenu.reject();
        window.location.hash = '#/login/';
    });

    FW.Partial.data('settings', deferredSettings.promise());
    FW.Partial.data('page-settings', FW.getPromise('i18n'));
    FW.Partial.data('dashboard-topmenu', deferredTopMenu.promise());

    FW.Partial.render('page-settings', $('[data-placeholder="page"]')).then(function () {
        updateUI(); // FIXME TODO
        $('html, body').animate({scrollTop: 0}, 250);

        // Change password
        $('#btn-save-new-password').click(function (e) {
            function reportError(error) {
                $('#btn-save-new-password').prop('disabled', false);
                $('#new-password,#re-new-password').addClass('error');
                userNotif(error || "Error changing password", 'error', false);
            }

            e.preventDefault();

            var newPass = $('#new-password').val();
            var reNewPass = $('#re-new-password').val();

            $('#btn-save-new-password').prop('disabled', true);

            if (newPass !== reNewPass || newPass === '') {
                reportError("Passwords don't match");
                return;
            }

            Checkout.init().then(function () {
                Checkout.Customer.validatePassword(newPass).then(function (valid) {
                    if (!valid) {
                        reportError('Invalid password');
                        return;
                    }

                    FW.getPromise('authToken').then(function (authToken) {
                        FW.getPromise('customerInfo').then(function (customerInfo) {
                            FW.resetPromise('authToken');
                            Checkout.Auth.changePasswordByMode(
                                window.themeSettings.checkout_auth_mode,
                                customerInfo.email,
                                newPass,
                                true,
                                authToken,
                            ).then(function () {
                                userNotif("Password was successfully changed", 'success', false);
                                window.location.hash = '#/settings/updated=' + Date.now() + '/';
                            }, reportError);
                        }, reportError);
                    }, reportError);
                }, console.error);
            }, reportError);
        });

        // Cancel subscription
        $('#cancel-subscription-button').click(function () {
            $('#js-cancelSub').modal('hide');
            var subscriptionId = $('#js-cancelSub-id').data('subs-id');
            Checkout.init().then(function () {
                Checkout.Subscription.cancel(subscriptionId).then(
                    function (sub) {
                        userNotif("Subscription successfully cancelled", 'success', false);
                        $('#subStatusSpan').html(sub.status);
                        $('#cancel-sub-header,#cancel-sub-ul').remove();
                        //window.location.hash = '#/settings/updated=' + Date.now() + '/';
                    },
                    function () {
                        userNotif("Error cancelling subscription", 'error', false);
                    }
                );
            });
        });
    });
});

FW.Router.register('^\/favorites\/(.*)?$', function (full, query) {

    var deferredFavorites = $.Deferred();
    var deferredTopMenu = $.Deferred();

    FW.getPromise('accessToken').then(function (accessToken) {

        var extra = {limit: FW.Partial.global('itemsPerPage')};
        extra.token = accessToken;

        FW.resetPromise('customerInfo');
        $.when.apply($, [
            $.ajax({url: FW.Partial.global('backendApiUrl') + 'user-info/?' + Query.build({token: accessToken}, '&')}),
            FW.getPromise('customerInfo'),
            $.ajax({url: FW.Partial.global('backendApiUrl') + 'user-favorites/?' + Query.build(Object.assign(extra, FW.Partial.global('browseFilters')), '&')})

        ]).then(function (r1, r2, r3) {

            var customerPlan = Subscription.getCustomerPlan(r2.subscriptions);
            if (jQuery.isEmptyObject(customerPlan)) {
                deferredFavorites.resolve({
                    pageTitle: 'Favorites',
                    data: r3[0],
                    showNext: r3[0].showNext,
                    customerPlan: customerPlan
                });
                deferredTopMenu.resolve({
                    user: r1[0],
                    customer: r2,
                    customerPlan: customerPlan
                });
            } else {
                FW.getPromise('planInfo', customerPlan.id).then(function (plan) {
                    r3[0].showNext = (r3[0].length == FW.Partial.global('itemsPerPage'));
                    customerPlan.name = plan.name;
                    deferredFavorites.resolve({
                        pageTitle: 'Favorites',
                        data: r3[0],
                        showNext: r3[0].showNext,
                        customerPlan: customerPlan
                    });
                    deferredTopMenu.resolve({
                        user: r1[0],
                        customer: r2,
                        customerPlan: customerPlan
                    });
                }, function () {
                    deferredFavorites.reject();
                    deferredTopMenu.reject();
                });
            }

        }, function () {
            deferredFavorites.reject();
            deferredTopMenu.reject();
        });
    }, function () {
        deferredFavorites.reject();
        deferredTopMenu.reject();
        window.location.hash = '#/login/';
    });

    FW.Partial.data('favorites', deferredFavorites.promise());
    FW.Partial.data('page-favorites', FW.getPromise('i18n'));
    FW.Partial.data('dashboard-topmenu', deferredTopMenu.promise());

    FW.Partial.render('page-favorites', $('[data-placeholder="page"]')).then(function () {
        updateUI(); // FIXME TODO
        $('html, body').animate({scrollTop: 0}, 250);

        $('.pagination-box a.previous,.pagination-box a.next').click(function () {
            var filters = FW.Partial.global('browseFilters');
            filters.page = $(this).data('page');
            var query = Query.build(filters, '/');
            window.location.hash = '#/favorites/' + (query ? query + '/' : '');
        });

        $('.dasboard-favorite-actions a[data-book-id]').click(function () {
            favorites.remove(this);
        });
    });

});

FW.Router.register('^\/library\/(.*)?$', function (full, query) {
    var deferredLibrary = $.Deferred();
    var deferredTopMenu = $.Deferred();
    var url, data;

    FW.getPromise('accessToken').then(function (accessToken) {
        var extra = {limit: FW.Partial.global('itemsPerPage')};
        extra.token = accessToken;
        extra.group = 1;

        FW.resetPromise('customerInfo');
        url = FW.Partial.global('backendApiUrl') + 'user-purchases/?' + Query.build(Object.assign(extra, FW.Partial.global('browseFilters')), '&');
        $.when.apply($, [
            $.ajax({url: url}),
            $.ajax({url: FW.Partial.global('backendApiUrl') + 'user-info/?' + Query.build({token: accessToken}, '&')}),
            FW.getPromise('customerInfo')
        ]).then(function (userPurchases, userInfo, customerInfo) {
            data = JSON.stringify(userPurchases[0]);
            var customerPlan = Subscription.getCustomerPlan(customerInfo.subscriptions);
            if (jQuery.isEmptyObject(customerPlan)) {
                deferredLibrary.resolve({
                    pageTitle: 'Library',
                    data: userPurchases[0],
                    accessToken: accessToken,
                    showNext: userPurchases[0].length >= FW.Partial.global('itemsPerPage'),
                    customerPlan: customerPlan
                });
                deferredTopMenu.resolve({
                    user: userInfo[0],
                    customer: customerInfo,
                    customerPlan: customerPlan
                });
            } else {
                FW.getPromise('planInfo', customerPlan.id).then(function (plan) {
                    customerPlan.name = plan.name;
                    deferredLibrary.resolve({
                        pageTitle: 'Library',
                        data: userPurchases[0],
                        accessToken: accessToken,
                        showNext: userPurchases[0].length >= FW.Partial.global('itemsPerPage'),
                        customerPlan: customerPlan
                    });
                    deferredTopMenu.resolve({
                        user: userInfo[0],
                        customer: customerInfo,
                        customerPlan: customerPlan
                    });
                }, function () {
                    deferredLibrary.reject();
                    deferredTopMenu.reject();
                });
            }
        }, function () {
            deferredLibrary.reject();
            deferredTopMenu.reject();
        });
    }, function () {
        deferredLibrary.reject();
        deferredTopMenu.reject();
        window.location.hash = '#/login/';
    });

    FW.Partial.data('library', deferredLibrary.promise());
    FW.Partial.data('page-library', FW.getPromise('i18n'));
    FW.Partial.data('dashboard-topmenu', deferredTopMenu.promise());

    FW.Partial.render('page-library', $('[data-placeholder="page"]')).then(function () {
        updateUI(); // FIXME TODO
        //$('html, body').animate({scrollTop: 0}, 250);

        $('.pagination-box a.previous,.pagination-box a.next').click(function () {
            var filters = FW.Partial.global('browseFilters');
            filters.page = $(this).data('page');
            var query = Query.build(filters, '/');
            window.location.hash = '#/library/' + (query ? query + '/' : '');
        });

        function reload() {
            if (window.location.hash.substring(1, 10) == '/library/') {
                $.ajax({url: url}).then(function (userPurchases) {
                    var json = JSON.stringify(userPurchases);
                    if (data == json) {
                        setTimeout(reload, 10000);
                    } else {
                        FW.reload();
                    }
                }, function () {
                    setTimeout(reload, 10000);
                });
            }
        }
        setTimeout(reload, 10000);
    });

});

FW.Router.register('^\/reset[-]password\/$', function (full, query) {
    var deferred = $.Deferred();

    FW.getPromise('authToken').then(function () {
        deferred.resolve({pageTitle: 'Reset password'});
    }, function () {
        deferred.reject();
        window.location.hash = '#/login/';
    });

    FW.Partial.data('reset-password', deferred.promise());
    FW.Partial.data('page-reset-password', FW.getPromise('i18n'));

    FW.Partial.render('page-reset-password', $('[data-placeholder="page"]')).then(function () {
        updateUI(); // FIXME TODO

        var $resetPasswordBtn = $('#reset-password-btn');

        $('html, body').animate({scrollTop: 0}, 250);

        // Change password
        $resetPasswordBtn.click(function (e) {
            function reportError(error) {
                $resetPasswordBtn.prop('disabled', false);
                $('#confirm_resetpassword, #reconfirm_resetpassword').addClass('error');
                userNotif(error || "Error resetting password", 'error', false);
            }

            e.preventDefault();

            var newPass = $('#confirm_resetpassword').val();
            var reNewPass = $('#reconfirm_resetpassword').val();

            $resetPasswordBtn.prop('disabled', true);

            if (newPass !== reNewPass || newPass === '') {
                reportError("Passwords don't match");
                return;
            }

            Checkout.init().then(function () {
                Checkout.Customer.validatePassword(newPass).then(function (valid) {
                    if (!valid) {
                        reportError('Invalid password');
                        return;
                    }

                    FW.getPromise('authToken').then(function (authToken) {
                        FW.getPromise('customerInfo').then(function (customerInfo) {
                            FW.resetPromise('authToken');
                            Checkout.Auth.changePasswordByMode(
                                window.themeSettings.checkout_auth_mode,
                                customerInfo.email,
                                newPass,
                                true,
                                authToken,
                            ).then(function () {
                                userNotif("Password was successfully changed", 'success', false);
                                window.location.hash = '#/settings/'
                            }, reportError);
                        }, reportError);
                    }, reportError);
                }, console.error);
            }, reportError);
        });

        $('#confirm_resetpassword, #reconfirm_resetpassword').keypress(function (event) {
            if (event.keyCode === 13) {
                $resetPasswordBtn.click();
                event.preventDefault();
            }
        });
    });
});

FW.Router.register('^\/credits\/$', function (full, query) {

    FW.Partial.data('credits', $.Deferred().resolve({pageTitle: 'Credits & Returns Policy'}).promise());
    FW.Partial.data('page-credits', FW.getPromise('i18n'));
    FW.Partial.render('page-credits', $('[data-placeholder="page"]')).then(function () {

        updateUI(); // FIXME TODO
        $('html, body').animate({scrollTop: 0}, 250);

    });
});

FW.Router.register('^\/faq\/$', function (full, query) {

    FW.Partial.data('faq', $.Deferred().resolve({pageTitle: 'Customer Support & FAQ'}).promise());
    FW.Partial.data('page-faq', FW.getPromise('i18n'));
    FW.Partial.render('page-faq', $('[data-placeholder="page"]')).then(function () {

        updateUI(); // FIXME TODO
        $('html, body').animate({scrollTop: 0}, 250);

    });
});

FW.Router.register('^\/privacy\/$', function (full, query) {

    FW.Partial.data('privacy', $.Deferred().resolve({pageTitle: 'Privacy Policy'}).promise());
    FW.Partial.data('page-privacy', FW.getPromise('i18n'));
    FW.Partial.render('page-privacy', $('[data-placeholder="page"]')).then(function () {

        updateUI(); // FIXME TODO
        $('html, body').animate({scrollTop: 0}, 250);

    });
});

FW.Router.register('^\/about\/$', function (full, query) {

    FW.Partial.data('about', $.Deferred().resolve({pageTitle: 'About Us'}).promise());
    FW.Partial.data('page-about', FW.getPromise('i18n'));
    FW.Partial.render('page-about', $('[data-placeholder="page"]')).then(function () {

        updateUI(); // FIXME TODO
        $('html, body').animate({scrollTop: 0}, 250);

    });
});

FW.Router.register('^\/terms\/$', function (full, query) {

    FW.Partial.data('terms', $.Deferred().resolve({pageTitle: 'Terms Of Service'}).promise());
    FW.Partial.data('page-terms', FW.getPromise('i18n'));
    FW.Partial.render('page-terms', $('[data-placeholder="page"]')).then(function () {

        updateUI(); // FIXME TODO
        $('html, body').animate({scrollTop: 0}, 250);

    });
});

FW.Router.register('^\/contact\/$', function (full, query) {
    FW.Partial.data('contact-us', $.Deferred().resolve({pageTitle: 'Contact Us'}).promise());
    FW.Partial.data('page-contact-us', FW.getPromise('i18n'));

    FW.Partial.render('page-contact-us', $('[data-placeholder="page"]')).then(function () {
        updateUI(); // FIXME TODO
        $('html, body').animate({scrollTop: 0}, 250);
    });
});

(function (window) {
    var Subscription = {};

    Subscription.formatDate = function (date) {
        var monthNames = [
            "January", "February", "March",
            "April", "May", "June", "July",
            "August", "September", "October",
            "November", "December"
        ];

        var day = date.getDate();
        var monthIndex = date.getMonth();
        var year = date.getFullYear();

        return monthNames[monthIndex] + ' ' + day + ' ' + year;
    };

    Subscription.isValidActiveSubscription = function (_item) {
        if (_item.orderType !== 'subscription') {
            return false
        }
        if (_item.status.substr(0, 6).toLowerCase() === 'active') {
            return true
        }

        var dateOk = false;
        if (!_item.endTime) {
            dateOk = true;
        } else {
            var q = new Date();
            var nowDate = new Date(q.getFullYear(), q.getMonth(), q.getDate(), q.getHours(),
                q.getMinutes(), q.getSeconds());
            var endDate = new Date(_item.endTime.replace(' ', 'T'));
            if (endDate > nowDate) {
                dateOk = true;
            }
        }

        return dateOk;
    };

    Subscription.getCustomerPlan = function (subs) {
        var plan = {};
        $.each(subs, function (index, item) {
            if (Subscription.isValidActiveSubscription(item)) {
                plan.id = item.planId;
                plan.status = item.status;
                plan.renewalTime = item.renewalTime;
                plan.subscriptionId = item.id;
            }
        });
        return plan;
    };

    window.Subscription = Subscription;

})(window);

(function (window) {
    var favorites = {};

    favorites.toggle = function (el) {
        var method;
        if ($(el).hasClass('fav')) {
            $(el).removeClass('fav').addClass('notfav');
            $(el).html('<i class="ion ion-md-heart-empty"></i> Add to Favorites</a>');
            $(el).closest('.single-product-wrap').find('.product-favorite').addClass('d-none');
            method = 'DELETE';
        } else {
            $(el).removeClass('notfav').addClass('fav');
            $(el).html('<i class="icon-heart-slash"></i> Remove from Favorites</a>');
            $(el).closest('.single-product-wrap').find('.product-favorite').removeClass('d-none');
            method = 'POST';
        }
        var bookId = $(el).data('book-id');
        FW.getPromise('accessToken').then(function (accessToken) {
            $.ajax({
                url: FW.Partial.global('backendApiUrl') + 'user-favorite/' + accessToken + '/' + bookId + '/',
                type: method
            }).done(function (data) {
            });
        }, function () {
            // TODO: store somewhere
        });
    };

    favorites.remove = function (el) {
        $('[data-fav-item=' + $(el).attr('data-book-id') + ']').remove();
        var bookId = $(el).attr('data-book-id');
        FW.getPromise('accessToken').then(function (accessToken) {
            $.ajax({
                url: FW.Partial.global('backendApiUrl') + 'user-favorite/' + accessToken + '/' + bookId + '/',
                type: 'DELETE'
            }).done(function (data) {
            });
        }, function () {});
    };

    window.favorites = favorites;
})(window);

FW.init().then(function (FW) {
    FW.registerPromise(
        'planInfo',
        function (planId) {
            var deferred = $.Deferred();
            var resolved = FW.Partial.global('plans')[planId];
            if (resolved) {
                deferred.resolve(resolved);
            } else {
                Checkout.init().then(function () {
                    Checkout.Plan.get(planId).then(deferred.resolve, deferred.reject);
                }, deferred.reject);
            }
            return deferred.promise();
        },
        []
    );

    FW.registerPromise(
        'authToken',
        function () {
            var deferred = $.Deferred();
            var token = Checkout.Customer.getToken();
            if (token) {
                deferred.resolve(token);
            } else {
                deferred.reject();
            }
            return deferred.promise();
        },
        []
    );

    FW.registerPromise(
        'contentInfo',
        function () {
            var deferred = $.Deferred();
            Checkout.init().then(function () {
                FW.getPromise('authToken').then(function (authToken) {
                    Checkout.Content.get(FW.Partial.global('contentId'), authToken).then(
                        deferred.resolve,
                        function (error) {
                            deferred.reject(error);
                            FW.resetPromise('authToken');
                            if (!window.redirecting) {
                                Checkout.Customer.setToken(undefined);
                                window.location.hash = '#/login/';
                            }
                        }
                    );
                }, deferred.reject);
            }, deferred.reject);
            return deferred.promise();
        },
        ['authToken']
    );

    FW.registerPromise(
        'accessToken',
        function () {
            var deferred = $.Deferred();
            FW.getPromise('authToken').then(function () {
                FW.getPromise('contentInfo').then(function (contentInfo) {
                    if (!contentInfo.token) {
                        deferred.reject();
                    }
                    deferred.resolve(contentInfo.token);
                }, deferred.reject);
            }, deferred.reject);
            return deferred.promise();
        },
        ['authToken', 'contentInfo']
    );

    FW.registerPromise(
        'userInfo',
        function () {
            var deferred = $.Deferred();
            FW.getPromise('accessToken').then(function (accessToken) {
                $.ajax({url: FW.Partial.global('backendApiUrl') + 'user-info/?' + Query.build({token: accessToken})}).then(deferred.resolve, deferred.reject);
            }, deferred.reject);
            return deferred.promise();
        },
        ['accessToken']
    );

    FW.registerPromise(
        'customerInfo',
        function () {
            var deferred = $.Deferred();
            Checkout.init().then(function () {
                FW.getPromise('authToken').then(function (authToken) {
                    Checkout.Customer.get(authToken).then(
                        deferred.resolve,
                        function (error) {
                            deferred.reject(error);
                            FW.resetPromise('authToken');
                            if (!window.redirecting) {
                                Checkout.Customer.setToken(undefined);
                                window.location.hash = '#/login/';
                            }
                        }
                    );
                }, deferred.reject);
            }, deferred.reject);
            return deferred.promise();
        },
        ['authToken']
    );

    FW.reload = function () {
        FW.Partial.reset();
        var $modal = $('.modal');
        var routeCallback = function () {
            $modal.remove();
            FW.Router.route((location.hash || '').slice(1));
        };
        if ($modal.length && $modal.hasClass('show')) {
            $modal.modal('hide').on('hidden.bs.modal', routeCallback);
        } else {
            routeCallback();
        }
    }

    if (Query.getItem('token')) {
        Checkout.Customer.setToken(Query.getItem('token'));
        location.href = location.protocol + "//" + location.hostname +
            (location.port && location.port != 80 && location.port != 443 ? ':' + location.port : '') +
            location.pathname + location.hash;
        window.redirecting = true;
    } else {
        var hash;
        $(window).bind('hashchange', function (event) {
            FW.Partial.data('user-menu', FW.getPromise('accessToken').then(function (accessToken) {
                return {accessToken: accessToken};
            }, function () {
                return {accessToken: ''};
            }));

            var location = window.location;
            if (hash !== location.hash) {
                hash = location.hash;
                FW.reload();
            }
        }).trigger('hashchange');
    }
});

FW.init().then(function (FW) {

    if (Query.getItem('language')) {
        FW.Storage.setItem('language', Query.getItem('language'));
        location.href = location.protocol + "//" + location.hostname +
            (location.port && location.port != 80 && location.port != 443 ? ':' + location.port : '') +
            location.pathname + location.hash;
    }
    $('body').on('click', '.languages a[data-value]', function (event) {
        var language = $(this).data('value');
        FW.Storage.setItem('language', FW.Partial.global('language', language));
        FW.resetPromise('i18n');
        FW.reload();
        event.preventDefault();
        return false;
    })
});
FW.init().then(function (FW) {
    // list of languages and their native names
    var languageNames = FW.Partial.global('languageNames', {
        en: 'English',
        fr: 'Français',
        es: 'Español',
        de: 'Deutsche',
        it: 'Italiano',
        ar: 'عربى',
        pt: 'Português',
        zh: '中文',
        da: 'Dansk',
        ja: '日本の',
        nl: 'Nederlands',
        no: 'Norsk',
        sv: 'Svenska',
        ru: 'Русский'
    });

    // list of available website languages
    var siteLanguages = FW.Partial.global(
        'siteLanguages',
        ['en', 'fr', 'de', 'es', 'nl', 'ga'] // Object.keys(languageNames) // FIXME
    );

    // list of user preferred languages
    var userLanguages = FW.Partial.global('userLanguages', $.unique($.map($.grep(
        navigator.languages || [navigator.language || navigator.userLanguage],
        function (language) {return !!language;}
    ), function (language) {return language.split('-')[0];})));

    var array = $.merge($(userLanguages).filter(siteLanguages), siteLanguages).toArray();
    // list of available website languages prioritized based on user preferences
    var languages = FW.Partial.global('languages', $.grep(array, function (element, index) {
        return index === $.inArray(element, array);
    }));

    // user selected language or the top most preferred language
    var language = FW.Partial.global('language', FW.Storage.getItem('language') || languages[0]);
    FW.Storage.setItem('language', language);

    FW.registerPromise(
        'i18n',
        function () {
            var deferred = $.Deferred();

            var language = FW.Partial.global('language');
            var i18nData = FW.Storage.getItem('i18n_' + language);
            if (i18nData)
                i18nData = JSON.parse(i18nData);
            var i18nTime = FW.Storage.getItem('i18n@' + language);
            if (i18nTime)
                i18nTime = parseInt(i18nTime);

            (function () {
                if (!i18nData || !i18nTime || i18nTime < Date.now()/* - 60 * 60 * 1000*/) {
                    return $.getJSON($('meta[property="theme:path"]').attr('content') + '/assets/i18n/' + language + '.json').then(function(data) {
                        i18nData = data;
                        i18Time = Date.now();
                        FW.Storage.setItem('i18n_' + language, JSON.stringify(i18nData));
                        FW.Storage.setItem('i18n@' + language, '' + i18Time);
                    }, console.error);
                } else {
                    return $.Deferred().resolve().promise();
                }
            })().then(function () {
                var resources = {};
                resources[language] = i18nData || {};
                i18next.init({
                    fallbackLng: null,
                    lng: language,
                    // debug: true,
                    interpolation: {
                        prefix: '[[',
                        suffix: ']]',
                        nestingPrefix: '_T(',
                        nestingSuffix: ')',
                        escapeValue: false
                    },
                    resources: resources
                }).then(function (t) {
                    window._T = t;
                }).then(deferred.resolve, deferred.reject);
            });
            return deferred.promise();
        },
        []
    );
});
