// GLOBAL
var $cartBadge;
var options;
var drawTable;
var jqxhr;
var selectOptionSelected = {};
var sc;
var inputsWithValue = [];
var showModal;
var param = new Object;
var extra_param = new Object;
var idCartModal;
var ProductManager;
var seatmapWorkflowURL;

const branch = 'seatmap_testing'; // seatmap_testing or seatmap_main 
var DATA = {
    'CONFIG': {},
};
set_predefined_config(DATA);

function set_predefined_config(DATA) {
    DATA['CONFIG']['DEBUG'] = 1;
    DATA['CONFIG']['SEATMAP-SERVER'] = {};
    
    if (branch === 'seatmap_testing') {
        if (typeof DATA.CONFIG['SEATMAP_VERSION'] != 'undefined') {
            DATA.CONFIG["SEATMAP_VERSION"] = DATA.CONFIG["SEATMAP_VERSION"] + ' (testing)';
        }
        DATA.CONFIG['SEATMAP-SERVER']['ROOT_URL'] = 'https://staging.purchase.tickets.zinomedia.de/seatmap-server/seatmap-server.pl';
    }
    else if (branch === 'seatmap_main') {
        DATA.CONFIG['SEATMAP-SERVER']['ROOT_URL'] = 'https://zinomedia.de/seatmap_main/seatmap-server/seatmap-server.pl';
        DATA.CONFIG["SEATMAP_VERSION"] = DATA.CONFIG["SEATMAP_VERSION"];
    }
}

const checkoutParam = [
    'request_type', 'trxstate', 'request_action', 'agency', 'etpgcode', 'parent_offer_id', 'flashDetected', 'recapToken', 'age_consent_is_checked', 'jcarousel_auto_off_val', 'selected_seat_indexes', 'ism_map_current_state_json_data', 'is_availability_switch_from_map', 'map_coupon_code', 'is_ticket_exchange_request', 'prevtrxstate', 'user_context', 'gid', 'target_trxstate', 'target_prev_trxstate', 'target_url', 'target_name_value', 'orgid', 'p_orgid', 'pid', 'redeem_voucher_data_event_mapping', 'supplier_code', 'valid_coupon_code_message', 'replay_request', 'inventory_filtering_action', 'inventory_month', 'inventory_year', 'upsell_selected', 'listing_type', 'invalid_seats', 'package_pids', 's_mem_tkt_ren_retrieval', 'mlbamsp', 'pay_pal_token', 'dpa_selection', 'timeout_seconds', 'APPTE', 'schedule', 'hbx_discounts', 'hbx_discount_prices', 'hbx_selected_tixx', 'hbx_requested_pg', 'hbx_offered_pg', 'hbx_pids', 'hbx_perf_codes', 'hbx_perf_sub_codes', 'hbx_upsell_flag', 'selected_upsell_option', 'cancelAndRedirectTrxState', 'secure_trxn_enabled', 'isCapEnabled', 'mainEventPID', 'discountdesc=A=97', 'discountprice=A=97', 'discountfees=A=97', 'discount=A=97', 'discountdesc=A=A0', 'discountprice=A=A0', 'discountfees=A=A0', 'discount=A=A0', 'supplierCode',
];

// POLYPHILL repeat()
if (!String.prototype.repeat) {
    String.prototype.repeat = function(count) {
        'use strict';
        if (this == null)
            throw new TypeError('can\'t convert ' + this + ' to object');

        var str = '' + this;
        // To convert string to integer.
        count = +count;
        // Check NaN
        if (count != count)
            count = 0;

        if (count < 0)
            throw new RangeError('repeat count must be non-negative');

        if (count == Infinity)
            throw new RangeError('repeat count must be less than infinity');

        count = Math.floor(count);
        if (str.length == 0 || count == 0)
            return '';

        // Ensuring count is a 31-bit integer allows us to heavily optimize the
        // main part. But anyway, most current (August 2014) browsers can't handle
        // strings 1 << 28 chars or longer, so:
        if (str.length * count >= 1 << 28)
            throw new RangeError('repeat count must not overflow maximum string size');

        var maxCount = str.length * count;
        count = Math.floor(Math.log(count) / Math.log(2));
        while (count) {
            str += str;
            count--;
        }
        str += str.substring(0, maxCount - str.length);
        return str;
    };
}

// EVENT DOMCONTENTLOADED
document.addEventListener("DOMContentLoaded", ready);
window.onload = function() {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());
};

// EVENT CONTAINER VISIBLE
if ($('.container-fluid').is(':visible')) {
    // THROW ERROR AND DIE IF BROWSER IS IE
    detect_die_IE();
    
    // PARSE PARAM FROM POSTURL, CREATES param and extra_param
    let posturl = getParamValue('posturl');
    console.log('POSTURL: ' + posturl);
    
    var decoded_uri = decodeURIComponent(posturl);
    getParamsFromPosturl(decoded_uri);
    if (DATA.CONFIG['DEBUG']) console.log(param);
    if (DATA.CONFIG['DEBUG']) console.log(extra_param);
    
    // REMOVE PARAM FROM URL
    //window.history.replaceState(null, null, window.location.pathname);
    
    // GET DATA FROM SERVER AND BUILD SEATMAP
    //seatmapWorkflow(decoded_uri);
    seatmapWorkflow(posturl);
}

function detect_die_IE() {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());
    
    var IEdetected = detectIE();
    if (parseInt(IEdetected) < 12) {
        $('#IEdetected').show();
        throw new Error("IE " + IEDetected + " not supported.");
    }
}

function getParamsFromPosturl(decoded_uri) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());
    
    var checkoutParam = [
        'APPTE', 'age_consent_is_checked', 'agency', 'cancelAndRedirectTrxState', 'cogid', 'coids', 'discount=A=IE', 'discount=A=IV', 'discountdesc=A=IE', 'discountdesc=A=IV', 'discountfees=A=IE', 'discountfees=A=IV', 'discountprice=A=IE', 'discountprice=A=IV', 'dpa_selection', 'etpgcode', 'flashDetected', 'gid', 'hbx_discount_prices', 'hbx_discounts', 'hbx_offered_pg', 'hbx_perf_codes', 'hbx_perf_sub_codes', 'hbx_pids', 'hbx_requested_pg', 'hbx_selected_tixx', 'hbx_upsell_flag', 'request_type', 'invalid_seats', 'inventory_filtering_action', 'inventory_month', 'inventory_year', 'isCapEnabled', 'is_availability_switch_from_map', 'is_ticket_exchange_request', 'ism_map_current_state_json_data', 'jcarousel_auto_off_val', 'listing_type', 'mainEventPID', 'map_coupon_code', 'mlbamsp', 'oid', 'ooids', 'orderkey', 'orgid', 'p_orgid', 'package_pids', 'parent_offer_id', 'pay_pal_token', 'pid', 'prevtrxstate', 'recapToken', 'redeem_voucher_data_event_mapping', 'replay_request', 'request_action', 's_mem_tkt_ren_retrieval', 'schedule', 'secure_trxn_enabled', 'selected_seat_indexes', 'selected_upsell_option', 'supplierCode', 'supplier_code', 'target_name_value', 'target_prev_trxstate', 'target_trxstate', 'target_url', 'timeout_seconds', 'trxstate', 'upsell_selected', 'user_context', 'valid_coupon_code_message',
    ];
    var extraParam = ['note', 'request_switch'];
    
    for (var i = 0; i < checkoutParam.length; i++) {
        let value = getParamValue(checkoutParam[i], decoded_uri);
        if (value !== undefined) {
            param[checkoutParam[i]] = getParamValue(checkoutParam[i], decoded_uri);
        }
    }
    for (var i = 0; i < extraParam.length; i++) {
        let value = getParamValue(extraParam[i], decoded_uri);
        if (value !== undefined) {
            extra_param[extraParam[i]] = value;
        }
    }
}

// EVENT RESIZE
$(window).resize(function() {
    if ($(window).width() < 400) {
        $('.container-fluid').hide();
        $('#screenTooSmall').show();
    }
    else {
        $('.container-fluid').show();
        $('#screenTooSmall').hide();
    }
});

function detectIE () {
    var ua = window.navigator.userAgent;

    var msie = ua.indexOf('MSIE ');
    if (msie > 0) {
        // IE 10 or older => return version number
        return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
    }

    var trident = ua.indexOf('Trident/');
    if (trident > 0) {
        // IE 11 => return version number
        var rv = ua.indexOf('rv:');
        return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
    }

    var edge = ua.indexOf('Edge/');
    if (edge > 0) {
       // Edge (IE 12+) => return version number
       return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
    }

    // other browser
    return false;
}

