﻿// ajax callback / page load logic

CategorisedProductListing_OnLoad = function(sender, args) {
    var hasErrors = checkForException();

    // jQuery History Enabled links
    $('[jQHE]').bind('click', function(event) {
        event.preventDefault();
        customHistoryManager.onClick(event);
        if (typeof scrollToTop == 'function') scrollToTop();
        return false;
    });

    // jQuery History Enabled items per page / order by
    $('[jQHHIPP],[jQHHOB]').bind('change', function(event) {
        event.preventDefault();
        customHistoryManager.onClick(event);
        if (typeof scrollToTop == 'function') scrollToTop();
        return false;
    });
    
    $('[data-click-more-info=1]').click(function() {
        var offset = $('#moreinfo').offset();
        window.scrollTo(offset.left, offset.top - 300);
    });

    // UI

    // product name vertical centering
    try {
        var top = ($('ul.elementProductMain .title').height() - $('ul.elementProductMain .title a').height()) / 2;
        $('ul.elementProductMain .title a').css('margin-top', top);
    } catch (e) {

    }
};

CategorisedProductListing_OnResponseEnd = function(sender, args) {
    CategorisedProductListing_Initialise();

    setTimeout(function() {
        CategorisedProductListing_OnLoad(sender, args);
    }, 250);
};

CategorisedProductListing_Initialise = function() {
    if (typeof LoadSlider == 'function') LoadSlider();
    if (typeof initialiseDefaultButtons == 'function') initialiseDefaultButtons();
    if (typeof initialiseFonts == 'function') initialiseFonts();
    if (typeof initialiseCategoryToggle == 'function') initialiseCategoryToggle();
    if (typeof initScroll == 'function') initScroll();
};

initialiseCategoryToggle = function() {
    try {

        // Hide toggle containers except for catergories
        
        $(".toggle_container")
            .hide();

        // Expand / collapse 

        $(".heading h4.toggle").click(function() {
            $(this).toggleClass("toggle-show").parent().next(".toggle_container").slideToggle("fast");
            return false;
        });
    } catch (e) {
        trace(e);
    }
}

initialiseCategoryToggle();


var customHistoryManager;
$(function() {
    CategorisedProductListing_Initialise();

    /* jQuery History Plugin Integration */
    customHistoryManager = new CategorisedProductListing_Hash();
    SetAjaxHistoryLoaded(false);
    
    $.history.init(ajaxLoad);
    CategorisedProductListing_OnLoad();
});

///
/// jQuery History Plugin Integration
///
/// This hash based history integration is specific to this page, controls and structure
/// DO NO MODIFY
///
/// TODO:
///     - Re-write all regular expressions to have shortest regular expression possible; and
///     - Write some tests
///     - Please optimise this code
///

