function readData() {
    generic = new Generic(parseInt(pstore['key']), pstore['has_options']);
    for (var id in pstore['specifics']) {
        specific = new Specific(id);
        for (var o_id in pstore['specifics'][id]['offers']) {
            var op = pstore['offer_params'];
            var specific_offer_params = pstore['specifics'][id]['offers'][o_id]['offer_params'];
            jQuery.extend(op, specific_offer_params);
            op['extended_availability_text'] = op['extended_availability_text'].
                replace(/@OFFER.SHIPPING_MESSAGE@/g, op['shipping_message']).
                replace(/@OFFER.QUANTITY@/g, op['quantity']);
            op['availability_message'] = op['availability_message'].
                replace(/@OFFER.QUANTITY@/g, op['quantity']);
            offer = new Offer(
                o_id, op['shop_id'],
                op['brutto_price_cents'],
                op['explained_price'],
                op['quantity'],
                formatCurrency(op['shipping_costs_cents']/100.0),
                op['shipping_cost_fixed_cents'],
                op['shipping_costs_description'],
                op['availability_state'],
                op['availability_message'],
                op['extended_availability_text'],
                op['allowance'],
                op['allowance_reasoning']
                );
            specific.addOffer(offer);
            eval(op['add_cart_items'])
        }
        generic.addSpecific(specific);
        if (!pstore['has_options']) {
            for (var aid in pstore['specifics'][id]['variation_values']) {
                values = pstore['specifics'][id]['variation_values'][aid];
                specific.addAttribute(new Attribute(aid, values));
            }
        }
    }
    generic.clearSelection();
    for (var aid in selections) {
        generic.addSelection(new Selection(aid, selections[aid]));
    }
    for (var shop_id in pstore['shops']) {
        shop_values = pstore['shops'][shop_id];
        generic.addShop(new Shop(shop_id, shop_values['name'], shop_values['shipping_costs_description']));
    }
    for (var i = 0; i < attribute_variations.length; i++) {
        aid = attribute_variations[i][0]
        generic.addVariantAttribute(new VariantAttribute(aid, attribute_variations[i][1][0], attribute_variations[i][1][1]));
    }
}

function setUpProductImages() {
    var totalImageWidth = 0;
    var totalThumbnailWidth = 0;
    var thumbnailSetWidth = $("#thumbnails ul").width();
    var imagePositions = new Array();

    /* Loop through all the images and store their accumulative widths in totalImageWidth */
    $('#image_gallery .image').each(function(i){
        /* The positions array contains each image's cumulative offset from the left part of the container */
        imagePositions[i] = totalImageWidth;
        totalImageWidth += $(this).innerWidth();
    
        /* Make sure that all images have preset css-values for width */
        if(!$(this).width()){
            alert("Please, set a width for all your images!");
            return false;
        }
    });

    /* Loop through all the thumbnails and store their accumulative widths in totalThumbnailWidth */
    $('#thumbnails ul').each(function(i){
        totalThumbnailWidth += $(this).width();
    
        /* Make sure that all thumbnails have preset css-values for width */
        if(!$(this).width()){
            alert("Please, set a width for all your thumbnails!");
            return false;
        }
    });

    /* Change the container div's width to the exact width of all the images combined */
    $('#image_gallery ul').width(totalImageWidth);
    $('#thumbnail_container').width(totalThumbnailWidth);

    /* On a thumbnail click */
    $('#thumbnails ul li img').click(function(e){
        /* Calculate the new offset */
        var image = $(this).parent().attr('id');
        var position = parseInt(image.charAt(image.length - 1), 10);
    
        /* toggle active/inactive states */
        $('#thumbnails li.active').switchClass('active', 'inactive');
        $(this).parent().switchClass('inactive', 'active');

        /* Start the sliding animation */
        $('#image_gallery ul').stop().animate({
            marginLeft:-imagePositions[position]+'px'
        },500);
    });
  
    /* On a click on the next-button */
    $('#image_navigation .next').click(function(e){
        e.preventDefault();
        var thumbnail_container = $(this).next("#thumbnails").children("#thumbnail_container");
        var next_position = parseInt(thumbnail_container.children('.active').attr('id'), 10) + 1;
        var last_position_id = thumbnail_container.children(':last-child').attr('id');
        var last_position = parseInt(last_position_id.charAt(last_position_id.length - 1), 10);
    
        if(next_position >= last_position) next_position = last_position;
    
        thumbnail_container.children('.active').removeClass('active');
        $("#"+next_position).addClass('active');
        var new_offset = (next_position * thumbnailSetWidth) - thumbnailSetWidth;

        /* Start the sliding animation */
        $('#thumbnail_container').stop().animate({
            marginLeft:-new_offset+'px'
        }, 500);
    });
  
    /* On a click on the back-button */
    $('#image_navigation .back').click(function(e){
        e.preventDefault();
        var thumbnail_container = $(this).nextAll("#thumbnails").children("#thumbnail_container");
        var next_position = parseInt(thumbnail_container.children('.active').attr('id'), 10) - 1;
        if(next_position < 1) next_position = 1;
    
        thumbnail_container.children('.active').removeClass('active');
        $("ul#"+next_position).addClass('active');
        var new_offset = (next_position * thumbnailSetWidth) - thumbnailSetWidth;

        /* Start the sliding animation */
        $('#thumbnail_container').stop().animate({
            marginLeft:-new_offset+'px'
        }, 500);
    });

    /* On page load, mark the first thumbnail as well as the first thumbnail set as active */
    $('#image_navigation ul li:first').addClass('active');
    $('#image_navigation ul:first').addClass('active');
}