function init(DATA) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    /*
     * jQuery myCart - v1.7 - 2018-03-07
     * http://asraf-uddin-ahmed.github.io/
     * Copyright (c) 2017 Asraf Uddin Ahmed; Licensed None
     */

    (function($) {

        "use strict";

        var OptionManager = (function() {
            var objToReturn = {};

            var _options = null;
            var DEFAULT_OPTIONS = {
                currencySymbol: DATA.CONFIG["CURRENCY_SYMBOL"],
                classCartIcon: 'my-cart-icon',
                classCartBadge: 'my-cart-badge',
                classProductQuantity: 'my-product-quantity',
                classProductRemove: 'my-product-remove',
                classCheckoutCart: 'my-cart-checkout',
                affixCartIcon: true,
                showCheckoutModal: true,
                numberOfDecimals: 2,
                cartItems: null,
                clickOnAddToCart: function($addTocart) {},
                afterAddOnCart: function(products, totalPrice, totalQuantity) {},
                clickOnCartIcon: function($cartIcon, products, totalPrice, totalQuantity) {},
                checkoutCart: function(products, totalPrice, totalQuantity) {
                    if (DATA.CONFIG['DEBUG']) console.log("checkoutCart");
                    return false;
                },
                getDiscountPrice: function(products, totalPrice, totalQuantity) {
                    return null;
                }
            };

            var loadOptions = function(customOptions) {
                _options = $.extend({}, DEFAULT_OPTIONS);
                if (typeof customOptions === 'object') {
                    $.extend(_options, customOptions);
                }
            };
            var getOptions = function() {
                return _options;
            };

            objToReturn.loadOptions = loadOptions;
            objToReturn.getOptions = getOptions;
            return objToReturn;
        }());

        var MathHelper = (function() {
            var objToReturn = {};
            var getRoundedNumber = function(number) {
                if (isNaN(number)) {
                    throw new Error('Parameter is not a Number');
                }
                number = number * 1;
                options = OptionManager.getOptions();
                return number.toFixed(options.numberOfDecimals);
            };
            objToReturn.getRoundedNumber = getRoundedNumber;
            return objToReturn;
        }());

        ProductManager = (function() {
            var objToReturn = {};
            var localStorage = {};

            /*
            PRIVATE
            */
            // localStorage.products = localStorage.products ? localStorage.products : "";
            if (typeof localStorage.products !== "undefined") {
                if (DATA.CONFIG['DEBUG']) console.log("localStorage defined");
                localStorage.products = "";
            }
            else {
                if (DATA.CONFIG['DEBUG']) console.log("localStorage undefined");
            }

            var getIndexOfProduct = function(id) {
                var productIndex = -1;
                var products = getAllProducts();
                $.each(products, function(index, value) {
                    if (value.id == id) {
                        productIndex = index;
                        return;
                    }
                });
                return productIndex;
            };
            var setAllProducts = function(products) {
                localStorage.products = JSON.stringify(products);
            };
            var addProduct = function(id, name, summary, price, quantity, image, seatObj) {
                var products = getAllProducts();
                products.push({
                    id: id,
                    name: name,
                    summary: summary,
                    price: price,
                    quantity: quantity,
                    image: image,
                    seatObj: seatObj,
                });
                setAllProducts(products);
            };

            /*
            PUBLIC
            */
            var getAllProducts = function() {
                try {
                    var products = JSON.parse(localStorage.products);
                    return products;
                }
                catch (e) {
                    return [];
                }
            };
            var updatePoduct = function(id, quantity) {
                var productIndex = getIndexOfProduct(id);
                if (productIndex < 0) {
                    return false;
                }
                var products = getAllProducts();
                products[productIndex].quantity = typeof quantity === "undefined" ? products[productIndex].quantity * 1 + 1 : quantity;
                setAllProducts(products);
                return true;
            };
            var updatePrice = function(id, price) {
                var productIndex = getIndexOfProduct(id);
                if (productIndex < 0) {
                    return false;
                }
                var products = getAllProducts();
                //   products[productIndex].quantity = typeof quantity === "undefined" ? products[productIndex].quantity * 1 + 1 : quantity;
                products[productIndex].price = price;
                setAllProducts(products);
                return true;
            };
            var setProduct = function(id, name, summary, price, quantity, image, seatObj) {
                if (typeof id === "undefined") {
                    console.error("id required");
                    return false;
                }
                if (typeof name === "undefined") {
                    console.error("name required");
                    return false;
                }
                if (typeof image === "undefined") {
                    console.error("image required");
                    return false;
                }
                if (!$.isNumeric(price)) {
                    console.error("price is not a number");
                    return false;
                }
                if (!$.isNumeric(quantity)) {
                    console.error("quantity is not a number");
                    return false;
                }
                if (typeof seatObj === "undefined") {
                    console.error("seatObj required");
                    return false;
                }
                summary = typeof summary === "undefined" ? "" : summary;

                if (!updatePoduct(id)) {
                    addProduct(id, name, summary, price, quantity, image, seatObj);
                }
            };
            var clearProduct = function() {
                setAllProducts([]);
            };
            var removeProduct = function(id) {
                var products = getAllProducts();
                products = $.grep(products, function(value, index) {
                    return value.id != id;
                });
                setAllProducts(products);
            };
            var getTotalQuantity = function() {
                var total = 0;
                var products = getAllProducts();
                $.each(products, function(index, value) {
                    total += value.quantity * 1;
                });
                return total;
            };
            var getTotalPrice = function() {
                var products = getAllProducts();
                var total = 0;
                $.each(products, function(index, value) {
                    total += value.quantity * value.price;
                    total = MathHelper.getRoundedNumber(total) * 1;
                });
                return total;
            };

            objToReturn.getAllProducts = getAllProducts;
            objToReturn.updatePoduct = updatePoduct;
            objToReturn.updatePrice = updatePrice;
            objToReturn.setProduct = setProduct;
            objToReturn.clearProduct = clearProduct;
            objToReturn.removeProduct = removeProduct;
            objToReturn.getTotalQuantity = getTotalQuantity;
            objToReturn.getTotalPrice = getTotalPrice;
            return objToReturn;
        }());


        var loadMyCartEvent = function(targetSelector) {

            var options = OptionManager.getOptions();
            var $cartIcon = $("." + options.classCartIcon);
            $cartBadge = $("." + options.classCartBadge);
            var classProductQuantity = options.classProductQuantity;
            var classProductRemove = options.classProductRemove;
            var classCheckoutCart = options.classCheckoutCart;

            idCartModal = 'my-cart-modal';
            var idCartTable = 'my-cart-table';
            var idGrandTotal = 'my-cart-grand-total';
            var idEmptyCartMessage = 'my-cart-empty-message';
            var idDiscountPrice = 'my-cart-discount-price';
            var classProductTotal = 'my-product-total';
            var classAffixMyCartIcon = 'my-cart-icon-affix';


            if (options.cartItems && options.cartItems.constructor === Array) {
                ProductManager.clearProduct();
                $.each(options.cartItems, function() {
                    ProductManager.setProduct(this.id, this.name, this.summary, this.price, this.quantity, this.image);
                });
            }

            $cartBadge.text(ProductManager.getTotalQuantity());

            if (!$("#" + idCartModal).length) {
                var modal_body = 'Bitte überprüfen Sie Ihre Plätze. Dies ist die letze Möglichkeit, um ggfs. die Ermäßigung zu ändern.';
                if (extra_param['note']) {
                    modal_body = modal_body + '<br>' + extra_param['note'];
                }
                
                $('body').append(
                    '<div class="modal fade" id="' + idCartModal + '" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">' +
                    '<div class="modal-dialog" role="document">' +
                    '<div class="modal-content">' +
                    '<div class="modal-header">' +
                    '<button type="button" class="close" data-dismiss="modal" aria-label="Zurück"><span aria-hidden="true">&times;</span></button>' +
                    '<h2 class="modal-title" id="myModalLabel"><span class="glyphicon glyphicon-shopping-cart"></span> Einkaufswagen</h2>' +
                    '</div>' +
                    '<div class="modal-body cartFont">' + modal_body + '</div>' +
                    '<div class="modal-body">' +
                    '<table class="table table-hover table-responsive" id="' + idCartTable + '"></table>' +
                    '</div>' +
                    '<div class="modal-footer">' +
                    '<button type="button" class="btn btn-default" data-dismiss="modal">Zurück</button>' +
                    '<button type="button" class="btn btn-primary ' + classCheckoutCart + '">zur Kasse</button>' +
                    '</div>' +
                    '</div>' +
                    '</div>' +
                    '</div>'
                );
            }

            drawTable = function() {
                var DATA = jqxhr.responseJSON;

                var $cartTable = $("#" + idCartTable);
                $cartTable.empty();

                var products = ProductManager.getAllProducts();

                $.each(products, function() {
                    var total = this.quantity * this.price;

                    // OPTION DROPDOWN
                    var selectID = 'select' + this.id;
                    var select = "<select onchange=\"selectRefreshPrice(this); drawTable();\" class=\"selectBuyerTypes\" id=\"" + selectID + "\">";

                    $cartTable.append(
                        '<tr title="' + this.summary + '" data-id="' + this.id + '" data-price="' + this.price + '">' +
                        '<td><div style="width: 1.5vw; height: 1.5vw; background-color: ' + this.summary + '"></div> </td>' +
                        '<td>' + this.name + '</td>' +
                        '<td id="tdSelect">' + select + '</td>' +
                        '<td title="Total" class="' + classProductTotal + '">' + options.currencySymbol + MathHelper.getRoundedNumber(total) + '</td>' +
                        '<td title="Remove from Cart" class="text-center" style="width: 30px;"><a onclick="untickSeat(this.id)" id="' + this.id + '" class="btn btn-xs btn-danger ' + classProductRemove + '">X</a></td>' +
                        '</tr>'
                    );

                    // CREATE OPTION SELECT DROPDOWN
                    var selectObj = document.getElementById(selectID);
                    for (var buyerType in this.seatObj.settings.data.buyerTypesSortedConfig) {
                        var o = new Option(buyerType, this.seatObj.settings.data.buyerTypesSortedConfig[buyerType]["PRICE"]);
                        if (DATA.CONFIG['DEBUG']) console.log('buyerType: ' + buyerType + ' PRICE: ' + this.seatObj.settings.data.buyerTypesSortedConfig[buyerType]["PRICE"]);
                        $(o).html(buyerType);
                        $(selectObj).append(o);
                    }
                });

                $cartTable.append(products.length ?
                    '<tr>' +
                    '<td></td>' +
                    '<td><strong>Summe</strong></td>' +
                    '<td></td>' +
                    '<td><strong id="' + idGrandTotal + '"></strong></td>' +
                    '<td></td>' +
                    '</tr>' :
                    '<div class="alert alert-danger" role="alert" id="' + idEmptyCartMessage + '">Ihr Einkaufswagen ist leer.</div>'
                );

                //   var discountPrice = options.getDiscountPrice(products, ProductManager.getTotalPrice(), ProductManager.getTotalQuantity());
                //   if (products.length && discountPrice !== null) {
                //     $cartTable.append(
                //       '<tr style="color: red">' +
                //       '<td></td>' +
                //       '<td><strong>Total (including discount)</strong></td>' +
                //       '<td></td>' +
                //     //   '<td></td>' +
                //       '<td><strong id="' + idDiscountPrice + '"></strong></td>' +
                //       '<td></td>' +
                //       '</tr>'
                //     );
                //   }

                setSelectedIndex();
                showGrandTotal();
                //   showDiscountPrice();
            };
            showModal = function() {
                drawTable();
                $("#" + idCartModal).modal('show');
            };
            var updateCart = function() {
                $.each($("#" + classProductQuantity), function() {
                    var id = $(this).closest("tr").data("id");
                    ProductManager.updatePoduct(id, $(this).val());
                });
            };
            var showGrandTotal = function() {
                $("#" + idGrandTotal).text(options.currencySymbol + MathHelper.getRoundedNumber(ProductManager.getTotalPrice()));
            };
            var showDiscountPrice = function() {
                $("#" + idDiscountPrice).text(options.currencySymbol + MathHelper.getRoundedNumber(options.getDiscountPrice(ProductManager.getAllProducts(), ProductManager.getTotalPrice(), ProductManager.getTotalQuantity())));
            };

            /*
            EVENT
            */
            if (options.affixCartIcon) {
                var cartIconBottom = $cartIcon.offset().top * 1 + $cartIcon.css("height").match(/\d+/) * 1;
                var cartIconPosition = $cartIcon.css('position');
                $(window).scroll(function() {
                    $(window).scrollTop() >= cartIconBottom ? $cartIcon.addClass(classAffixMyCartIcon) : $cartIcon.removeClass(classAffixMyCartIcon);
                });
            }

            $cartIcon.click(function() {
                options.showCheckoutModal ? showModal() : options.clickOnCartIcon($cartIcon, ProductManager.getAllProducts(), ProductManager.getTotalPrice(), ProductManager.getTotalQuantity());
            });

            $(document).on("input", "." + classProductQuantity, function() {
                var price = $(this).closest("tr").data("price");
                var id = $(this).closest("tr").data("id");
                var quantity = $(this).val();

                $(this).parent("td").next("." + classProductTotal).text(options.currencySymbol + MathHelper.getRoundedNumber(price * quantity));
                ProductManager.updatePoduct(id, quantity);

                $cartBadge.text(ProductManager.getTotalQuantity());
                showGrandTotal();
                showDiscountPrice();
            });

            $(document).on('keypress', "." + classProductQuantity, function(evt) {
                if (evt.keyCode == 38 || evt.keyCode == 40) {
                    return;
                }
                evt.preventDefault();
            });

            $(document).on('click', "." + classProductRemove, function() {
                var $tr = $(this).closest("tr");
                var id = $tr.data("id");
                $tr.hide(500, function() {
                    ProductManager.removeProduct(id);
                    drawTable();
                    $cartBadge.text(ProductManager.getTotalQuantity());
                });
            });

            $(document).on('click', "." + classCheckoutCart, function() {

                var products = ProductManager.getAllProducts();
                if (!products.length) {
                    $("#" + idEmptyCartMessage).fadeTo('fast', 0.5).fadeTo('fast', 1.0);
                    return;
                }
                updateCart();
                var isCheckedOut = options.checkoutCart(ProductManager.getAllProducts(), ProductManager.getTotalPrice(), ProductManager.getTotalQuantity());
                // if (isCheckedOut !== false) {
                //     ProductManager.clearProduct();
                //     $cartBadge.text(ProductManager.getTotalQuantity());
                //     $("#" + idCartModal).modal("hide");
                // }
            });

            $(document).on('click', targetSelector, function() {
                var $target = $(this);
                options.clickOnAddToCart($target);

                var id = $target.data('id');
                var name = $target.data('name');
                var summary = $target.data('summary');
                var price = $target.data('price');
                var quantity = $target.data('quantity');
                var image = $target.data('image');

                ProductManager.setProduct(id, name, summary, price, quantity, image);
                $cartBadge.text(ProductManager.getTotalQuantity());

                options.afterAddOnCart(ProductManager.getAllProducts(), ProductManager.getTotalPrice(), ProductManager.getTotalQuantity());
            });

        };


        $.fn.myCart = function(userOptions) {
            OptionManager.loadOptions(userOptions);
            loadMyCartEvent(this.selector);
            return this;
        };

    })(jQuery);

    $('.my-cart-btn').myCart({
        currencySymbol: DATA.CONFIG["CURRENCY_SYMBOL"],
        classCartIcon: 'my-cart-icon',
        classCartBadge: 'my-cart-badge',
        classProductQuantity: 'my-product-quantity',
        classProductRemove: 'my-product-remove',
        classCheckoutCart: 'my-cart-checkout',
        affixCartIcon: true,
        showCheckoutModal: true,
        numberOfDecimals: 2,
        cartItems: [],
        clickOnAddToCart: function($addTocart) {
            goToCartIcon($addTocart);
        },
        afterAddOnCart: function(products, totalPrice, totalQuantity) {
            if (DATA.CONFIG['DEBUG']) console.log("afterAddOnCart", products, totalPrice, totalQuantity);
        },
        clickOnCartIcon: function($cartIcon, products, totalPrice, totalQuantity) {
            if (DATA.CONFIG['DEBUG']) console.log("cart icon clicked", $cartIcon, products, totalPrice, totalQuantity);
        },
        checkoutCart: function(products, totalPrice, totalQuantity) {
            var checkoutString = "Total Price: " + totalPrice + "\nTotal Quantity: " + totalQuantity;
            checkoutString += "\n\n id \t name \t summary \t price \t quantity \t image path";

            var selected_seat_indexes = '';

            $.each(products, function() {
                checkoutString += ("\n " + this.id + " \t " + this.name + " \t " + this.summary + " \t " + this.price + " \t " + this.quantity + " \t " + this.image);

                // GENERATE SELECTED_SEAT_INDEXES
                var selected;
                var e = document.getElementById(this.seatObj.settings.data.selectID);
                var buyerTypeSelected = e.options[e.selectedIndex].text;

                // REVERT BUYERT TYPE BACK TO ORIGINAL FROM XML
                buyerTypeSelected = this.seatObj.settings.data.buyerTypesSortedConfig[buyerTypeSelected]["ORIG_DESC"];

                for (var id in this.seatObj.settings.data.buyerTypes) {
                    if (this.seatObj.settings.data.buyerTypes[id].DESC == buyerTypeSelected) {
                        if (selected_seat_indexes == '') {
                            selected_seat_indexes = this.seatObj.settings.data.seatObjJSON.ID1 + ',' + this.seatObj.settings.data.buyerTypes[id].ID + ',' + this.seatObj.settings.data.buyerTypes[id].CODE;
                        }
                        else {
                            selected_seat_indexes += '|' + this.seatObj.settings.data.seatObjJSON.ID1 + ',' + this.seatObj.settings.data.buyerTypes[id].ID + ',' + this.seatObj.settings.data.buyerTypes[id].CODE;
                        }
                        break;
                    }
                }
            });
            if (DATA.CONFIG['DEBUG']) console.log("selected_seat_indexes: " + selected_seat_indexes);

            // CHECK IF SELECTED SEATS ARE VALID
            checkoutCheckResponse(selected_seat_indexes, DATA);

        },
        getDiscountPrice: function(products, totalPrice, totalQuantity) {
            return totalPrice * 0.5;
        }
    });
}