/* constructor */
var CategorisedProductListing_Hash = function(inputId, pageInputId, ippInputId, orderInputId) {
    this._inputId = ((typeof inputId != 'undefined' && inputId != null) ? inputId : 'hfSerialisedFilters');
    this._pager = ((typeof pageInputId != 'undefined' && pageInputId != null) ? pageInputId : 'hfCurrentPage');
    this._ipp = ((typeof ippInputId != 'undefined' && ippInputId != null) ? ippInputId : 'hfItemsPerPage');
    this._order = ((typeof orderInputId != 'undefined' && orderInputId != null) ? orderInputId : 'hfOrderBy');

    this.Action = {
        add: 0,
        remove: 1,
        clear_type: 2,
        clear: 3
    };
    this.Type = {
        filter: 0,
        pager: 1,
        items_per_page: 2,
        order: 3
    };

    /* validate object */
    this.validate = function() {
        if ($('input[id=' + this._inputId + ']').length <= 0) throw new 'Required input control not found: hfSerialisedFilters';
    };

    this.onClick = function(event) {
        try {
            // click event handler for jQuery History Enabled content
            // since checkboxes and radio buttons are encapsulated inside <span> tags
            // (and these span tags contain all the relevant attributes), we must find the tag
            // which contains the relevant attributes;

                var target = event.target;
                var tag = target.tagName;


                var type = null;
                var jQHistoryElement = null;

                // check if its paging or items per page control
            var $target = $(target);
            if (/select/i.test(tag) || !!$target.attr('jQHHP') || !!$target.attr('jQHHOB') || !!$target.attr('jQHHIPP')) {
                if (typeof $target.attr('jQHHIPP') != 'undefined') {
                        // items per page
                        type = this.Type.items_per_page;
                        jQHistoryElement = target;
                } else if (typeof $target.attr('jQHHP') != 'undefined') {
                        // paging
                        type = this.Type.pager;
                    jQHistoryElement = target;
                } else if (typeof $target.attr('jQHHOB') != 'undefined') {
                    // order by
                    type = this.Type.order;
                        jQHistoryElement = target;
                    } else {
                        throw new 'Unknown tag found';
                    }
                } else {
                    type = this.Type.filter;
                    if (/span/i.test(tag) || /a/i.test(tag)) {
                        jQHistoryElement = target;
                    } else if (/input/i.test(tag) || /label/i.test(tag)) {
                    var wrapper = $target.parent('span')[0];
                        jQHistoryElement = wrapper;
                    } else {
                        throw new 'Unknown tag found';
                    }
                }

                if (jQHistoryElement == null) {
                    throw new 'Relevant jQuery History Element could not be found. (target: {0})'.format(target);
                }

                if (type == null) {
                    throw new 'Unknown jQuery History Element type. (target: {0}'.format(target);
                }


                // check what action to perform
                var action = null;
                if (type == this.Type.filter) {
                    // filter controls
                    action = this.Action.add;
                    if (typeof $(jQHistoryElement).attr('jQHC') != 'undefined') {
                        action = this.Action.clear;
                    } else if (typeof $(jQHistoryElement).attr('jQHCT') != 'undefined') {
                        action = this.Action.clear_type;
                    } else if (typeof $(jQHistoryElement).attr('jQHR') != 'undefined') {
                        action = this.Action.remove;
                    }
                }

                // perform action on hash
                var hash = '';

            var $jQHistoryElement = $(jQHistoryElement);
                if (type == this.Type.filter) {
                    if (action == this.Action.add || action == this.Action.remove) {
                    hash = $jQHistoryElement.attr('jQHHV');
                        if (action == this.Action.remove) this.removeParent(hash);
                        else this.add(hash);
                    } else if (action == this.Action.clear_type) {
                    var typeId = $jQHistoryElement.attr('jQHCT');
                        this.removeType(typeId);
                    } else if (action == this.Action.clear) {
                        this.setFilter('');
                    } else {
                        throw new 'Unable to perform unknown action: {0}'.format(action);
                    }
                } else if (type == this.Type.pager) {
                var page = $jQHistoryElement.attr('jQHHP'); 
                    this.changePage(page);
            } else if (type == this.Type.order) {
                var order = $jQHistoryElement.children(':selected').val(); 
                this.changeOrderBy(order);
                } else if (type == this.Type.items_per_page) {
                var ipp = $jQHistoryElement.children(':selected').val(); 
                    this.changeItemsPerPage(ipp);
                } else {
                    throw new 'Unknown type: {0}'.format(type);
                }

                //don't scroll to top when a category (i.e. furniture type) is clicked
                if ((/-t71-c/.test(hash))) { }
                else {
                    scroll(0, 0);
                }

                // load page based on current hash
                $.history.load(this.getHash());
        } catch (e) {
            trace(e);
        }
    };

    /* get hash value */
    this.getHash = function() {
        try {
            this.validate();
            var hash = 'p={0}&ipp={1}&f={2}&o={3}'.format(this.current(this.Type.pager), this.current(this.Type.items_per_page), this.current(this.Type.filter), this.current(this.Type.order));
            return hash;
        } catch (e) {
            trace(e);
        }
    }

    /* change the page */
    this.changePage = function(page) {
        try {
            this.validate();
            $('input[id=' + this._pager + ']')[0].value = page;
        } catch (e) {
            trace(e);
        }
    };

    /* change items per page */
    this.changeItemsPerPage = function(ipp) {
        try {
            this.validate();
            $('input[id=' + this._ipp + ']')[0].value = ipp;
            this.changePage(1);
        } catch (e) {
            trace(e);
        }
    };

    this.changeOrderBy = function(order) {
        try {
            this.validate();
            $('input[id=' + this._order + ']')[0].value = order;
            this.changePage(1);
        } catch (e) {
            trace(e);
        }
    };
    /* returns current hash value */
    this.current = function(type) {
        try {
            this.validate();

            if (type == this.Type.filter) {
                return $('input[id=' + this._inputId + ']')[0].value;
            } else if (type == this.Type.items_per_page) {
                return $('input[id=' + this._ipp + ']')[0].value;
            } else if (type == this.Type.pager) {
                return $('input[id=' + this._pager + ']')[0].value;
            } else if (type == this.Type.order) {
                return $('input[id=' + this._order + ']')[0].value;
            } else {
                throw new 'Invalid type: {0}'.format(type);
            }
        } catch (e) {
            trace(e);
        }

        return '';
    };

    /* sets the current hash value */
    this.setFilter = function(hash) {
        try {
            this.validate();
            $('input[id=' + this._inputId + ']')[0].value = hash;
            this.changePage(1);
        } catch (e) {
            trace(e);
        }
    };

    /* adds given hash value to the current hash value */
    this.add = function(hash) {
        try {
            this.validate();
            // need to filter out certain types of hash values (i.e., prices) and remove all previous
            // hash values of the same type before adding a new, and updated, hash value
            // FIXME: only remove this type if the hash being added is of this type
            if (/-t1003-c/.test(hash)) {
                this.removeType(1003);
            }
            if (/-t22-c/.test(hash)) {
                this.removeType(22);
                if (/-t16701-c/.test(this.current(this.Type.filter)))
                    this.removeType(22);
                if (/-t16702-c/.test(this.current(this.Type.filter)))
                    this.removeType(22);
                if (/-t16715-c/.test(this.current(this.Type.filter)))
                    this.removeType(22);  
            }
            if (/-t86-c/.test(hash)) {
                this.removeType(71);
                this.removeType(86);
                this.removeType(22); //designer
                this.removeType(13); //colour
                this.removeType(77); //
                this.removeType(77); //material
                this.removeType(1003); //price
                this.removeParent(hash);

            }
            if (/-t71-c/.test(hash) || /-pv71-c/.test(hash)) {
                this.removeSubType(71); //want to keep the parent category in hash, but remove sub types, so categories 'stick' on left.
                this.removeType(86);
                this.removeType(22);
                this.removeType(13); //colour
                this.removeType(77); //material
                this.removeType(1003); //price
                if (/-t1002-c/.test(this.current(this.Type.filter)))
                    this.removeType(71);
                if (/-t16701-c/.test(this.current(this.Type.filter)))
                    this.removeType(71);
                if (/-t16702-c/.test(this.current(this.Type.filter)))
                    this.removeType(71);
                if (/-t16715-c/.test(this.current(this.Type.filter)))
                    this.removeType(71);   
            }                    
            if(!this.contains(hash))
                $('input[id=' + this._inputId + ']')[0].value += hash;

            this.changePage(1);
        } catch (e) {
            trace(e);
        } finally {
            return this.current(this.Type.filter);
        }
    };

    /* returns true if given hash value is already in the current value */
    this.contains = function(hash) {
        var currentValue = this.current(this.Type.filter);
        return (currentValue.indexOf(hash) > -1);
    };

    /* remove given hash value from the current hash value */
    this.remove = function(hash) {
        try {
            if (hash.search(/-c([^_]+)_/) > -1) { // since count is always different, we disregard count section
                hash = hash.substring(0, hash.search(/-c([^_]+)_/));
                var regexString = hash + '-c(\\d+)_';
                regexString = regexString.replace('|', '\\|');
                var regex = new RegExp(regexString);
                var currentValue = this.current(this.Type.filter);
                currentValue = currentValue.replace(regex, '');
                this.setFilter(currentValue);
                this.changePage(1);
            }
        } catch (e) {
            trace(e);
        } finally {
            return this.current(this.Type.filter);
        }
    };

    /* remove the given hash and all other hash values that are regarded as its parents */
    this.removeParent = function(hash) {
        try {
            // 1. extract parent value from the given hash
            // 2. find the hash value which has its value set to extract parent value
            // 3. remove the given hash value
            // 4. run removeParent on the hash value found in number 2
            this.validate();

            // 1. find the parent value from given hash
            var parentValue = null;
            var _parentRegex = '_v([^-]+)-pv';
            var parentRegex = new RegExp(_parentRegex, "i");
            var parentResult = parentRegex.exec(hash);
            if (typeof parentResult != 'undefined' && parentResult != null) parentValue = parentResult[parentResult.length - 1];
            if (parentValue == null) throw new 'Parent value could not be extract from the given hash value: {0}'.format(hash);

            // we need current value from here
            var currentValue = this.current(this.Type.filter);

            // 2. find parent hash
            var parentHash = null;
            var _parentHashRegex = '_v[^-]+-pv{0}-n[^_]+_'.format(parentValue); // regex to extract parent value
            var parentHashRegex = new RegExp(_parentHashRegex, 'i');
            var parentHashResult = parentHashRegex.exec(currentValue);
            if (typeof parentHashResult != 'undefined' && parentHashResult != null) parentHash = parentHashResult[parentHashResult.length - 1];

            // 3. remove the given hash value
            this.remove(hash);

            // 4. if parentHash is not null, run removeParent on it
            if (parentHash != null) this.removeParent(parentHash);
        } catch (e) {
            trace(e);
        }
    };

    /* remove given type */
    this.removeType = function(typeId) {
        try {
            var _typeRegex = '_[^_]+-t{0}-[^_]+_'.format(typeId);
            var typeRegex = new RegExp(_typeRegex);
            var currentValue = this.current(this.Type.filter);
            currentValue = currentValue.replace(typeRegex, '');
            this.setFilter(currentValue);
        } catch (e) {
            trace(e);
        } finally {
            return this.current(this.Type.filter);
        }
    };

    this.removeSubType = function(typeId) {
        try {
            var _typeRegex = '_[^_]+-pv(?!{0})[^_]+-t{0}-[^_]+_'.format(typeId);
            var typeRegex = new RegExp(_typeRegex);
            var currentValue = this.current(this.Type.filter);
            currentValue = currentValue.replace(typeRegex, '');
            this.setFilter(currentValue);
        } catch (e) {
            trace(e);
        } finally {
            return this.current(this.Type.filter);
        }
    };

    /* extract names of the current hash values */
    this.title = function() {
        var title = '';
        try {
            this.validate();
            var currentValue = this.current(this.Type.filter);
            // we're only interested in the captured group <name>
            // this will filter out names like: '15 - 20' because of the [^_] match if you wish to include them
            // then replace the regular expression with: '-n(?<name> .+?)-t'. this is a non-greedy way of grabbing names
            var _nameRegex = '-n(?<name> [^-]+)-t';
            var xnameRegex = new XRegExp(_nameRegex, 'ix');

            // see doc: http://xregexp.com/api/
            xnameRegex.forEachExec(currentValue, function(match) {
                title += '{0}{1}'.format((title == '' ? '' : ' - '), (match[match.length - 1]));
            });
        } catch (e) {
            trace(e);
        } finally {
            return title;
        }
    };

    /* extract the last filter */
    this.lastFilterName = function() {
        var title = '';
        try {
            this.validate();
            var currentValue = this.current(this.Type.filter);
            // we're only interested in the captured group <name>
            // this will filter out names like: '15 - 20' because of the [^_] match if you wish to include them
            // then replace the regular expression with: '-n(?<name> .+?)-t'. this is a non-greedy way of grabbing names
            var _nameRegex = '-n(?<name> [^-]+)-t2-';
            var xnameRegex = new XRegExp(_nameRegex, 'ix');

            // see doc: http://xregexp.com/api/
            xnameRegex.forEachExec(currentValue, function(match) {
                title = match[match.length - 1];
            });
        } catch (e) {
            trace(e);
        } finally {
            return title;
        }
    };

    this.validate();
};

var AJAX_HISTORY_KEY = 'IsAjaxHistoryLoaded_Key';
IsAjaxHistoryLoaded = function() {
    return window[AJAX_HISTORY_KEY] === true;
};
SetAjaxHistoryLoaded = function(value) {
    window[AJAX_HISTORY_KEY] = !!value;
};

/* ajax load */
ajaxLoad = function(hash) {
    // $.history will run this callback function load, which is what we want to avoid
    if (!IsAjaxHistoryLoaded() && hash === '') {
        SetAjaxHistoryLoaded(true);
        return;
    }

    try {
        SetAjaxHistoryLoaded(true);
        if (typeof ram === typeof undefined) {
            throw 'Rad Ajax Manager could not be found on this page';
        }

        var ajaxManager = ram;
        ajaxManager.AjaxRequest(hash);
    } catch (e) {
        trace(e);
    }
};