jQuery(document).ready(function(){
    $('.view_types .grid_inactive').live('click', function(){
        $('#search_results ul').stop().animate({
            opacity: '0.3'
        }, 300, 'linear', function(){
            $('#product_list_detailed').attr('id', 'product_list_grid');
        });
        $('#search_results ul').animate({
            opacity: '1.0'
        }, 300, 'linear');
  
        $('.view_types .detailed_active').each(function(){
            $(this).attr("class", "detailed_inactive");
        });
        $('.view_types .grid_inactive').each(function(){
            $(this).attr("class", "grid_active");
        });
    });

    $('.view_types .detailed_inactive').live('click', function(){
        $('#search_results ul').stop().animate({
            opacity: '0.3'
        }, 300, 'linear', function(){
            $('#product_list_grid').attr('id', 'product_list_detailed');
        });
        $('#search_results ul').animate({
            opacity: '1.0'
        }, 300, 'linear');
  
        $('.view_types .grid_active').each(function(){
            $(this).attr("class", "grid_inactive");
        });
        $('.view_types .detailed_inactive').each(function(){
            $(this).attr('class', 'detailed_active');
        });
    });
});

function adjustAttributes(attribute_id) {
    var ai;
    for (var aix = 0; aix < generic.variant_attributes.length; aix++) {
        var variant_attribute = generic.variant_attributes[aix];
        ai = variant_attribute.id;
        var sel = $("#selector_" + ai);
        if ((variant_attribute.values[0].length == 1) && (ai == "107")) {
            sel.attr('disabled', false);
            sel.children()[1].selected = true;
            sel.attr('disabled', true);
            $("#l_selector_" + ai).hide();
            $("#s_selector_" + ai).hide();
        } else {
            sel.attr('disabled', false);
            $("#l_selector_" + ai).show();
            $("#s_selector_" + ai).show();
        }

    }
    var selector = $("#selector_" + attribute_id);
    var selected_norm_value = selector == null ? "" : selector.val();

    if (selected_norm_value == "") {
        rebuildAttributeLists();
        return;
    }

    var selection = getSelection();
    // find matching products
    var matching_offers = new Array();

    var nselect = 0;
    var list_norm_value;
    for (var si = 0; si < selection.length; si++) {
        ai = si2ai(si);
        if (selection[si][1] == "") {
            matching_offers[si] = generic.offers;
            continue;
        }

        list_norm_value = selection[si][1];
        matching_offers[si] = getMatching(list_norm_value, ai);
        if (matching_offers[si].length > 0) nselect++;
    }
    generic.clearMatchingShop();
    for (var m_si = 0; m_si < matching_offers.length; m_si++) {
        for (var oi = 0; oi < matching_offers[m_si].length; oi++) {
            generic.addMatchingShop(getShop_from_id(matching_offers[m_si][oi].shop_id));
        }
    }

    if (nselect == 0) {
        rebuildAttributeLists();
        return;
    }
    if (!generic.is_options_product) {
        for (var mm_si = 0; mm_si < matching_offers.length; mm_si++) {
            var m_ai = si2ai(mm_si);
            if (m_ai != attribute_id) continue;
            for (var lsi = 0; lsi < generic.variant_attributes.length; lsi++) {
                var ai1 = si2ai(lsi);
                if (ai1 == attribute_id) continue;
                var list = $("#selector_" + ai1);
                list_norm_value = list.val(); //old selection in other list
                clearSelectList(ai1);

                var offers = matching_offers[mm_si];

                for (var ssi = 0; ssi < offers.length; ssi++) {
                    var specific = offers[ssi].specific;

                    for (sai = 0; sai < specific.attributes.length; sai++) {
                        var a = specific.attributes[sai];

                        if (a.id == ai1) {
                            var is_selected = false;
                            if (list_norm_value == a.norm_value) {
                                is_selected = true;
                            }
                            addToList(a, is_selected);
                        }

                    }
                }
            }
            var ai2 = 107;

            if (generic.variant_attributes.length == 1) continue;

            clearSelectList(ai2);

            var offers2 = matching_offers[mm_si];

            for (var ssi2 = 0; ssi2 < offers2.length; ssi2++) {
                var shop_id = offers2[ssi2].shop_id;
                var shop = getShop_from_id(shop_id);
                addToList(shop.attribute, list_norm_value == shop.name);
            }
        }
    }
}