function ready() {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());
    if (DATA.CONFIG['DEBUG']) console.log('iFrame DOMContentLoaded');
}

function getParamValue(paramName, url) {
    // if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    if (url == null) {
        url = window.location.search.substring(1); //get rid of "?" in querystring
    }
    var qArray = url.split('&'); //get key-value pairs
    for (var i = 0; i < qArray.length; i++) {
        var pArr = qArray[i].split('='); //split key and value
        if (pArr[0] == paramName) {
            return pArr[1]; //return value
        }
    }
}

function checkMobile() {
    console.log(getFuncName());

    var isMobile = false; //initiate as false
    // device detection
    if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent) ||
        /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0, 4))) {
        isMobile = true;
        $("html").append('<h3 class="centered">Please use a desktop browser. Mobile devices are not yet compatible with this website.</h3>');
    }
    if (DATA.CONFIG['DEBUG']) console.log("isMObile: " + isMobile);
}

function getHTMLInputs(selected_seat_indexes) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    // ONLY FOR PRODUCTION
    // DATA OBJECT
    var DATA = jqxhr.responseJSON;

    // FETCH INPUT FROM VENUE TRXSTATE 0 PAGE
    var rootURL = 'https://purchase.tickets.com/buy/TicketPurchase';
    var venueDesc = DATA.VENUE.DESC;
    var url = rootURL + '?agency=' + DATA.CONFIG[venueDesc]["AGENCY"] + '&perfsubcode=2019&perfcode=' + DATA["EVENT"]["CODE"];
    if (DATA.CONFIG['DEBUG']) console.log("Get: " + url);

    var jqxhr2 = $.get(url, function(DATA2) {
            if (DATA.CONFIG['DEBUG']) console.log("success");

            var data = $.parseHTML(DATA2);
            $(data).find('input').each(function() {
                console.log(this.id);

                if (this.value !== '' && this.id !== '') {
                    if (checkoutParam.includes(this.id)) {
                        inputsWithValue.push(this);
                    }
                }
            });

            if (DATA.CONFIG['DEBUG']) console.log(inputsWithValue);

        })
        .done(function(DATA2) {
            if (DATA.CONFIG['DEBUG']) console.log("second success");
            checkoutGenerateURL(selected_seat_indexes);
        })
        .fail(function(jqxhr2, textStatus, errorThrown) {
            if (DATA.CONFIG['DEBUG']) console.log("error: " + textStatus);
        })
        .always(function() {
            if (DATA.CONFIG['DEBUG']) console.log("complete");
        });
}

