CustomHtmlTableParsers = Object();
CustomHtmlTableParsers.price = function() {
    var match = this.get('text').match(/[\d\.,]+/);
    return match ? match[0].toFloat() : null;
};
CustomHtmlTableParsers.img_alt_string = function() {
    var img = this.getElement('img');
    return img ? img.get('alt') : null;
};
CustomHtmlTableParsers.rating = function() {
    return this.get('sortval');
};
CustomHtmlTableParsers.bytes = function() {
    var multipliers = {'mb': 1, 'gb': 1000, 'tb': 1000000};
    var value = 0;
    var match = this.get('text').replace(/,/g, '').match(/(unlimited|([\d\,\.]+)\s*(mb|gb|tb))/i);
    if (match) {
        if (match[1].toLowerCase() == 'unlimited')
            value = 999999999999;
        else
            value = parseFloat(match[2]) * multipliers[match[3].toLowerCase()];
    }
    return value;
};

var FilterHandler = new Class({
    Implements: [Options],
    options: {
        max_show_count: 10,
        base_url: '',
        compare_base_url: ''
    },
    initialize: function(options) {
        this.setOptions(options);
        this.handle_updates = false;
        this.attach();
        var had_filter = this.load_filter_fragment();
        this.handle_updates = true;
        if (had_filter)
            this.update_filter();
    },
    attach: function() {
        this.search_form = $('search_form');
        this.search_progress = $('search_progress');
        this.results_count = $('results_count');
        this.hosts_wrapper = $('results');
        this.permalink = $('permalink');
        this.social_links = $$('.social_links a');
        if (!this.options.redirect) {
            this.search_form.addEvent('submit', function(e){
                new Event(e).stop();
                this.update_filter();
            }.bind(this));
        }
        $$('a.reset_button').each(function(elem){
            elem.addEvent('click', function(e){
                new Event(e).stop();
                this.reset();
            }.bind(this));
        }.bind(this));
        $$('#search_form select').each(function(elem){
            elem.addEvent('change', this.update_filter.bind(this));
        }.bind(this));
        $$('#search_form input[type=checkbox]').each(function(elem){
            elem.addEvent('click', function(){
                var wrapper = elem.getParent().getParent();
                if (wrapper && wrapper.hasClass('option')) {
                    var child_options = wrapper.getElement('.child_options');
                    if (child_options) {
                        var choose_link = wrapper.getElement('.choose');
                        choose_link.addEvent('click', function(e){
                            new Event(e).stop();
                            child_options.setStyle('display', child_options.getStyle('display') == 'none' ? 'block' : 'none');
                        });
                        if (elem.checked)
                            wrapper.addClass('chosen');
                        else {
                            wrapper.removeClass('chosen');
                            child_options.setStyle('display', 'none');
                        }
                    }
                }
                this.update_filter();
            }.bind(this));
        }.bind(this));
        $$('a.show_count_link').each(function(elem){
            elem.addEvent('click', function(e){
                new Event(e).stop();
                this.options.max_show_count = elem.get('text');
                this.update_results();
            }.bind(this));
        }.bind(this));
        this.bandwidth_slider = new Slider($('bandwidth_slider'), $('bandwidth_knob'), {
            range: [0, this.options.bandwidth_values.length-1],
            onChange: function(value){
                $('bandwidth_display').set('text', this.options.bandwidth_values[value]);
                $('bandwidth_input').set('value', this.options.bandwidth_values[value]);
            }.bind(this),
            onComplete: function(value){
                this.update_filter();
            }.bind(this)
        });
        this.bandwidth_slider.set(this.find_index(this.options.bandwidth_values, this.options.initial_bandwidth_value));
        this.disk_space_slider = new Slider($('disk_space_slider'), $('disk_space_knob'), {
            range: [0, this.options.disk_space_values.length-1],
            onChange: function(value){
                $('disk_space_display').set('text', this.options.disk_space_values[value]);
                $('disk_space_input').set('value', this.options.disk_space_values[value]);
            }.bind(this),
            onComplete: function(value){
                this.update_filter();
            }.bind(this)
        });
        this.disk_space_slider.set(this.find_index(this.options.disk_space_values, this.options.initial_disk_space_value));
        $$('.criterion.compact').each(function(elem){
            var toggle = new Element('a', {'class': 'toggle', 'href': '#'});
            toggle.addEvent('click', function(e){
                new Event(e).stop();
                elem.toggleClass('open');
            });
            elem.getElement('h3').adopt(toggle);
            if (elem.getElement('.suppressed')) {
                var more = new Element('a', {'class': 'more', 'href': '#', 'text': 'more...'});
                var less = new Element('a', {'class': 'less', 'href': '#', 'text': 'less'});
                var f = function(e){
                    new Event(e).stop();
                    elem.toggleClass('all');
                };
                more.addEvent('click', f);
                less.addEvent('click', f);
                elem.getElement('.options').adopt(more);
                elem.getElement('.options').adopt(less);
            }
        });
        this.table = new HtmlTable($('hosts_table'), {
            sortIndex: null,
            classNoSort: 'no_sort',
            classHeadSort: 'sorted_asc',
            classHeadSortRev: 'sorted_desc',
            classSortSpan: null,
            classCellSort: null,
            parsers: [CustomHtmlTableParsers.img_alt_string, null, CustomHtmlTableParsers.rating, CustomHtmlTableParsers.bytes, CustomHtmlTableParsers.bytes, CustomHtmlTableParsers.price],
            sortable: true,
            onSort: this.update_stripes
        });
        this.jump_form = $('jump_form');
        this.free_text = this.jump_form.getElement('#free_text');
        this.free_text.set('autocomplete', 'off');
        this.jump_form.addEvent('submit', function(e){
            new Event(e).stop();
            this.reset_controls();
            this.search_progress.setStyle('display', 'block');
            new Request.JSON({
                url: '/compare-filter/',
                method: 'get',
                onSuccess: function(data){
                    try {
                        this.data = data;
                        this.update_results();
                    }
                    finally {
                        setTimeout(function(){this.search_progress.setStyle('display', 'none')}.bind(this), 500);
                    }
                }.bind(this)
            }).send('free-text='+this.free_text.get('value'));
        }.bind(this));
        this.jump_form.getElement('select.filter').addEvent('change', function(e){
            var filter = e.target.get('value');
            if (filter) {
                this.reset_controls();
                this.handle_updates = false;
                var had_filter = this.load_filter_fragment(filter);
                this.handle_updates = true;
                if (had_filter)
                    this.update_filter();
            }
            else
                this.reset();
        }.bind(this));
        $$('a.filter').addEvent('click', function(e){
            new Event(e).stop();
            var hash_pos = e.target.href.indexOf('#');
            if (hash_pos != -1) {
                var filter = e.target.href.substr(hash_pos);
                if (filter) {
                    this.reset_controls();
                    this.handle_updates = false;
                    var had_filter = this.load_filter_fragment(filter);
                    this.handle_updates = true;
                    if (had_filter)
                        this.update_filter();
                }
            }
        }.bind(this));
        this.report_problem = $('report_problem');
        this.report_problem_form = this.report_problem.getElement('form');
        this.report_problem_permalink = this.report_problem_form.getElement('#report_permalink');
        $('report_link').addEvent('click', function(e){
            new Event(e).stop();
            this.report_problem.toggleClass('reporting');
            this.report_problem.removeClass('sent');
        }.bind(this));
        this.report_problem_form.addEvent('submit', function(e){
            new Event(e).stop();
            new Request({
                url: this.options.base_url + '/report-compare-problem/',
                method: this.report_problem_form.method,
                onSuccess: function() {
                    this.report_problem.removeClass('reporting');
                    this.report_problem.addClass('sent');
                }.bind(this)
            }).send(this.report_problem_form.toQueryString());
        }.bind(this));
        this.ask_expert = $('ask_expert');
        this.ask_expert_form = this.ask_expert.getElement('form');
        this.ask_expert_form.addEvent('submit', function(e){
            new Event(e).stop();
            if (!this.ask_expert_form.help_name.get('value') || !this.ask_expert_form.help_email.get('value'))
                this.ask_expert.addClass('invalid');
            else {
                new Request({
                    url: this.ask_expert_form.action,
                    url: this.options.base_url + '/ask-expert-mail/',
                    method: this.ask_expert_form.method,
                    onSuccess: function() {
                        this.ask_expert.removeClass('error');
                        this.ask_expert.addClass('sent');
                    }.bind(this)
                }).send(this.ask_expert_form.toQueryString());
            }
        }.bind(this));
        this.email_permalink = $('email_permalink');
        var last_updated = $('last_updated');
        var timestamp = new Date(1000 * last_updated.getElement('span.timestamp').get('text'));
        last_updated.getElement('span.datetime').set('text', timestamp.format('%d-%b-%Y %H:%M'));
        this.sort_by = $('sort_by');
        this.sort_by.selectedIndex = 0;
        this.sort_by.addEvent('change', function(e){
            var value = this.sort_by.get('value');
            this.table.sort(value[1], value[0] == '-');
        }.bind(this));
        this.update_floatboxes();
        if (this.options.reset_controls)
            this.reset_controls();
    },
    load_filter_fragment: function(fragment) {
        // Take a url fragment like #filter:scripting[]=php/control_panel[]=cpanel and set the form values
        var had_filter = false;
        if (typeof(fragment) == 'undefined')
            fragment = document.location.hash;
        if (fragment && fragment.match(/^#filter:/)) {
            var parts = fragment.substr(8).split('/');
            var map = {};
            parts.each(function(part){
                var kv = decodeURIComponent(part).replace(/\+/g, ' ').split('=', 2);
                if (kv.length == 2)
                    map[kv[0]] = kv[1];
            }.bind(this));
            this.search_form.getElements('input[type=checkbox]').each(function(elem){
                if (map[elem.name] == elem.value) {
                    elem.checked = true;
                    this.ensure_option_visible(elem);
                }
            }.bind(this));
            this.search_form.getElements('select').each(function(elem){
                var value = map[elem.name];
                if (map[elem.name]) {
                    var options = elem.getElements('option');
                    for (var index = 0; index < options.length; index++) {
                        if (options[index].value == value) {
                            elem.selectedIndex = index;
                            break;
                        }
                    }
                }
            });
            if (map['bandwidth'])
                this.bandwidth_slider.set(this.find_index(this.options.bandwidth_values, map['bandwidth']));
            if (map['disk-space'])
                this.disk_space_slider.set(this.find_index(this.options.disk_space_values, map['disk-space']));
            if (!Browser.Engine.trident)
                document.location.hash = '#';
            had_filter = true;
        }
        return had_filter;
    },
    ensure_option_visible: function(checkbox) {
        var criterion = checkbox.getParent().getParent();
        while (criterion && !criterion.hasClass('criterion'))
            criterion = criterion.getParent();
        if (criterion) {
            criterion.addClass('open');
            checkbox.getParent().removeClass('suppressed');
        }
    },
    update_filter: function() {
        if (!this.handle_updates)
            return;
        if (this.options.redirect) {
            this.search_form.submit();
            return;
        }
        this.search_progress.setStyle('display', 'block');
        var removals = [];
        this.search_form.getElements('input[type=checkbox]').each(function(elem){
            if (elem.checked) {
                // Uncheck if hidden.
                var size = elem.getComputedSize();
                if (size.height <= 0)
                    elem.checked = false;
                // Note parent value if child is checked.
                var wrapper = elem.getParent().getParent();
                if (wrapper && wrapper.hasClass('option')) {
                    var children = wrapper.getElement('div.child_options');
                    if (children && wrapper.hasClass('chosen')) {
                        var child_checked = false;
                        children.getElements('input[type=checkbox').each(function(child_checkbox){
                            if (child_checkbox.checked)
                                child_checked = true;
                        });
                        if (child_checked)
                            removals.push(elem.get('name')+'='+elem.get('value'));
                    }
                }
            }
        });
        // Override data to remove parent value if child checked.
        var data = this.search_form.toQueryString();
        removals.each(function(item){
            data = data.replace(item, '');
        });
        data = data.replace(/&{2,}/, '&');
        new Request.JSON({
            url: '/compare-filter/',
            method: 'get',
            onSuccess: function(data){
                try {
                    this.data = data;
                    this.update_results();
                }
                finally {
                    setTimeout(function(){this.search_progress.setStyle('display', 'none')}.bind(this), 500);
                }
            }.bind(this)
        }).send(data);
    },
    update_results: function() {
        $('hosts_tbody').set('html', this.data.rows);
        var shown_count = 0;
        $$('#hosts_tbody tr').each(function(row){
            if (this.options.max_show_count == 'All' || shown_count < this.options.max_show_count) {
                row.removeClass('hidden');
                shown_count++;
            }
            else
                row.addClass('hidden');
        }.bind(this));
        if (shown_count) {
            this.hosts_wrapper.removeClass('no_results');
            if (this.data.row_count <= shown_count)
                this.results_count.set('html', 'Matched '+this.data.row_count+' hosts, showing all '+shown_count);
            else
                this.results_count.set('html', 'Matched '+this.data.row_count+' hosts, showing '+shown_count);
        }
        else {
            this.hosts_wrapper.addClass('no_results');
            this.results_count.set('html', '');
        }
        $('filter_title').set('text', this.data.headline ? this.data.headline : '');
        $('filter_editorial').set('text', this.data.editorial ? this.data.editorial : '');
        this.hosts_wrapper.removeClass('initial');
        this.hosts_wrapper.addClass('filtered');
        this.update_permalinks();
        this.update_floatboxes();
        this.table.reSort();
        if (this.options.content_changed_callback)
            this.options.content_changed_callback();
    },
    update_stripes: function() {
        var alt = false;
        $$('#hosts_table tbody tr').each(function(row){
            if (!row.hasClass('hidden')) {
                if (alt)
                    row.addClass('color');
                else
                    row.removeClass('color');
                alt = !alt;
            }
        });
    },
    update_permalinks: function(new_url) {
        var old_url = this.permalink.href;
        if (!new_url)
            new_url = this.data.permalink; 
        this.permalink.href = new_url;
        this.social_links.each(function(elem){
            elem.href = elem.href.replace(old_url, new_url);
        }.bind(this));
        this.report_problem_permalink.set('value', new_url);
        this.email_permalink.set('value', new_url);
    },
    update_floatboxes: function() {
        $$('#hosts_table td.floatbox_container').each(function(container){
            var triggers = container.getElements('.floatbox_trigger');
            for (var index = 0;index<triggers.length;index++) {
                trigger = triggers[index];
                if (trigger.get('href') == '#')
                    trigger.addEvent('click', function(e){new Event(e).stop();});
                var box = container.getElement('.floatbox');
                if (box) {
                    trigger.addEvent('mouseenter', function(e){container.addClass('hover');});
                    trigger.addEvent('mouseleave', function(e){container.removeClass('hover');});
                    box.addEvent('mouseenter', function(e){container.addClass('hover');});
                    box.addEvent('mouseleave', function(e){container.removeClass('hover');});
                }
            }
        });
    },
    reset: function() {
        if (this.options.redirect) {
            document.location.href = this.options.compare_base_url + '/';
            return;
        }
        this.search_progress.setStyle('display', 'block');
        this.reset_controls();
        new Request.JSON({
            url: '/compare-filter-reset/',
            method: 'get',
            onSuccess: function(data){
                try {
                    this.data = data;
                    this.update_results();
                }
                finally {
                    setTimeout(function(){this.search_progress.setStyle('display', 'none')}.bind(this), 500);
                }
            }.bind(this)
        }).send();
        this.hosts_wrapper.removeClass('filtered');
        this.hosts_wrapper.addClass('initial');
        window.scrollTo(0,0);
    },
    reset_controls: function() {
        var old_handle_updates = this.handle_updates;
        this.handle_updates = false;
        try {
            this.search_form.getElements('input[type=checkbox]').each(function(elem){
                elem.checked = false;
            });
            this.bandwidth_slider.set(0);
            this.disk_space_slider.set(0);
            $('price-per-month').set('value', '');
            $$('.compact').each(function(elem){
                if (elem.hasClass('initial_open'))
                    elem.addClass('open');
                else
                    elem.removeClass('open');
                elem.removeClass('all');
            });
        }
        finally {
            this.handle_updates = old_handle_updates;
        }
    },
    find_index: function(values, target_value) {
        for (var index = 0;index<values.length;index++) {
            if (values[index] == target_value || values[index].toLowerCase() == target_value)
                return index;
        }
        return -1;
    }
});