function addToArray(a,v) {
    for (var i = 0; i < a.length; i++) {
        if (a[i] == v)
            return;
    }
    a[a.length] = v;
}

function redrawAttributes(attribute_id) {
    // recompute text decorations
    var selection = getSelection();
    for (var xsi =0; xsi < generic.variant_attributes.length; xsi++) {
        var ai = si2ai(xsi);
        var variant_attribute = generic.variant_attributes[xsi];
        for (var vj=0; vj < variant_attribute.values[0].length; vj++) {
            var value = variant_attribute.values[0][vj];
            var selector = $("#selector_" + ai);
            var found = false;
            var options = selector.children();
            for (var i = 0; i < options.length; i++) {
                if (options[i].value == value[1]) {
                    found = true;
                    break;
                }
            }
            var span_obj = $("#a_" + ai + "_" + vj);
            if(ai == 32){
                span_obj.className = selection[xsi][1] == value[1] ? "color_box variant_attribute var_attribute_selected": (found ? "color_box variant_attribute var_attribute_unselected" : "color_box variant_attribute var_attribute_unselected var_attribute_disabled");
            } else {
                span_obj.className = selection[xsi][1] == value[1] ? "variant_attribute var_attribute_selected": (found ? "variant_attribute var_attribute_unselected" : "variant_attribute var_attribute_unselected var_attribute_disabled");
            }
        }
    }
}

function observeAttributes() {
    $(document).ready(function() {
        $('.variant_attribute').click(function() {
            var axi = this.id.indexOf("a_");
            var saxi = this.id.substr(axi+2);
            var svi = saxi.indexOf("_");
            var vi = saxi.substr(svi+1);
            var ai = this.id.substr(axi+2, svi);
            var xsi = ai2si(ai);
            var selector = $("#selector_" + ai);
            var selectedIndex = 0;
            var variant_attribute = generic.variant_attributes[xsi];
            var color_value = variant_attribute.values[0][vi][1];

            for (i = 0; i < selector.options.length; i++) {
                if (color_value == selector.options[i].value) {
                    selectedIndex = i;
                    break;
                }
            }
            if (selectedIndex == 0) {
                rebuildAttributeLists();
                redrawAttributes();
                for (i = 0; i < selector.options.length; i++) {
                    if (color_value == selector.options[i].value) {
                        selectedIndex = i;
                        break;
                    }
                }
            }

            if (selectedIndex == 0) {
                redrawAttributes();
                return;
            }

            selector.children()[i].selected = true;
            adjustAttributes(ai);
            redrawAttributes();
            adjustAttributes(ai);
            redrawAttributes();
            generic.redrawPriceInfo();
        });
    });
}


function formatCurrency(num) {
    if(isNaN(num))
        num = "0";
    var sign = (num == (num = Math.abs(num)));
    num = Math.floor(num*100+0.50000000001);
    var cents = num%100;
    num = Math.floor(num/100).toString();
    if(cents<10)
        cents = "0" + cents;
    for (var i = 0; i < Math.floor((num.length-(1+i))/3); i++)
        num = num.substring(0,num.length-(4*i+3))+'.'+ num.substring(num.length-(4*i+3));
    return (((sign)?'':'-') + num + ',' + cents + " EUR");
}

function intersectOffers(set1, set2) {
    var intersection = new Array();
    for (var is1 = 0; is1 < set1.length; is1++) {
        for (var is2 = 0; is2 < set2.length; is2++) {
            if (set1[is1].equalsOffer(set2[is2])) {
                intersection.push(set1[is1]);
            }
        }
    }
    return intersection;
}
function mergeArrays(array_of_arrays) {
    var result = Array();

    for (var i = 0; i < array_of_arrays.length; i++) {
        var ta = array_of_arrays[i];
        for (var ti = 0; ti < ta.length; ti ++) {
            var exists = false;
            for (var mi = 0; mi < result.length; mi ++) {
                if (result[mi] == ta[ti]) {
                    exists = true;
                }
            }
            if (!exists) {
                result.push(ta[ti]);
            }
        }
    }
    return result;
}