function arrayMatrix(numrows, numcols, initial) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    var arr = [];
    for (var i = 0; i < numrows; ++i) {
        var columns = [];
        for (var j = 0; j < numcols; ++j) {
            columns[j] = initial;
        }
        arr[i] = columns;
    }
    return arr;
}

function getFuncName(arg) {
    var caller;
    if (getFuncName.caller.name !== '') {
        caller = getFuncName.caller.name;
    }
    else {
        caller = arg;
    }
    return '\n' + '-'.repeat(80) + '\n' + 'CHILD ' + caller + '\n' + '-'.repeat(80);
}

// SEATMAP
function seatmapWorkflow(URI) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());
    
    //seatmapWorkflowURL = DATA.CONFIG["SEATMAP-SERVER"]["ROOT_URL"] + "?url=" + decodedURI;
    //if (DATA.CONFIG['DEBUG']) console.log("Get: " + seatmapWorkflowURL);
    //let seatmapWorkflowURLEncoded = DATA.CONFIG["SEATMAP-SERVER"]["ROOT_URL"] + "?url=" + encodeURIComponent(URI);
    let seatmapWorkflowURLEncoded = DATA.CONFIG["SEATMAP-SERVER"]["ROOT_URL"] + "?url=" + URI;
    if (DATA.CONFIG['DEBUG']) console.log("Get: " + seatmapWorkflowURLEncoded);
    
    jqxhr = $.getJSON(seatmapWorkflowURLEncoded, function(DATA) {
            if (DATA.CONFIG['DEBUG']) console.log("success");
            
            // MERGE PREDEFINED AND SERVER SETTINGS
            set_predefined_config(DATA);
            if (DATA.CONFIG['DEBUG']) console.log(DATA);
            
            // INIT MYCART
            init(DATA);
            
            // BUILD SEATMAP
            generateSeatmap(DATA);
        })
        .done(function(DATA) {
            if (DATA.CONFIG['DEBUG']) console.log("second success");
            
            if (DATA.CONFIG['DEBUG']) console.log(DATA);
            
            manipulateHTML(DATA);
        })
        .fail(function(jqXHR, textStatus, errorThrown) {
            if (DATA.CONFIG['DEBUG']) console.log("error: " + textStatus);
        })
        .always(function() {
            if (DATA.CONFIG['DEBUG']) console.log("complete");
        });
}

function replaceUmlautsDATA(DATA) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    DATA.EVENT.DESC = replaceUmlauts(DATA.EVENT.DESC);
    DATA.EVENT.PUBLIC_DESC = replaceUmlauts(DATA.EVENT.PUBLIC_DESC);
    DATA.VENUE.CODE = replaceUmlauts(DATA.VENUE.CODE);
    DATA.VENUE.DESC = replaceUmlauts(DATA.VENUE.DESC);
    DATA.VENUE.NAME = replaceUmlauts(DATA.VENUE.NAME);
}

function fillSeatObjData(id, DATA) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    // Seat Object
    var seatObj = sc.get(id);
    
    if (DATA.CONFIG['DEBUG']) {
        console.log(DATA);
        console.log(seatObj);
    }

    // GET SECTION ID, ROW AND SEATNR FOR IDENTIFICATION
    var arrID = id.split('_'),
        sectionID = arrID[0],
        row = arrID[1],
        seatNr = arrID[2];

    // JSON SEAT OBJ
    var seatObjJSON = DATA.VENUE.SEATMAP_CONFIG[sectionID].ROWS[row][seatNr];
    // console.log(seatObjJSON);

    // PRICESCALES ID AND OBJECT
    var pricescalesID = seatObjJSON.PRICESCALES_ID;
    var pricescalesObj = DATA.VENUE.PRICESCALES[pricescalesID];
    // console.log(pricescalesObj);

    // BUYER TYPE OBJECT
    var buyerTypesObj = DATA.VENUE.BUYER_TYPES;
    // console.log(buyerTypesObj);

    // ROW AND PRODUCT TITLE
    var product = seatObjJSON['SECTIONID_DESC'] + ' Reihe ' + seatObjJSON['ROW_PARSED'] + ' Platz ' + seatObjJSON.SEATNR_PARSED; // SHOWS IN CART
    var productJBox = seatObjJSON['SECTIONID_DESC'] + ' Reihe ' + seatObjJSON['ROW_PARSED'] + ' Platz ' + seatObjJSON.SEATNR_PARSED + ' | ' + seatObj.data().price + DATA.CONFIG["CURRENCY_SYMBOL"]; // SHOWS IN JBOX

    // SEAT COLOR
    var seatColor = pricescalesObj.COLOR;
    var jQuerySeatColor = '#' + seatColor;

    // SELECT ID
    var selectID = 'select' + id;

    // SORT BUYER TYPES FROM PRICESCALES
    const ordered = {};
    const orderedConfigBuyerTypes = {};
    var price = 0;
    Object.keys(pricescalesObj.PRICES).sort().forEach(function(key) {
        // MAP WITH CONFIG BUYER TYPES FOR OPTION SELECT DROPDOWN
        for (var buyerTypeID in buyerTypesObj) {
            if (buyerTypesObj[buyerTypeID]["DESC"] == key && key !== 'REF_PRICE') {
                var venueDesc = DATA.VENUE.DESC.toUpperCase();
                var code = buyerTypesObj[buyerTypeID]["CODE"];
                var configBuyerType = DATA.CONFIG[venueDesc]["BUYER_TYPES"][code];
                orderedConfigBuyerTypes[configBuyerType] = {
                    "PRICE": pricescalesObj.PRICES[key],
                    "ORIG_DESC": key,
                    "MAP_DESC": configBuyerType,
                }
            }
        }

        // DROP DOWN WITH XML BUYER TYPES (NOT IN USE)
        ordered[key] = pricescalesObj.PRICES[key];

        // SET HIGHEST BUYER TYPE AS DEFAULT FOR OPTION MENU
        if (pricescalesObj.PRICES[key] > price && key !== 'REF_PRICE') {
            selectOptionSelected[selectID] = { selected: configBuyerType }; // Default Option menu select
        }
    });
    delete ordered['REF_PRICE']; // REMOVE REF PRICE FROM OPTION SELECT DROPDOWN

    seatObj.data().color = jQuerySeatColor;
    seatObj.data().product = product;
    seatObj.data().productJBox = productJBox;
    seatObj.data().buyerTypesSorted = ordered;
    seatObj.data().buyerTypesSortedConfig = orderedConfigBuyerTypes;
    seatObj.data().filled = true;
    seatObj.data().buyerTypes = buyerTypesObj;
    seatObj.data().seatObjJSON = seatObjJSON;
    seatObj.data().selectID = selectID;
}

function replaceUmlauts(str) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    // str = str.replace(/\u00dc/g, "UE");
    // str = str.replace(/\u00fc/g, "ue");
    // str = str.replace(/\u00c4/g, "AE");
    // str = str.replace(/\u00e4/g, "ae");
    // str = str.replace(/\u00d6/g, "OE");
    // str = str.replace(/\u00f6/g, "oe");
    str = str.replace(/├╝/g, "ü");
    str = str.replace(/├Â/g, "ö");
    str = str.replace(/├®/g, "é");
    str = str.replace(/├í/g, "á");
    str = str.replace(/├ñ/g, "ä");
    str = str.replace(/├Û/g, "Ö");
    str = str.replace(/├Ƒ/g, "ß");

    str = str.toUpperCase()
    return str;
}

function manipulateHTML(DATA) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    document.getElementById("eventDesc").innerHTML = DATA.EVENT.DESC;
    document.getElementById("datetime_DE").innerHTML = 'Beginn: ' + DATA.EVENT.DATETIME_DE;
    document.getElementById("venueDesc").innerHTML = 'Ort: ' + DATA.VENUE.DESC.toUpperCase();
    document.getElementById("seatmap_version").innerHTML = 'Version ' + DATA.CONFIG["SEATMAP_VERSION"];

    $('.container-fluid').css('visibility', 'visible');
}

