function Search() {

    this.searchUrl = "/WebSearch";
    this.searchResultsPerPage = 10;
    this.groupSimilarResults = false;
    this.currResultsPage = 1;
    this.queryString = '';
    this.filter = '';
    this.sortBy = 'time';
    this.results = null;
    this.maxPage = 1;
    this.lastPage = -1;
    this.tags = new Array();
    this.editTagId = -1;
    this.getNewResultsCountInterval = 5000;
    this.newResultsCount = 0;
    this.lastNewResultsCount = -1;

    this.showPageNumbers = function() {
        var pg = 1;
        var l = this.currResultsPage - 10;
        if (l < 1)
            l = 1;
        var r = l + 20;
        if (r > this.maxPage)
            r = this.maxPage;
        l = r - 20;
        if (l < 1)
            l = 1;
        var pages = $("#search_pages_links td.inner");
        for (var i = 0; i < pages.length; i++)
            pages.eq(i).showHide((i+1) >= l && (i+1) <= r);
        $("#search_prev span").addRemoveClass(this.currResultsPage <= 1, 'gray');
        $("#search_next span").addRemoveClass(this.currResultsPage >= this.maxPage, 'gray');
    }

    this.encodeTagsInUrl = function() {
        var s = '';
        for (var i in this.tags) {
            var tag = this.tags[i];
            if (s != '')
                s += ',';
            s += escape(tag.show + "|" + tag.code);
        }
        return s;
    }

    this.makeSearchUrl = function(pg, sortBy, newQuery) {
        if (!sortBy)
            sortBy = this.sortBy;
        if (newQuery)
            return '?search' +
                '&query=' + escape(this.queryString) +
                '&sortby=' + sortBy;
        else
            return '?search' +
                '&page=' + pg +
                '&q=' + escape(this.queryString) +
                '&sortby=' + sortBy +
                '&tags=' + this.encodeTagsInUrl() +
                '&ctx=' + this.searchId;
    }

    this.createNewPages = function() {
        var res = $('#search_results');
        var toPage = this.currResultsPage + 9;
        if (toPage > this.maxPage)
            toPage = this.maxPage;
        for (var pg = 1; pg <= toPage; pg++) {
            if ($('#search_pages_links_' + pg).length > 0)
                continue;
            $('#search_pages_links td.next').before(
                '<td id="search_pages_links_' + pg + '" class="inner' + (pg == this.currResultsPage ? ' on' : '') + '">' +
                    '<a href="javascript:;" onclick="ShowModal(\'#download\', \'#modal_next_page\')"><span>' + pg + '</span></a>' +
                '</td>');
            res.append('<div id="search_results_page' + pg + '"></div>');
        }
        this.showPageNumbers();
    }

    this.renderRowContent = function(row) {
        var title = row.showTitle;
        var tags = '';

        var allTags = this.tags.concat(row.tags);
        for (var i in allTags) {
        	var tagTitle = '';
        	if(allTags[i].code.endsWith('11'))
                    tagTitle = 'Show only items at site \'' + allTags[i].show + '\'';
        	else if(allTags[i].code.endsWith('22'))
                    tagTitle = 'Show only items in category \'' + allTags[i].show + '\'';
        	else
                    tagTitle = 'Show only items with tag \'' + allTags[i].show + '\'';

            tags += '<a href="javascript:search.addTag(\''
                + escape(allTags[i].show) + '\', \''
                + escape(allTags[i].code) + '\')" '
                + 'title="' + tagTitle
                + '">' + allTags[i].show + '</a>&nbsp;';
        }

        if (!row.showUrl)
            row.showUrl = row.url;

        var subject = 'Re: ' + row.title;
        var body = escape('Here is something I found via Wowd (www.wowd.com):\n\n' + row.url);
        var content =
            '<table width="100%" cellpadding="0" cellspacing="0"><tr>' +
            '<td align="left">' +
                '<div class="title"><a href="' + row.url + '" target="_blank">' + title + '</a></div>' +
                '<div class="snippet">' + row.abs + '</div>' +
                '<div>' +
                    '<span class="timestamp" title="Last viewed: ' + row.lastViewed + ', Last indexed: ' + row.timestamp + '">' + row.lastViewed + '</span>' +
                    '&nbsp;&nbsp;&nbsp;' +
                    '<span class="actions">' +
                        '<a href="mailto:?subject=' + subject + '&body=' + body + '"><img src="gfx/email.gif" title="Send to a friend" alt="Send to a friend" height="16" width="16"></a>' +
                        '<a href="javascript:;" onclick="ShowModal(\'#download\', \'#modal_thumbs_down\')"><img src="gfx/twitter-action.gif" title="Share this via Twitter" alt="Share this via Twitter" width="16" height="16" /></a>' +
                        '<a href="http://www.facebook.com/sharer.php?u=' + escape(row.url) + '&t=' + escape(row.title) + '" target="_blank"><img src="gfx/facebook-action.gif" title="Share this via Facebook" alt="Share this via Facebook" width="16" height="16" /></a>' +
                        '<a href="javascript:;" onclick="ShowModal(\'#download\', \'#modal_thumbs_down\')"><img src="gfx/thumb_down.gif" title="Report as Inappropriate" alt="Report as Inappropriate" height="16" width="16"></a>' +
                        //'<a href="javascript:;" onclick="ShowModal(\'#download\', \'#modal_add_tag\')"><img src="gfx/add-tag.gif" title="Add a tag to this page" alt="Add tag"></a>' +
                    '</span>' +
                    '&nbsp;&nbsp;&nbsp;' +
                    '<span class="tags">' + tags + '</span>' +
                '</div>' +
            '</td>' +
            '</tr></table>';

        return content;
    }

    this.updateRow = function(row) {
        var name = "#sr" + row.ord + (row.subOrd > 0 ? "_sub" + row.subOrd : "");
        $(name).html(this.renderRowContent(row));
        $(name + ' .actions img')
            .css('opacity', 0.5)
            .mouseover(function() {
               $(this).css('opacity', 1.0);
            })
            .mouseout(function() {
               $(this).css('opacity', 0.5);
            });
    }

    this.renderRow = function(container, row) {
        var name = "sr" + row.ord + (row.subOrd > 0 ? "_sub" + row.subOrd : "");
        container.append(
            '<div id="' + name + '" class="result_row">' +
                this.renderRowContent(row) +
            '</div>'
        );
        $('#' + name + ' .actions img')
            .css('opacity', 0.5)
            .mouseover(function() {
               $(this).css('opacity', 1.0);
            })
            .mouseout(function() {
               $(this).css('opacity', 0.5);
            });
    }

    this.renderRows = function(pageId, rows) {
        var id = (pageId - 1) * this.searchResultsPerPage;
        $('#search_cnt_to').html(id + rows.length);
        var page = $('#search_results_page' + pageId);

        for (var i = 0; i < rows.length; i++) {
            rows[i].ord = ++id;

            if (this.results[id-1] != null) {
                if (this.results[id-1].hasSimilarResults != rows[i].hasSimilarResults) {
                    this.results[id-1].hasSimilarResults = rows[i].hasSimilarResults;
                    this.updateRow(this.results[id-1]);
                }
                continue;
            }

            if (i == 0)
                page.html('');

            this.renderRow(page, rows[i]);

            if (i+1 == this.searchResultsPerPage)
                page.append('<div id="finished_page' + pageId + '" style="display:none;"></div>');

            while (this.results.length < id)
                this.results.push(null);
            this.results[id-1] = rows[i];

            if (this.gfxEffects)
                $('#sr' + id).show("fast");
            else
                $('#sr' + id).show();
        }
    }

    this.updateNewResultsCount = function(data) {
        if (data.infoNewResults)
            $("#search_cnt2").text(data.infoNewResults).show();
        if (data.count < 0)
            return;
        if (data.count == this.lastNewResultsCount)
            return;
        this.lastNewResultsCount = data.count;
        var s = data.count <= 100 ? ('<strong>' + data.count + ' new</strong> since your last search') : 'More than 100 new since your last search';
        $("#search_info_new_results span").fadeOut(function() {
            if (data.count > 0)
                $(this).html('<a href="javascript:;" onclick="ShowModal(\'#download\', \'#modal_new_results\')">' + s + '</a>').fadeIn()
            else
                $(this).html(s).fadeIn()
        });
    }

    this.getNewResultsCount = function() {
        var n = Math.random();
        if (n > 0.7) this.newResultsCount++;
        if (n > 0.8) this.newResultsCount++;
        if (n > 0.9) this.newResultsCount++;
        if (n > 0.7) this.updateNewResultsCount({ count: this.newResultsCount });
    }

    this.showResults = function(data) {
        var first = this.results.length == 0;
        this.renderRows(data.page, data.results);
        if (first) {
            $('#search_cnt').show();
            $('#search_results').show();
            $('#search_pages_links').show();
            $('.sortbar').show();

            if (this.sortBy == 'time')
                this.tidGetNewResultsCount = setInterval( "search.getNewResultsCount()", this.getNewResultsCountInterval);
        }
    }

    this.showSimilarResults = function(idx) {
        var row = this.results[idx-1];
        if (row.subResults && row.subResults.length > 0) {
            for (var i = 0; i < row.subResults.length; i++)
                $('#sr' + idx + '_sub' + (i+1)).show();
            $("#sr" + idx + " cite.similar").html('<a href="javascript:search.hideSimilarResults(' + idx + ')">Hide similar results »</a>');
            return;
        }

        $.getJSONExt(this.searchURL, {ctx : this.searchId, idx: idx},
            function(data) {
                if (!data.idx || !data.results)
                    return;
                search.results[idx-1].subResults = data.results;
                var container = $('#sr' + idx);
                for (var i = 0; i < data.results.length; i++) {
                    var row = data.results[i];
                    var subOrd = i+1;
                    row.ord = idx;
                    row.subOrd = subOrd;
                    container.after(
                        '<div id="sr' + idx + '_sub' + subOrd + '" class="result_row" style="padding-left:20px">' +
                            search.renderRowContent(row) +
                        '</div>'
                    );
                    $('#sr' + idx + '_sub' + subOrd + ' .actions img')
                        .css('opacity', 0.5)
                        .mouseover(function() {
                           $(this).css('opacity', 1.0);
                        })
                        .mouseout(function() {
                           $(this).css('opacity', 0.5);
                        });
                }
                $("#sr" + idx + " cite.similar").html('<a href="javascript:search.hideSimilarResults(' + idx + ')">Hide similar results »</a>');
            },
            function() {
                search.backendError();
            }
        );
    }

    this.hideSimilarResults = function(idx) {
        var row = this.results[idx-1];
        for (var i = 0; i < row.subResults.length; i++)
            $('#sr' + idx + '_sub' + (i+1)).hide();
        $("#sr" + idx + " cite.similar").html('<a href="javascript:search.showSimilarResults(' + idx + ')">Show similar results »</a>');
    }

    this.renderInfoMessage = function(msg) {
        msg += ' <strong></strong>';
        if (this.tags.length == 1)
            msg += ' and tag <strong></strong>';
        else if (this.tags.length > 1)
            msg += ' and tags <strong></strong>';
        $('#search_info').html(msg);
        $('#search_info strong').eq(0).text(decodeURIComponent(this.queryString));
        if (this.tags.length > 0) {
            msg = '';
            for (var i in this.tags) {
                if (msg != '')
                    msg += ', ';
                msg += this.tags[i].show;
            }
            $('#search_info strong').eq(1).text(msg);
        }
    }

    this.dataReady = function(data) {
        this.searchId = data.ctx;

        $('#search_running').hide();
        $('#search_cnt_total').text(data.trackerTotal);

        this.maxPage = Math.ceil(data.trackerTotal / this.searchResultsPerPage);
        this.createNewPages();

        if (data.page && data.results.length > 0)
            this.showResults(data);

        if ((data.networkProblems != undefined) && data.networkProblems) {
            ShowModal('#download-invite');
            return;
            $('#search_results').hide();
            $('#search_cnt').hide();
            $('#search_pages_links').hide();
            $('#search_running').hide();
        }

        if (!data.finished) {
            if (data.results.length < this.searchResultsPerPage)
                this.sendQuery();
        } else {
            if (data.lastPage) {
                this.lastPage = data.lastPage;
                if (this.maxPage > this.lastPage)
                    this.maxPage = this.lastPage;
                if (this.maxPage < this.currResultsPage)
                    this.showResultsPage(this.maxPage);
                this.showPageNumbers();
            }
            if (data.page == 1 && this.results.length == 0) {
                this.renderInfoMessage("No results found for your search");
                $("#search_info").show();
                $('#search_results').show();
                $('#search_cnt').hide();
                $('#search_status').show();
                $('#search_pages_links').hide();
                $(".sortbar").hide();
            }
        }
    }

    this.sendQuery = function() {
        var args;
        if (this.searchId)
            args = {ctx : this.searchId, page: this.currResultsPage, query : this.queryString, sortby : this.sortBy};
		else
            args = {q: this.queryString, sortby: this.sortBy};
        if (this.filter != '')
            args.filter = this.filter;

        $('#search_running').show();
        $.getJSONExt(this.searchUrl, args, function(data) {search.dataReady(data);}, function() {search.finishQuery();});
    }

    this.backendError = function() {
        this.finishQuery();
        $('#search_running').hide();
    }

    this.closeQuery = function() {
        if (!this.searchId)
            return;
        this.searchId = false;
    }

    this.finishQuery = function() {
        if (this.lastPage < 0)
            this.lastPage = this.maxPage;
    }

    this.query = function() {
        this.closeQuery();
        this.queryString = $('#search_box').val();
        
        var s = '';
        for (var i in this.tags) {
            if (s != '')
                s += ';';
            s += this.tags[i].code;
        }
        this.filter = s;

        this.searchId = null;
        this.currResultsPage = 1;
        this.results = new Array();

        $('#search_results').html('');
        $('#search_pages_links td.inner').remove();
        $('#search_pages_links').hide();
        $('#search_info').hide();
        $('#search_cnt').hide();
        $('#search_cnt_from').text('1');
        $('#search_cnt_to').text('1');
        $('#search_info_new_results').showHide(this.sortBy == 'time');
        $('#search_status').show();
        $('#search_running').show();
        $('#search_results').hide();
        $('.sortbar').hide();

        this.maxPage = 1;
        this.lastPage = -1;
        this.createNewPages();
        this.sendQuery();

        return false;
    }

    this.searchString = function(s) {
        $('#search_box').val(s);
        this.query();
    }

    this.showTags = function() {
        var s = '';
        for (var i in this.tags) {
            s +=
                '&nbsp;<span>' + this.tags[i].show + '</span>' +
                '<a href="javascript:search.removeTag(\'' + escape(this.tags[i].code) + '\')" ' +
                    'id="hide-tagsample" class="remove" title="Remove this tag">x</a>';
        }
        if (s != '')
            $("#search_tags").show().html(s);
        else
            $("#search_tags").hide();
    }

    this.addTag = function(tagShow, tagCode) {
        for (var i in this.tags)
            if (this.tags[i].code == tagCode)
                return;
        this.tags.push({show: tagShow, code: tagCode});
        this.showTags();
        location.href = 'index.jsp' + this.makeSearchUrl(this.currResultsPage, this.sortBy, true) + '&tags=' + this.encodeTagsInUrl();
    }

    this.removeTag = function(code) {
        var l = new Array();
        for (var i in this.tags)
            if (this.tags[i].code != code)
                l.push(this.tags[i]);
        this.tags = l;
        this.showTags();
        if (this.tags.length == 0 && this.queryString == '')
            location.href = 'index.jsp';
        else 
            location.href = 'index.jsp' + this.makeSearchUrl(this.currResultsPage, this.sortBy, true) + '&tags=' + this.encodeTagsInUrl();
    }

    this.showResultsPage = function(page) {
        $('#search_results_page' + this.currResultsPage).hide();
        $('#search_results_page' + page).show();
        $('#search_pages_links_' + this.currResultsPage).removeClass('on');
        $('#search_pages_links_' + page).addClass('on');
        this.currResultsPage = page;
        var fromCnt = (page - 1) * this.searchResultsPerPage + 1;
        var toCnt = page * this.searchResultsPerPage;
        if (toCnt > this.results.length)
            toCnt = this.results.length < fromCnt ? fromCnt : this.results.length;
        $('#search_cnt_from').text(fromCnt);
        $('#search_cnt_to').text(toCnt);
        this.showPageNumbers();
        if (!$('#finished_page' + page).length)
            setTimeout(this.sendQuery(),400);
    }

    this.runSearch = function() {
        var query = $('#search_box').val().trim();
        if (query == '' && this.tags.length == 0)
            return;
        this.closeQuery();
        var tags = this.encodeTagsInUrl();
        if (tags != '')
            tags = '&tags=' + tags;
        var url = 'index.jsp?search&query=' + escape(query) + tags + "&sortby=" + this.sortBy;
        setTimeout("location.href='" + url + "'", 100);
        return false;
    }

    this.runSortBy = function(sortBy) {
        this.sortBy = sortBy;
        this.runSearch();
    }

    this.runEmptySearch = function() {
        $("#search_box").focus();
        $(".info").hide();
        $(".sortbar").hide();
        $("#search_running").hide();
    }

    this.onShow = function() {
    }

    this.onHide = function() {
    }

    this.init = function() {
    }

    this.close = function() {
        this.closeQuery();
    }

    this.parseTags = function(s) {
        this.tags = new Array();
        var tags = s.split(",");
        for (var i in tags) {
            var tag = tags[i];
            var l = tag.split("|");
            if (l.length == 2)
                this.tags.push({show: l[0], code: l[1]});
        }
        this.showTags();
    }

    this.run = function() {
        if (HasArgument('sortby'))
            this.sortBy = GetArgumentSortBy();
        $('#sort_popularity').addRemoveClass(this.sortBy == 'rank', 'sortsel');
        $('#sort_freshness').addRemoveClass(this.sortBy == 'time', 'sortsel');

        if (HasArgument('tags'))
            this.parseTags(GetArgumentTags());
        if (HasArgument('query') || GetArgumentQuery('query') == '')
            this.searchString(GetArgumentQuery('query'));
        else
            this.runEmptySearch();
    }
}

var search = new Search();