function autoSelectSingleChoices(attribute_id) {
    for (var i =0; i < generic.variant_attributes.length; i++) {
        var ai = generic.variant_attributes[i].id;
        if (ai == attribute_id || attribute_id == null) {
            var list_id = $("#selector_" + ai);

            if (list_id.children().length == 2) {
                list_id.children()[1].selected = true;
            }
        }

    }
}


function rebuildAttributeLists() {
    if (generic.is_options_product) {
        clearAllSelections();
        return;
    }
    clearAllAttributeSelectLists();


    for (var i = 0; i < generic.specifics.length; i++) {

        var specific = generic.specifics[i];

        for (var j =0; j< specific.attributes.length; j++) {
            addToList(specific.attributes[j]);
        }

    }
}

function ai2si(attribute_id) {
    for (var ai =0; ai < generic.variant_attributes.length; ai++) {
        if (generic.variant_attributes[ai].id == attribute_id) return ai;
    }
    return -1;
}

function si2ai(selector_id) {
    return generic.variant_attributes[selector_id].id;
}

Array.prototype.array_value_delete = function(position) {
    for (var x = 0; x < this.length; ++x) {
        if (x >= position) {
            this[x] = this[x + 1];
        }
    }
    this.pop();
};
function clearSelectList(ai6) {
    var list_id = $("#selector_" + ai6);

    if (list_id.children().size() <= 1) {
        return;
    }

    list_id.children()[0].selected = true;
    for (var j = list_id.children().size() - 1; j>=1; j--) {
        list_id.children().last().remove()
    }
}

function clearAllSelections() {
    for (var i =0; i < generic.variant_attributes.length; i++) {
        var ai = generic.variant_attributes[i].id;
        var list_id = $("#selector_" + ai);

        if (list_id.children().size() <= 1) {
            return;
        }

        list_id.children()[0].selected = true;
    }
}

function clearAllAttributeSelectLists() {
    for (var ai =0; ai < generic.variant_attributes.length; ai++) {
        if (generic.variant_attributes[ai].id != 107) {
            clearSelectList(generic.variant_attributes[ai].id);
        }
    }
}

function getShop_from_id(id) {
    for (var i = 0; i < generic.shops.length; i++) {
        if (id == generic.shops[i].id) return generic.shops[i];
    }
    return null;
}

function getOptionsText(selection) {
    var options_text = "";
    for (var si = 0; si < selection.length; si++) {
        var ai = si2ai(si);
        var name = generic.variant_attributes[si].short_name;
        var val = selection[si][0];
        if (selection[si][1] != "" && ai != 107) {
            if (val.length <= 20) {
                options_text += "<p><strong>" + name + ": </strong>" + "<span>" + val + "</span></p>";
            } else {
                options_text += "<p><strong>" + name + ": </strong>" + "<br />" + "<span>" + val + "</span></p>";
            }
        }
    }
    return options_text;
}

function getOptions(selection) {
    var options = new Array();
    for (var si = 0; si < selection.length; si++) {
        var ai = si2ai(si);
        var val = selection[si][1];
        var options_entry = new Array();
        if (selection[si][1] != "" && ai != 107) {
            options_entry.push(ai, val);
            options.push(options_entry);
        }
    }
    return options;
}

function getShop_from_name(name) {
    for (var i = 0; i < generic.shops.length; i++) {
        if (name == generic.shops[i].name) return generic.shops[i];
    }
    return null;
}
//create function, it expects 2 values.
function insertAfter(newElement,targetElement) {
	//target is what you want it to go after. Look for this elements parent.
	var parent = targetElement.parentNode;

	//if the parents lastchild is the targetElement...
	if(parent.lastchild == targetElement) {
		//add the newElement after the target element.
		parent.appendChild(newElement);
		} else {
		// else the target has siblings, insert the new element between the target and it's next sibling.
		parent.insertBefore(newElement, targetElement.nextSibling);
		}
}
/*
 * add attribute to selector if not already there
 */
function addToList(attribute, sel) {
    var selector = $("#selector_" + attribute.id);

    var options = selector.children();
    var append_index = 0;
    for (var i = 0; i < options.length; i++) {
        if (options[i].value == attribute.norm_value) {
            return;
        }
        //find most adjacent ordered by normalized values
        if (options[i].value < attribute.norm_value && i > 0) {
            append_index = i;
        }
    }

    var newElem = document.createElement('option');

    //sorted insert into selector list
    insertAfter(newElem, options[append_index])
    
    newElem.text = attribute.ext_value;
    newElem.value = attribute.norm_value;

    //if attribute is a color
    if (attribute.id == 32) {
        //get background from internal value which is the color code
        newElem.style.backgroundColor = "#" + attribute.int_value;
        newElem.style.color = "#" + black_or_white("" + attribute.int_value);
    }
    //unique id for selector option
    newElem.id = attribute.id + "_" + attribute.norm_value;

    

    if (sel == true) {
        newElem.selected = true;
    }
}