function generateLegend(DATA, legendContainer) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    var legend = {};
    var items = new Array();

    //  BIND LEGEND TO FOLLOWING NODE
    // var node = '$(\'#' + legendContainer + '\')';
    var node = eval('$(\'#' + legendContainer + '\')');

    // LOOP PRICESCALES
    for (var pricescalesID in DATA.VENUE.PRICESCALES) {
        var pricescalesObj = DATA.VENUE.PRICESCALES[pricescalesID];

        // DESC IS THE LOWEST TO HIGHEST PRICE
        var sortable = []; 
        for (var buyerType in pricescalesObj.PRICES) {
            sortable.push(pricescalesObj.PRICES[buyerType]);
        }
        sortable.sort(function(a, b) { return a - b });
        var pricescalesDesc = DATA.CONFIG["CURRENCY_SYMBOL"] + sortable[0] + ' -  ' + DATA.CONFIG["CURRENCY_SYMBOL"] + sortable[sortable.length - 1];
        // console.log(sortable);


        items.push([pricescalesObj.CODE, 'available', pricescalesDesc]);
        // items.push(pricescalesObj.CODE);
    }

    legend = { node: node, items: items };
    return legend;
}

function generateSeats(DATA, mappingPricescalesSections) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    var seats = {};
    var cssProperties;

    // LOOP PRICESCALES
    for (var pricescalesID in DATA.VENUE.PRICESCALES) {
        // OBJECTS
        var sectionID = mappingPricescalesSections[pricescalesID];
        var pricescalesObj = DATA.VENUE.PRICESCALES[pricescalesID];
        
        if (typeof DATA.CONFIG[DATA.VENUE.CODE]["CUSTOM_PRICESCALES_COLOR"] != "undefined") {
            if (DATA.CONFIG['DEBUG']) console.log("Applying custom colors");
            cssProperties = '{' +
                'background-color: #' + DATA.CONFIG[DATA.VENUE.CODE]["CUSTOM_PRICESCALES_COLOR"][pricescalesObj.ID] + ' !important;' +
            '}';
        }
        else {
            if (DATA.CONFIG['DEBUG']) console.log("Applying colors from XML");
            cssProperties = '{' +
                'background-color: #' + pricescalesObj.COLOR + ' !important;' +
            '}';
        }
        
        var cssClass = '_' + pricescalesObj.ID;
        createCSSClass(cssClass, cssProperties);
        seats[pricescalesObj.CODE] = { price: pricescalesObj.PRICES.REF_PRICE, classes: cssClass };
    }
    

    return seats;
}

function resolve(path, obj=self, separator='.') {
    var properties = Array.isArray(path) ? path : path.split(separator)
    return properties.reduce((prev, curr) => prev && prev[curr], obj)
}

Object.byString = function(o, s) {
    s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
    s = s.replace(/^\./, '');           // strip a leading dot
    var a = s.split('.');
    for (var i = 0, n = a.length; i < n; ++i) {
        var k = a[i];
        if (k in o) {
            o = o[k];
        } else {
            return;
        }
    }
    return o;
};

function createCSSClass(cssClass, cssProperties) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    var style = document.createElement('style');
    style.type = 'text/css';
    style.innerHTML = '.' + cssClass + cssProperties;
    document.getElementsByTagName('head')[0].appendChild(style);
}

function getMinMaxXY(ROWS) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());
    return { minimum: { x: Math.min.apply(null, Object.values(ROWS).map(function(seat) { return seat.X_COORD; })), y: Math.min.apply(null, Object.values(ROWS).map(function(seat) { return seat.Y_COORD; })) }, maximum: { x: Math.max.apply(null, Object.values(ROWS).map(function(seat) { return seat.X_COORD; })), y: Math.max.apply(null, Object.values(ROWS).map(function(seat) { return seat.Y_COORD; })) } };
}

function getMinMaxXY(ROWS) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    var xMax = 0;
    var yMax = 0;
    var xMin = Number.MAX_VALUE;
    var yMin = Number.MAX_VALUE;

    for (var seatNr in ROWS) {
        for (var seat in ROWS[seatNr]) {
            if (xMax < ROWS[seatNr][seat].X_COORD) {
                xMax = Number(ROWS[seatNr][seat].X_COORD);
            }
            if (xMin > ROWS[seatNr][seat].X_COORD) {
                xMin = Number(ROWS[seatNr][seat].X_COORD);
            }
            if (yMax < ROWS[seatNr][seat].Y_COORD) {
                yMax = Number(ROWS[seatNr][seat].Y_COORD);
            }
            if (yMin > ROWS[seatNr][seat].Y_COORD) {
                yMin = Number(ROWS[seatNr][seat].Y_COORD);
            }
        }
    }

    return { minimum: { x: xMin, y: yMin }, maximum: { x: xMax, y: yMax } };
}

function getOverallMaxXY(DATA) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    var xMax = 0;
    var yMax = 0;
    var rowMax = 0;
    var xMin = Number.MAX_VALUE;
    var yMin = Number.MAX_VALUE;
    for (var seatmapID in DATA.VENUE.SEATMAP_CONFIG) {
        var minMax = getMinMaxXY(DATA.VENUE.SEATMAP_CONFIG[seatmapID].ROWS);
        rowMax += Object.keys(DATA.VENUE.SEATMAP_CONFIG[seatmapID].ROWS).length;

        if (xMax < minMax.maximum.x) {
            xMax = minMax.maximum.x;
        }
        if (xMin > minMax.minimum.x) {
            xMin = minMax.minimum.x;
        }
        if (yMax < minMax.maximum.y) {
            yMax = minMax.maximum.y;
        }
        if (yMin > minMax.minimum.y) {
            yMin = minMax.minimum.y;
        }
    }
    var maxSeats = xMax - xMin;
    return [xMax, xMin, yMax, yMin, rowMax, maxSeats];
}

function sortSeatmaps(DATA) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    var sortable = [];
    for (var seatmapID in DATA.VENUE.SEATMAP_CONFIG) {
        var hotspotCoord = DATA.VENUE.SEATMAP_CONFIG[seatmapID].HOTSPOT_COORDS.split(',');
        var xTotal = parseInt(hotspotCoord[1]) + parseInt(hotspotCoord[3]) + parseInt(hotspotCoord[5]) + parseInt(hotspotCoord[7]) + parseInt(hotspotCoord[9]);

        sortable.push([xTotal, DATA.VENUE.SEATMAP_CONFIG[seatmapID]]);
    }
    sortable.sort(function(a, b) {
        return a[0] - b[0];
    });

    return sortable;
}

// function bigMatrixDim(sortedSections) {
//     if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

//     var beneath = 0;
//     var under = 0;
//     var mapping = {};
//     var matrixBIG = new Array();
//     var array = new Array();
    
//     for (var k in sortedSections) {
//         var sectionObj = sortedSections[k][1];
        
//         matrixBIG[matrixBIG.length] = new Array();
        
//         // NEW APPROACH
//         var hotspot_coords_array = sectionObj.HOTSPOT_COORDS.split(',');
//         console.log('Hotspor coord: ' + sectionObj.HOTSPOT_COORDS);
//         var arrayLength = hotspot_coords_array.length;
//         console.log('arrayLength: ' + arrayLength);

//         var pairObj = { X: 0, Y: 0 };
        

//         for (var i = 0; i < arrayLength; i+=2) {
//             // console.log('i is: ' + i);
//             // console.log('x: ' + hotspot_coords_array[i]);
//             // console.log('y: ' + hotspot_coords_array[i+1]);
            
//             var x = parseInt(hotspot_coords_array[i], 10);
//             var y = parseInt(hotspot_coords_array[i+1], 10);
//             if (y >= pairObj['Y']) {
//                 pairObj['Y'] = y;
//                 // console.log('Current xMax: ' + pairObj['Max']['x']);
//                 // console.log('x ' + x);
//                 if (x > pairObj['X']) {
//                     // console.log('assigning...');
//                     pairObj['X'] = x;
//                     pairObj['SECTION_ID'] = sectionObj.ID;
//                 }
//             }
//         }
//         array.push(pairObj);
//         console.log(pairObj);
//     }
    
//     // NEW APPROACH
//     array.sort(compareValues('Y', 'asc'));
//     var group = new Array();
//     var old_y;
//     var bigdim_y = 0;
//     for (var i = 0; i < array.length; i++) {
//         var y_curr = array[i]['Y'];
        
//         if (i == array.length-1 ) {
//             group.push(array[i]);
//         }
//         if (old_y && ( !between(old_y, y_curr-20, y_curr+20) || i == array.length-1 ) ) {
//             console.log('GROUP');
            
//             group.sort(compareValues('X', 'asc'));
//             console.log(group);
//             for (var j = 0; j < group.length; j++) {
                
//                 mapping[group[j]['SECTION_ID']] = { x: bigdim_y, y: j };
//             }
            
//             group = [];
//             old_y = undefined;
//             bigdim_y++;
//         }
        
//         group.push(array[i]);
//         old_y = y_curr;
//     }

//     if (DATA.CONFIG['DEBUG']) console.log(under + " " + beneath);
//     return [mapping, matrixBIG];
// }