/**
 * @param norm_value - attribute value used for matching to specifics
 * @param attribute_id - attribute_definition_id
 *
 * @return array with matching specific products
 */
function getMatching(norm_value, attribute_id) {

    var ret = new Array();

    for (var gsi = 0; gsi < generic.specifics.length; gsi++) {

        var specific = generic.specifics[gsi];

        if (generic.is_options_product) {
            for (var oi = 0; oi < generic.offers.length; oi++)  {
                var offer = generic.offers[oi];
                if (offer.available) {
                    ret.push(offer);
                }
            }
            return ret;
        }
        for (var aj = 0; aj < specific.attributes.length; aj++) {

            var attr = specific.attributes[aj];

            if ( (attr.norm_value == norm_value) && (attr.id == attribute_id )) {
                for (oi = 0; oi < specific.offers.length; oi++)  {
                    var offer2 = specific.offers[oi];
                    if (offer2.available) {
                        ret.push(offer2);
                    }
                }
            }
        }
        if (107 == attribute_id ) {
            var spi = getShop_from_name(norm_value);
            for (var oi3 = 0; oi3 < specific.offers.length; oi3++)  {
                var offer3 = specific.offers[oi3];
                if (offer3.available && offer3.shop_id == spi.id) {
                    ret.push(offer3);
                }
            }
        }
    }

    return ret;
}

function prepare_add_item_to_cart() {
    $("#add_item_to_cart_form").submit(function() {
        if (generic.ready) {
            generic.ready = false;
            $.post('/mycart', $("#add_item_to_cart_form").serialize(),
                function(data){
                    generic.ready = true;
                    if (data) {
                        cart_item = data.cart_item
                        generic.updateOffer(cart_item.offer_id, cart_item.id, cart_item.quantity, cart_item.options);
                        update_cart(cart_item.offer_id);
                    }
                })
        }
        return false;
    });
}


function getSelection() {

    var selection = new Array();
    var attribute_id;
    var selector;

    for (var si =0; si < generic.variant_attributes.length; si++) {
        attribute_id = si2ai(si);
        selector = $("#selector_" + attribute_id);
        selection[si] = [selector.children()[selector[0].selectedIndex].text, selector.val()];
    }
    return selection;
}

function displayAvailability(availability) {
    if (availability.length > 0) {
        $("#availability_text").html(availability);
        $("#availability_image").hide();
        $("#availability_text").show();
    } else {
        $("#availability_image").show();
        $("#availability_text").hide();
    }
}

function display_availability_image() {
    Effect.toggle('#availability_text','appear', {
        duration: 0.1
    });
    Effect.toggle('#availability_image','appear', {
        duration: 0.1
    });
}
var Generic;
var Specific;
var Offer;
var Attribute;
var VariantAttribute;
var Shop;
var Selection;

Generic = function(id, is_options_product) {

    this.selection_complete = false;
    this.is_options_product = eval(is_options_product)
    this.id = id;
    this.specifics = new Array();
    this.shops = new Array();
    this.selections = new Array();
    this.variant_attributes = new Array();
    this.matching_shops = new Array();
    this.offers = new Array();
    this.ready = true;

    this.addSpecific = function(specific) {
        this.specifics.push(specific);
    };
    this.addShop = function(shop) {
        this.shops.push(shop);
    };
    this.addVariantAttribute = function(variant_attribute) {
        this.variant_attributes.push(variant_attribute);
    };
    this.addOffer = function(offer) {
        this.offers.push(offer);
    };
    this.updateOffer = function(offer_id, cart_item_id, cart_item_quantity, cart_item_options) {
        for (var i=0; i < this.offers.length; i++) {
            if (this.offers[i].id == offer_id) {
                for (var ic=0; ic < this.offers[i].cart_items.length; ic++) {
                    var cart_item = this.offers[i].cart_items[ic];
                    var exists = false;
                    if (cart_item.id == cart_item_id) {
                        this.offers[i].cart_items[ic].quantity = cart_item_quantity;
                        exists = true;
                        break;
                    }
                }
                if (!exists) {
                    this.offers[i].addCartItem(new CartItem(cart_item_id, this.offers[i], cart_item_quantity, cart_item_options));
                }
            }
        }
        generic.redrawPriceInfo();
    };
    this.addMatchingShop = function(shop_id) {
        addToArray(this.matching_shops, shop_id);
    };
    this.clearMatchingShop = function() {
        this.matching_shops = new Array();
    };
    this.addSelection = function(selection) {
        this.selections.push(selection);
        selector = $('#selector_' + selection.id);
        var options = selector.children();
        for (var i = 0; i < options.length; i++) {
            if (options[i].value == selection.value) {
                selector.children()[i].selected = true;
                break;
            }
        }
    };
    this.clearSelection = function() {
        this.selections = new Array();
    };
    this.removeFromCart = function(offer_id, old_cart_item_id) {
        for (var i=0; i < generic.offers.length; i++) {
            if (generic.offers[i].id == offer_id) {
                for (var ic=0; ic < generic.offers[i].cart_items.length; ic++) {
                    var cart_item = generic.offers[i].cart_items[ic];
                    if (cart_item.id == old_cart_item_id) {
                        generic.offers[i].cart_items.array_value_delete(ic);
                        break;
                    }
                }
            }
        }
        generic.redrawPriceInfo();
    };
    this.selectionComplete = function() {
        return this.selection_complete;
    };
    this.redrawPriceInfo = function() {
        var selection = getSelection();
        var minimum_price_in_cents = null;
        generic.selection_complete = true;
        var all_matches = generic.offers;
        for (var si = 0; si < selection.length; si++) {
            var ai = si2ai(si);
            if (selection[si][1] == "") {
                generic.selection_complete = false;
                all_matches = intersectOffers(all_matches, generic.offers );
                continue;
            }

            var list_norm_value = selection[si][1];
            all_matches = intersectOffers(all_matches, getMatching(list_norm_value, ai));
        }
        var options_text = getOptionsText(selection);
        if ($("#options_selected").size() > 0) {
            $("#options_selected").html(options_text);
            $("#options_selected").show();
        }
        if (all_matches.length == 1 && generic.selection_complete) {
            //set price, etc
            var offer = all_matches[0];
            if (offer.discount > 0.0) {
                $("#price").html("<span class=\"mylugo_allowance_price\">Jetzt " + formatCurrency(offer.rebated_price_in_cents/100.0) + "</span><br />" + "<span class=\"mylugo_non_allowance_price\">statt <strike>" + formatCurrency(offer.price_in_cents/100.0) + "</strike></span>");
            } else {
                $("#price").html(formatCurrency(offer.price_in_cents/100.0));
            }
            $("#price_box").show();
            $("#explained_price").html(offer.explained_price);
            $("#availability_message").html(offer.extended_availability_message);
            $("#shipping_costs").html("+ " + offer.shipping_costs + " Versandkosten");
            $("#info-link").show();
            $("#availability_state").show();
            // if (offer.shipping_cost_fixed > -1 ) {
            //     $("#shipping_hint").html("Für dieses Produkt sind feste Versandkosten von "+formatCurrency(offer.shipping_cost_fixed/100.0)+" festgelegt.");
            // } else {
            $("#shipping_hint").html(offer.shipping_info);
            //}
            $("#action_hint").hide();
            $("#submit_cart_button").show();
            if($("#selection_header").size() > 0 && (options_text.length > 0)) {
                $("#selection_header").show();
            }
            var options = $.toJSON(getOptions(selection));
            var cart_item = offer.findCartItem(options);
            if (cart_item != null) {
                $("#with_cart_items")[0].style.display="block";
                $("#no_cart_items")[0].style.display="none";
                $("#price_box").show();
                $("#w_cart_item_quantity").val(cart_item.quantity);
                $("#w_cart_item_options").val(options);
                $("#w_cart_item_quantity").attr("original_value",cart_item.quantity);
                toggleButtonIfFieldChanged("#w_cart_item_quantity", "#update_cart_item");
                $("#update_cart_form").attr('onsubmit', '');
                $("#update_cart_form").unbind('submit');
                $("#update_cart_form").submit(function() {
                    if (generic.ready) {
                        generic.ready = false;
                        $.post('/mycart/' + cart_item.id, $("#update_cart_form").serialize(),
                            function(data) {
                                cart_item = data.cart_item
                                generic.ready = true;
                                generic.updateOffer(cart_item.offer_id, cart_item.id, cart_item.quantity);
                                update_cart(cart_item.offer_id);
                            }
                            )
                    }
                    return false;
                });
                $("#delete_from_cart_form").attr('onsubmit', '');
                $("#delete_from_cart_form").unbind('submit');
                $("#delete_from_cart_form").submit(function() {
                    if (generic.ready) {
                        generic.ready = false;
                        $.ajax({
                            url: '/mycart/' + cart_item.id,
                            type: 'DELETE',
                            data: $("#delete_from_cart_form").serialize(),
                            success: function(data) {
                                generic.ready = true;
                                offer_id = data[0];
                                cart_size = data[1];
                                old_cart_item_id = data[2];
                                update_cart(null);
                                if (typeof generic != 'undefined') generic.removeFromCart(offer_id, old_cart_item_id);
                            }
                        }
                        )
                    }
                    return false;
                });
            }
            else {
                if ($("#no_cart_items").size() > 0) {
                    $("#no_cart_items")[0].style.display="block";
                    $("#with_cart_items")[0].style.display="none";
                    $("#cart_item_offer_id").val(offer.id);
                    $("#cart_item_options").val($.toJSON(getOptions(selection)));
                    prepare_add_item_to_cart();
                }
            }
        } else if (all_matches.length == 0) {
            if ($("#no_cart_items").size() > 0) {
                $("#no_cart_items")[0].style.display="block";
                $("#cart_item_offer_id").val("invalid");
                $("#cart_item_options").val($.toJSON(getOptions(selection)));
                $("#price").html("");
                $("#price_box").hide()
                $("#availability_message").html("Dieser Artikel ist mit den ausgewählten Optionen leider nicht verfügbar.");
                $("#shipping_costs").html("");
                $("#action_hint").hide();
                $("#with_cart_items").hide();
                $("#submit_cart_button").hide();
                $("#selection_header").show();
            }
        } else {
            for (var oi1 = 0; oi1 < all_matches.length; oi1++) {
                var offer1 = all_matches[oi1];
                var int_price_in_cents = offer1.rebated_price_in_cents;
                if (int_price_in_cents < minimum_price_in_cents || minimum_price_in_cents == null) {
                    minimum_price_in_cents = int_price_in_cents;
                }
            }
            if ($("#no_cart_items").size() > 0) {
                $("#no_cart_items")[0].style.display="block";
                $("#cart_item_offer_id").val("invalid");
                $("#cart_item_options").val($.toJSON(getOptions(selection)));
                $("#with_cart_items")[0].style.display="none";
                $("#price_box").show();
                $("#price").html("ab " + formatCurrency(minimum_price_in_cents/100.0));
                $("#availability_message").html("");
                $("#shipping_costs").html("");
                $("#info-link").hide();
                $("#availability_state").hide();
                if (generic.variant_attributes.length == 1) {
                    $("#action_hint").html("<strong>Bitte wählen Sie oben den Händler für dieses Produkt.</strong>");
                } else {
                    $("#action_hint").html("<strong>Bitte Produkt-Option(en) auswählen.</strong>");
                }
                $("#action_hint").show();
                $("#submit_cart_button").hide();
                $("#selection_header").hide();
                prepare_add_item_to_cart();
            }
        }
    };
};