function bigMatrixDim(sortedSections) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    var firstLoop = true;
    var beneath = 0;
    var under = 0;
    var oldHotspotCoord;
    var mapping = {};
    var matrixBIG = new Array();
    var array = new Array();
    
    for (var k in sortedSections) {
        var sectionObj = sortedSections[k][1];
        
        matrixBIG[matrixBIG.length] = new Array();
        
        // OLD APPROACH
        // FIRST LOOP ONLY GET HOTSPOT AND CONTINUE
        if (firstLoop) {
            oldHotspotCoord = sectionObj.HOTSPOT_COORDS.split(',');
            firstLoop = false;
            var sectionID = sectionObj.ID;
            mapping[sectionObj.ID] = { x: beneath, y: under };
            continue;
        }

        // NOT FIRST LOOP
        var hotspotCoord = sectionObj.HOTSPOT_COORDS.split(',');
        if (hotspotCoord[9] != oldHotspotCoord[9]) {
            if (DATA.CONFIG['DEBUG']) console.log("Sections seem to be under previous");
            beneath = 0;
            under++;
        }
        else if (hotspotCoord[9] == oldHotspotCoord[9]) {
            if (DATA.CONFIG['DEBUG']) console.log("Sections seem to be beneath each other");
            beneath++;
        }

        mapping[sectionObj.ID] = { x: beneath, y: under };
        oldHotspotCoord = hotspotCoord;
        // END OLD APPROACH
    }

    if (DATA.CONFIG['DEBUG']) console.log(under + " " + beneath);
    return [mapping, matrixBIG];
}

function between(x, min, max) {
    return x >= min && x <= max;
}

function compareValues(key, order = 'asc') {
    return function innerSort(a, b) {
        if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) {
            return 0;
        }
        
        const varA = (typeof a[key] === 'string')
        ? a[key].toUpperCase() : a[key];
        const varB = (typeof b[key] === 'string')
        ? b[key].toUpperCase() : b[key];
        
        let comparison = 0;
        if (varA > varB) {
            comparison = 1;
        } else if (varA < varB) {
            comparison = -1;
        }
        return (
            (order === 'desc') ? (comparison * -1) : comparison
        );
    };
}

function ObjectLength(object) {
    var length = 0;
    for (var key in object) {
        if (object.hasOwnProperty(key)) {
            ++length;
        }
    }
    return length;
}

function generateMapMatrix(DATA) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    var rows = new Array(); // Custom rows naming for jQuery Seats
    var overallMinMaxXY = getOverallMaxXY(DATA); // return [xMax, xMin, yMax, yMin, rowMax, maxSeats];
    var sortedSections = sortSeatmaps(DATA);
    var [mapping, matrixBIG] = bigMatrixDim(sortedSections);
    
    if (DATA.CONFIG['DEBUG']) {
        console.log('mapping: ');
        console.log(mapping);
        console.log('mapping.length: ' + Object.keys(mapping).length);
        console.log('matrixBIG:');
        console.log(matrixBIG);   
        console.log('overallMinMaxXY:');
        console.log(overallMinMaxXY);
        console.log("Overall maxmimum seats per row: " + overallMinMaxXY[5]);
    }

    var seatsUnavailable = new Array();
    var mappingPricescalesSections = new Array();
    var jQuerySeatID;

    // LOOP THROUGH SORTED SECTIONS
    for (var k in sortedSections) {
        // SECTION OBJ
        var sectionObj = sortedSections[k][1];
        if (DATA.CONFIG['DEBUG']) console.log("NEW SECTION WITH ID: " + sectionObj.ID);

        // CALCULATE MATRIX
        var sectionMinMax = getMinMaxXY(sectionObj.ROWS); // returns sectioMinMax.maximum.x, sectioMinMax.minimum.x, sectioMinMax.maximum.y, sectioMinMax.minimum.y
        // if (DATA.CONFIG['DEBUG']) console.log('sectionMinMax:');
        // if (DATA.CONFIG['DEBUG']) console.log(sectionMinMax);
        var matrixX = sectionMinMax.maximum.x - sectionMinMax.minimum.x + 1;
        var matrixY = ObjectLength(sectionObj.ROWS);
        // var matrixY = sectionMinMax.maximum.y - sectionMinMax.minimum.y + 1;

        if (DATA.CONFIG['DEBUG']) console.log('matrixX: ' + matrixX);
        if (DATA.CONFIG['DEBUG']) console.log('matrixY: ' + matrixY);
        var matrix = arrayMatrix(matrixY, matrixX, '_');

        var maxSectionSeats = sectionMinMax.maximum.x - sectionMinMax.minimum.x + 1;
        var overallMaxSectionSeats = overallMinMaxXY[5] + 1;
        var offsetLeft = 0;
        var offsetRight = 0;
        var seatDiff;
        if (maxSectionSeats != overallMaxSectionSeats) {
            seatDiff = overallMaxSectionSeats - maxSectionSeats;
            if (DATA.CONFIG['DEBUG']) console.log("seatDiff: " + seatDiff);
            if (seatDiff > 0) {
                if (seatDiff & 1) { // ODD
                    offsetLeft = Math.floor(seatDiff / 2);
                    offsetRight = Math.floor((seatDiff / 2)) + (seatDiff % 2);
                    var remainder = seatDiff % 2;
                    
                    if (DATA.CONFIG['DEBUG']) console.log("Odd & Remainder: " + remainder);
                }
                else { // EVEN
                    offsetRight = seatDiff / 2;
                    offsetLeft = seatDiff / 2;
                    
                    if (DATA.CONFIG['DEBUG']) console.log('Even');
                }
                if (DATA.CONFIG['DEBUG']) console.log("offsetLeft: " + offsetLeft + " offsetRight: " + offsetRight);
            }
        }
        else {
            seatDiff = 0;
        }
        if (DATA.CONFIG['DEBUG']) console.log('overallMaxSectionSeats ' + overallMaxSectionSeats + " | maxSectionSeats " + maxSectionSeats + " | seatDiff: " + seatDiff);

        // LOOP THROUGH ROWS
        var rowSection = 0;
        for (var i in sectionObj.ROWS) {
            rowSection++;

            // LOOP THROUGH ROW SEATS
            var firstSeat = true;
            for (var seat in sectionObj.ROWS[rowSection]) {
                var seatObj = sectionObj.ROWS[rowSection][seat];

                // ONLY ON FIRST SEAT
                if (firstSeat == true) {
                    rows.push(seatObj.ROW_PARSED); // ADD ROW_PARSED TO ROWS ARR
                }

                var seatX = seatObj.X_COORD - sectionMinMax.minimum.x;
                var seatY = rowSection - 1;

                // GET PRICESCALES OBJECT
                var seatPricescalesID = seatObj.PRICESCALES_ID;
                var pricescalesObj = DATA.VENUE.PRICESCALES[seatPricescalesID];

                // SEAT STRING
                var seatString;

                // SEAT LETTER
                var seatLetter = pricescalesObj.CODE;

                // NEW
                jQuerySeatID = sectionObj.ID + '_' + seatObj.ROW + '_' + seatObj.SEATNR;
                if (seatObj.ENABLED == 1) {
                    seatString = seatLetter + '[' + jQuerySeatID + ', ]';
                }
                else if (seatObj.ENABLED == 0) {
                    seatString = '_';
                }

                // PUSH FINAL STRING TO CORRECT POS IN ARRAY
                matrix[seatY][seatX] = seatString;

                // SAVE UNAVAILABLE SEAT FOR LATER DISABLE
                if (seatObj.AVAILABLE == 0 && seatObj.ENABLED == 1) { // seatObj.ENABLED == 1 because cannot make undrawn (ENABLED == 0) seats unavailable
                    seatsUnavailable.push(jQuerySeatID);
                }

                // MAPPING PRICESCALE WITH SECTION FOR LATER USE
                if (typeof mappingPricescalesSections[seatPricescalesID] == 'undefined') {
                    mappingPricescalesSections[seatPricescalesID] = new Array();
                    mappingPricescalesSections[seatPricescalesID].push(seatObj.SECTIONID);
                }
                else if (typeof mappingPricescalesSections[seatPricescalesID] !== 'undefined') {
                    if (mappingPricescalesSections[seatPricescalesID].indexOf(seatObj.SECTIONID) == false) {
                        mappingPricescalesSections[seatPricescalesID].push(seatObj.SECTIONID);
                    }
                }

                firstSeat = false;
            }

            for (var h = 0; h < offsetLeft; h++) {
                matrix[seatY].unshift("_");
            }
            for (var j = 0; j < offsetRight; j++) {
                matrix[seatY].push("_");
            }
        }

        var y = mapping[sectionObj.ID]['y'];
        var x = mapping[sectionObj.ID]['x'];
        matrixBIG[y][x] = matrix;
        
        if (DATA.CONFIG['DEBUG']) {
            console.log('mapping y: ' + mapping[sectionObj.ID]['y']);
            console.log('mapping x: ' + mapping[sectionObj.ID]['x']); 
        }
    }

    if (DATA.CONFIG['DEBUG']) console.log(matrixBIG);

    // GENERATE MAP STRING
    var map1d = new Array();
    var length1 = matrixBIG.length;
    for (var i = 0; i < length1; i++) { // SECTIONS

        var length2 = matrixBIG[i].length;
        for (var j = 0; j < length2; j++) { // IN SECTION

            var length3 = matrixBIG[i][j].length;
            for (var k = 0; k < length3; k++) { // ROWS

                var rowString = matrixBIG[i][j][k].join("");
                map1d.push(rowString);
            }
        }
    }

    if (DATA.CONFIG['DEBUG']) {
        console.log(map1d);
        console.log(seatsUnavailable);
        console.log(mappingPricescalesSections);
        console.log(rows); 
    }

    return [map1d, seatsUnavailable, mappingPricescalesSections, rows];
}

function seperateSeatmapsCSS(DATA) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    // ROW NODES OBJECT
    var nodes = document.getElementById('seat-map').childNodes;
    var sortedSections = sortSeatmaps(DATA);

    // IF ONLY 1 SECTION
    if (Object.keys(DATA.VENUE.SEATMAP_CONFIG).length == 1) {
        if (DATA.CONFIG['DEBUG']) console.log("NOT MORE THAN 1 SECTION AVAILABLE. RETURN.");
        var sectionObj = sortedSections[0][1];
        
        // INSERT INDICATOR
        if (DATA.CONFIG[DATA.VENUE.CODE]["BUEHNE"] === "TOP") {
            console.log('Inserting front indicator...');
            $("<h4 class=\"front-indicator\" style=\"margin-top: 0vw\">" + "BÜHNE<br><br>" + sectionObj.DESC + "</h4>").insertBefore($(nodes[0]));
            return;
        }
    }

    // IF MORE THAN 1 SECTIONS
    for (var k in sortedSections) {
        // SECTION OBJ
        var sectionObj = sortedSections[k][1];
        
        // Find out highest Row with the highest Seat
        var highestRow = Math.max.apply(null, Object.keys(sectionObj.ROWS));
        var highestSeat = Math.max.apply(null, Object.keys(sectionObj.ROWS[highestRow]));
        if (DATA.CONFIG['DEBUG']) console.log("highestRow: " + highestRow + " highestSeat: " + highestSeat);

        // SKIP LAST ROW
        if (k == 0) {
            if (DATA.CONFIG[DATA.VENUE.CODE]["BUEHNE"] == "TOP") {
                // FIRST RUN ONLY: INSERT FRONT INDICATOR
                $("<h4 class=\"front-indicator\" style=\"margin-top: 0vw\">" + "BÜHNE<br><br>" + sectionObj.DESC + "</h4>").insertBefore($(nodes[0]));
            }
            else if (DATA.CONFIG[DATA.VENUE.CODE]["BUEHNE"] == "BOTTOM") {
                $("<h4 class=\"front-indicator\" style=\"margin-top: 0vw\">" + sectionObj.DESC + "</h4>").insertBefore($(nodes[0]));
            }
        }
        else if (k >= 1) {
            // INSERT FRONT ROW INDICATOR
            $("<h4 class=\"front-indicator\">" + sectionObj.DESC + "</h4>").insertAfter($(nodes[oldHighestRow+1]));
        }

        if (k == Object.keys(DATA.VENUE.SEATMAP_CONFIG).length - 1) {
            if (DATA.CONFIG['DEBUG']) console.log("Break.");
            if (DATA.CONFIG[DATA.VENUE.CODE]["BUEHNE"] == "BOTTOM") {
                $("<h4 class=\"stage-indicator\" style=\"margin-top: 2vw;\">BÜHNE</h4>").insertAfter($(nodes[nodes.length-1]));
            }
            break;
        }

        var oldHighestRow = highestRow;
    }

    // SEPERATE BETWEEN ROWS IN SECTIONS
    var rowOverall = 0;
    for (var k in sortedSections) {
        var sectionObj = sortedSections[k][1];

        // LOOP THROUGH ROWS
        var rowSection = 0;
        var lastRowSection;
        for (var i in sectionObj.ROWS) {
            rowOverall++;
            lastRowSection = rowSection;
            rowSection++;

            if (lastRowSection >= 2) {
                // console.log("lastRowSection: " + lastRowSection + " rowSection: " + rowSection);
                var currY_COORD = sectionObj.ROWS[rowSection][1].Y_COORD;
                var lastY_COORD = sectionObj.ROWS[lastRowSection][1].Y_COORD;
                // console.log("lastY_COORD: " + lastY_COORD + " currY_COORD: " + currY_COORD);

                var delta = currY_COORD - lastY_COORD;
                if (delta > 1) {
                    // APPLY MARGIN
                    console.log("MORE THAN 1 Y DIFFERENCE");
                    nodes[rowOverall + 2].style.marginBottom = "25px";
                }
            }
        }
    }
}

// MYCART
function myCartRemoveWrapper(id) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    ProductManager.removeProduct(id);
    drawTable();
    $cartBadge.text(ProductManager.getTotalQuantity());
}

function myCartAddWrapper(id, product, summary, price, quantity, image, seatObj) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    ProductManager.setProduct(id, product, summary, price, quantity, image, seatObj);
    $cartBadge.text(ProductManager.getTotalQuantity());
    ProductManager.getAllProducts();
    ProductManager.getTotalPrice();
    ProductManager.getTotalQuantity();
    drawTable(); // FIX RIGHT PRICE FOR DROPDOWN OPTION
}

function checkoutGenerateURL(selected_seat_indexes) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    var rootURL = 'https://purchase.tickets.com/buy/TicketPurchase';
    // var parameter = "trxstate=148&pid=" + param["pid"] + "&user_context=" + param["user_context"];
    var parameter = "trxstate=148&pid=" + param["pid"] + "&user_context=" + param["user_context"] + "&cogid=" + param["cogid"] + "&coids=" + param["coids"] + "&oid=" + param["oid"] + "&ooids=" + param["ooids"] + "&orderkey=" + param["orderkey"];

    // var parameter_extended = '';
    // if (param["cogid"] && param["coids"] && param["oid"] && param["ooids"] && param["oderkey"]) {
    //     parameter_extended = "&cogid=" + encodeURIComponent(param["cogid"]) + "&coids=" + encodeURIComponent(param["coids"]) + "&oid=" + encodeURIComponent(param["oid"]) + "&ooids=" + encodeURIComponent(param["ooids"]) + "&orderkey=" + encodeURIComponent(param["orderkey"]);
    //     console.log(parameter_extended);
    // }

    var checkoutURL = decodeURIComponent(rootURL + '?' + parameter + '&selected_seat_indexes=' + selected_seat_indexes);
    // var checkoutURL = decodeURIComponent(rootURL + '?' + parameter + '&selected_seat_indexes=' + selected_seat_indexes) + parameter_extended;
    if (DATA.CONFIG['DEBUG']) console.log("checkoutURL: " + checkoutURL);

    // similar behavior as an HTTP redirect
    // window.location.replace(checkoutURL);
}

function checkoutCheckResponse(selected_seat_indexes, DATA) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    var rootURL = 'https://purchase.tickets.com/buy/TicketPurchase';
    var successful;
    
    
    var parameter = '';
    for (var property in param) {
        if (param.hasOwnProperty(property)) {
            parameter = parameter + property + '=' + param[property] + '&';
        }
    }
    parameter = parameter.substring(0, parameter.length - 1);
    parameter = parameter + "&trxstate=148&selected_seat_indexes=" + selected_seat_indexes;
    
    // PROXY CHECKOUT URL
    //var rootURLNoSlash = 'purchase.tickets.com:443/buy/TicketPurchase';
    let rootURLNoSlash = 'https://purchase.tickets.com/buy/TicketPurchase';
    //var checkoutURLNoSlash = decodeURIComponent(rootURLNoSlash + '?' + parameter);
    //var proxyCheckoutURL = DATA.CONFIG["CORS-ANYWHERE"]["ROOT_URL"] + checkoutURLNoSlash;
    
    
    var checkoutURLNoSlash = encodeURIComponent(rootURLNoSlash + '?' + parameter + '&request_switch=checkoutCheckResponse');
    let checkoutCheckResponseURI = DATA.CONFIG["SEATMAP-SERVER"]["ROOT_URL"] + "?url=" + checkoutURLNoSlash;
    
    var checkoutURL;
    if (param.hasOwnProperty("orderkey")) {
        if (DATA.CONFIG['DEBUG']) console.log("ADD ANOTHER TICKET DETECTED");
        var parameter_30 = 'user_context=' + param['user_context'] + '&orderkey=' + param['orderkey'] + '&orgid=' + param['orgid'] + '&trxstate=30';
        checkoutURL = decodeURIComponent(rootURL + '?' + parameter_30);
    }
    else {
        if (DATA.CONFIG['DEBUG']) console.log("FIRST TICKET DETECTED");
        checkoutURL = decodeURIComponent(rootURL + '?' + parameter);
    }
    
    if (DATA.CONFIG['DEBUG']) {
        console.log(DATA);
        //console.log('proxyCheckoutURL: ' + proxyCheckoutURL);
        //console.log('checkoutURL:' + checkoutURL);
        console.log('checkoutCheckResponseURI: ' + checkoutCheckResponseURI);
    }
    
    if (DATA.CONFIG['DEBUG']) console.log("DATA['CONFIG']['CHECKOUT-AVAILABILITY-CHECK']: " + DATA['CONFIG']['CHECKOUT-AVAILABILITY-CHECK']);
    
    if( DATA['CONFIG']['CHECKOUT-AVAILABILITY-CHECK'] == 'enabled' ) {
        if (DATA.CONFIG['DEBUG']) console.log('CHECKOUT-AVAILABILITY-CHECK enabled');
        
        $.getJSON(checkoutCheckResponseURI,
        function(data) {
            if (DATA.CONFIG['DEBUG']) console.log(data);
            
      
            if( data['no_timeout_error_msg']['value'] === '' ) {
                console.log('Good to go');
                successful = 1;
                
                ProductManager.clearProduct();
                $cartBadge.text(ProductManager.getTotalQuantity());
                $("#" + idCartModal).modal("hide");
    
                // REDIRECT TO TICKET PURCHASE
                if (DATA.CONFIG['DEBUG']) console.log('successfull, now going to: ' + checkoutURL);
                //window.location.replace(checkoutURL);
            }
            else if( data['no_timeout_error_msg']['value'] !== '' ) {
                console.log('We have an error');
                successful = 0;
                
                let errorMsg = data['no_timeout_error_msg']['value'].replace(/\<br\>/g, ' ');
                new jBox('Notice', {
                    content: errorMsg,
                    color: 'red',
                    width: '100vw',
                    responsiveWidth: true,
                    position: { x: 'center', y: 'top' },
                    autoClose: 10000,
                    closeButton: 'box',
                });
            }
        });
    }
    else if( DATA['CONFIG']['CHECKOUT-AVAILABILITY-CHECK'] == 'disabled' ) {
        if (DATA.CONFIG['DEBUG']) console.log('CHECKOUT-AVAILABILITY-CHECK disabled');
        if (DATA.CONFIG['DEBUG']) console.log('Now going to: ' + checkoutURL);
        window.location.replace(checkoutURL);
    }
    
    
    // var successful;
    // $.ajax({
    //     url: checkoutCheckResponseURI,
    //     method: 'GET',
    //     dataType: 'html',
    //     //headers: { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Language': 'de,en-US;q=0.7,en;q=0.3', 'Host': 'purchase.tickets.com' },
    //     headers: { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Language': 'de,en-US;q=0.7,en;q=0.3' },
    //     success: function(data) {
    //         // CORS PROXY RESPONSE
    //         data = data.replace(/(?:\r\n|\r|\n|\t| {2,})/g, '');
    //         var errorMsg = data.match(/<input type="hidden" name="no_timeout_error_msg" id="no_timeout_error_msg" value="(.*?)" \/>/)[1];
    //         if (DATA.CONFIG['DEBUG']) console.log('errorMsg: ' + errorMsg);
            
    //         if (errorMsg === '') {
    //             successful = true;
    //             ProductManager.clearProduct();
    //             $cartBadge.text(ProductManager.getTotalQuantity());
    //             $("#" + idCartModal).modal("hide");

    //             // REDIRECT TO TICKET PURCHASE
    //             if (DATA.CONFIG['DEBUG']) console.log('successfull, now going to: ' + checkoutURL);
    //             window.location.replace(checkoutURL);
    //         }
    //         else {
    //             successful = false;
    //             errorMsg = errorMsg.replace(/\<br\>/g, ' ');
    //             new jBox('Notice', {
    //                 content: errorMsg,
    //                 color: 'red',
    //                 width: '100vw',
    //                 responsiveWidth: true,
    //                 position: { x: 'center', y: 'top' },
    //                 autoClose: 10000,
    //                 closeButton: 'box',
    //             });
    //         }
            
    //     }
    // });

    return successful;
}