Specific = function(id) {
    this.id = eval(id);
    this.offers = new Array();
    this.attributes = new Array();

    this.addAttribute = function(attribute) {
        this.attributes.push(attribute);
    };
    this.addOffer = function(offer) {
        this.offers.push(offer);
        generic.addOffer(offer);
        offer.specific = this;
    };
};

Offer = function(id, shop_id, price_in_cents, explained_price, quantity, shipping_costs, shipping_cost_fixed, shipping_info, availability_state, availability_message, extended_availability_message, discount, discount_reason) {
    this.id = eval(id);
    this.shop_id = shop_id;
    this.specific = null;
    this.cart_items = new Array();
    this.price_in_cents = price_in_cents;
    this.explained_price = explained_price;
    this.quantity = quantity;
    this.discount = discount;
    this.discount_reason = discount_reason;
    this.shipping_costs = shipping_costs;
    this.shipping_cost_fixed = shipping_cost_fixed;
    this.shipping_info = shipping_info;
    this.avalability_state = availability_state;
    this.avalability_message = availability_message;
    this.extended_availability_message = extended_availability_message;
    this.rebated_price_in_cents = this.price_in_cents - this.price_in_cents*this.discount/100.0;
    this.available = function() {
        return (this.quantity > 0 || this.availability_state == "on_demand");
    };
    this.equalsOffer = function(offer) {
        return (this.id == offer.id);
    };
    this.findCartItem = function(options) {
        var l_options = options;
        if (l_options == "") l_options = "[]";
        var ret = null;
        for (var i=0; i < this.cart_items.length; i++) {
            if (this.cart_items[i].options == l_options) {
                ret = this.cart_items[i];
                break;
            }
        }
        return ret;
    };
    this.addCartItem = function(cart_item) {
        this.cart_items.push(cart_item);
    };
};

Selection = function(id, value) {
    this.id = id;
    this.value = value;
};

Attribute = function(id, values) {
    this.id = id;
    this.ext_value = values[0];
    this.norm_value = values[1];
    this.int_value = values[2];
};

VariantAttribute = function(id, names, values) {
    this.id = id;
    this.display_name = names[0];
    this.short_name = names[1];
    this.values = values;
};

Shop = function(id, name, shipping_cost_description) {
    this.id = id;
    this.name = name;
    this.attribute = new Attribute(107,[name,name,name]);
    this.shipping_cost_description = shipping_cost_description;
};

CartItem = function(id, offer, quantity, options) {
    this.id = id;
    this.offer = offer;
    this.quantity = quantity;
    this.options = options;
    if (this.options == "" || this.options == null) this.options = "[]";
};

jQuery(document).ready(function(){
    $.toJSON=function(o)

    {
        if(typeof(JSON)=='object'&&JSON.stringify)
            return JSON.stringify(o);
        var type=typeof(o);
        if(o===null)
            return"null";
        if(type=="undefined")
            return undefined;
        if(type=="number"||type=="boolean")
            return o+"";
        if(type=="string")
            return $.quoteString(o);
        if(type=='object')

        {
            if(typeof o.toJSON=="function")
                return $.toJSON(o.toJSON());
            if(o.constructor===Date)

            {
                var month=o.getUTCMonth()+1;
                if(month<10)month='0'+month;
                var day=o.getUTCDate();
                if(day<10)day='0'+day;
                var year=o.getUTCFullYear();
                var hours=o.getUTCHours();
                if(hours<10)hours='0'+hours;
                var minutes=o.getUTCMinutes();
                if(minutes<10)minutes='0'+minutes;
                var seconds=o.getUTCSeconds();
                if(seconds<10)seconds='0'+seconds;
                var milli=o.getUTCMilliseconds();
                if(milli<100)milli='0'+milli;
                if(milli<10)milli='0'+milli;
                return'"'+year+'-'+month+'-'+day+'T'+
                hours+':'+minutes+':'+seconds+'.'+milli+'Z"';
            }
            if(o.constructor===Array)
            {
                var ret=[];
                for(var i=0;i<o.length;i++)
                    ret.push($.toJSON(o[i])||"null");
                return"["+ret.join(",")+"]";
            }
            var pairs=[];
            for(var k in o){
                var name;
                var type=typeof k;
                if(type=="number")
                    name='"'+k+'"';
                else if(type=="string")
                    name=$.quoteString(k);else
                    continue;
                if(typeof o[k]=="function")
                    continue;
                var val=$.toJSON(o[k]);
                pairs.push(name+":"+val);
            }
            return"{"+pairs.join(", ")+"}";
        }
    };

    $.evalJSON=function(src)

    {
        if(typeof(JSON)=='object'&&JSON.parse)
            return JSON.parse(src);
        return eval("("+src+")");
    };

    $.secureEvalJSON=function(src)

    {
        if(typeof(JSON)=='object'&&JSON.parse)
            return JSON.parse(src);
        var filtered=src;
        filtered=filtered.replace(/\\["\\\/bfnrtu]/g,'@');
        filtered=filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']');
        filtered=filtered.replace(/(?:^|:|,)(?:\s*\[)+/g,'');
        if(/^[\],:{}\s]*$/.test(filtered))
            return eval("("+src+")");else
            throw new SyntaxError("Error parsing JSON, source is not valid.");
    };

    $.quoteString=function(string)

    {
        if(string.match(_escapeable))

        {
            return'"'+string.replace(_escapeable,function(a)

            {
                    var c=_meta[a];
                    if(typeof c==='string')return c;
                    c=a.charCodeAt();
                    return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);
                })+'"';
        }
        return'"'+string+'"';
    };

    var _escapeable=/["\\\x00-\x1f\x7f-\x9f]/g;
    var _meta={
        '\b':'\\b',
        '\t':'\\t',
        '\n':'\\n',
        '\f':'\\f',
        '\r':'\\r',
        '"':'\\"',
        '\\':'\\\\'
    };

});

function black_or_white(hexval) {
    mat = hexval.match(/([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i);
    if (mat == null) return "000000";
    r=parseInt(mat[1], 16);
    g=parseInt(mat[2], 16);
    b=parseInt(mat[3], 16);
    if (Math.max(r,Math.max(g,b)) < 128) {
        return "ffffff";
    } else {
        return "000000";
    }
}