function selectRefreshPrice(select) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    if (DATA.CONFIG['DEBUG']) console.log(select);

    var $sel = $(select);
    var value = $sel.val();
    var text = $("option:selected", $sel).text();
    var idSelect = $sel[0].id;
    var id = idSelect.replace("select", "");

    ProductManager.updatePrice(id, value);
    selectOptionSelected[idSelect] = { selected: text }; // Remember Select Option Value for redraw in drawTable()
    // drawTable();
}

function setSelectedIndex() {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    for (var idSelect in selectOptionSelected) {
        if (selectOptionSelected.hasOwnProperty(idSelect)) {
            var s = document.getElementById(idSelect);
            var v = selectOptionSelected[idSelect].selected;

            if (s == null) {
                delete selectOptionSelected[idSelect];
                continue;
            }
            else {
                for (var i = 0; i < s.options.length; i++) {
                    if (s.options[i].text === v) {
                        if (DATA.CONFIG['DEBUG']) console.log(s.options[i].text + ' matches ' + v);
                        if (DATA.CONFIG['DEBUG']) console.log(v);
                        if (DATA.CONFIG['DEBUG']) console.log(s);
                        s.options[i].selected = true;
                        selectRefreshPrice(s); // FIX RIGHT PRICE OPTION DROPDOWN
                    }
                }
            }

        }
    }
}

function generateSeatmap(DATA) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    var returnArr = generateMapMatrix(DATA);
    var map1d = returnArr[0];
    var seatsUnavailable = returnArr[1];
    var mappingPricescalesSections = returnArr[2];
    var rows = returnArr[3];
    var seats = generateSeats(DATA, mappingPricescalesSections);
    var legend = generateLegend(DATA, 'legend');
    var firstSeatLabel = 1;

    // CHANGE HTML TITLE
    document.title = DATA.EVENT.DESC + ' | Saalplanbuchung by Tickets.com';
    
    // CUSTOM CONFIG SETTINGS FOR SEATMAP
    var left = true;
    if (typeof DATA.CONFIG[DATA.VENUE.CODE]["LEFT_NAMING"] != "undefined") {
        left = DATA.CONFIG[DATA.VENUE.CODE]["LEFT_NAMING"];
    }
        
    // SEAT MAP
    sc = $('#seat-map').seatCharts({
        map: map1d,
        seats: seats,

        naming: {
            top: false,
            left: left,
            // rows: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
            rows: rows,
            // columns: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y'],
            getLabel: function(character, row, column) {
                return firstSeatLabel++;
            },
        },
        legend: legend,
        click: function() {
            if (this.status() == 'available') {
                if ((ProductManager.getTotalQuantity() + 1) > DATA.CONFIG[DATA.VENUE.CODE]["MAX_TICKETS_PER_USER"]) {
                    var errorMsg = 'Maximale Ticketantahl erreicht: Sie können nicht mehr als ' + DATA.CONFIG[DATA.VENUE.CODE]["MAX_TICKETS_PER_USER"] + ' Tickets buchen.';
                    new jBox('Notice', {
                        content: errorMsg,
                        color: 'red',
                        width: '100vw',
                        responsiveWidth: true,
                        position: { x: 'center', y: 'top' },
                        closeButton: 'box',
                        autoClose: 10000,
                    });
                    return;
                }

                // ADD PRODUCT TO CART
                fillSeatObjData(this.settings.id, DATA);
                myCartAddWrapper(this.settings.id, this.settings.data.product, this.settings.data.color, this.settings.data.price, 1, '', this);

                return 'selected';
            }
            else if (this.status() == 'selected') {
                myCartRemoveWrapper(this.settings.id);
                return 'available';
            }
            else if (this.status() == 'unavailable') {
                // SEAT ALREADY BOOKED
                return 'unavailable';
            }
            else {
                return this.style();
            }
        }
    });

    // INIT JBOX TOOLTIP
    var jbox = new jBox('Tooltip', {
        attach: '.available',
        trigger: 'mouseenter',
        onCreated: function() {
            if (DATA.CONFIG['DEBUG']) console.log("onCreated");
        },
        onOpen: function() {
            //  GET SEAT ID AND OBJECT
            var seatID = this.source.context.id;
            var seatObj = sc.get(seatID);
            //   console.log(seatObj);

            if (seatID == '' || seatObj.settings.status == 'unavailable') {
                if (DATA.CONFIG['DEBUG']) console.log("Not a real seat or seat unavailable -> Return.");
                return;
            }

            // FILL SEAT OBJECT IF NOT ALREADY
            fillSeatObjData(seatID, DATA);

            //   SET JBOX CONTENT
            this.setContent(seatObj.settings.data.productJBox);
        },
        onClose: function() {}
    });

    // DETACH JBOX FROM LEGEND AND UNAVAILABLE SEATS
    for (var i = 0; i < jbox.attachedElements.length; i++) {
        if (jbox.attachedElements[i].id == "") {
            jbox.detach($(jbox.attachedElements[i]));
            i = -1;
            continue;
        }
    }
    for (var j = 0; j < seatsUnavailable.length; j++) {
        jbox.detach($('#' + seatsUnavailable[j]));
    }

    // MYCART
    $(function() {
        var goToCartIcon = function($addTocartBtn) {
            var $cartIcon = $(".my-cart-icon");
            var $image = $('<img width="30px" height="30px" src="' + $addTocartBtn.data("image") + '"/>').css({ "position": "fixed", "z-index": "999" });
            $addTocartBtn.prepend($image);
            var position = $cartIcon.position();
            $image.animate({
                top: position.top,
                left: position.left
            }, 500, "linear", function() {
                $image.remove();
            });
        };
    });

    // RUN POST GENERATION HOOKS
    sc.status(seatsUnavailable, 'unavailable'); // seatsUnavailable RECEIVED FROM SERVER
    seperateSeatmapsCSS(DATA); // CSS CHANGES AFTER GENERATE
    venueSpecificCSS(DATA);
    $(window).trigger('resize');
}

function venueSpecificCSS(DATA) {
    if (DATA.CONFIG['DEBUG']) console.log(getFuncName());

    // VENUE SPECIFIC WIDTH TO CENTER FRONT INDICATORS
    var paddingLeft = DATA.CONFIG[DATA.VENUE.CODE]["PADDING-LEFT"];
    $(".front-indicator").css({ "padding-left": paddingLeft });
    var paddingLeftStage = DATA.CONFIG[DATA.VENUE.CODE]["PADDING-LEFT-STAGE"];
    $(".stage-indicator").css({ "padding-left": paddingLeftStage });

    // STAATSOPERETTE DRESDEN SPECIFIC
    if (DATA.VENUE.CODE == "SAAL KKM" || DATA.VENUE.CODE == "GSP KKM") {
        $("#seat-map").append(DATA.CONFIG[DATA.VENUE.CODE]["TONPULT"]);
    }

    // VENUE SPECIFIC CSS
    if (DATA.CONFIG['DEBUG']) console.log('Applying venue specific CSS for ' + DATA.CONFIG[DATA.VENUE.CODE]);
    var styleSheet = document.createElement("style");
    styleSheet.type = "text/css";
    styleSheet.innerText = DATA.CONFIG[DATA.VENUE.CODE]["CSS"];
    document.head.appendChild(styleSheet);
}
