// JS for displaying search results.
// by Daniel Lichtenberger, UCS

// ////////////////////////////////////////////////
// ----------------- SearchResult -----------------
// ////////////////////////////////////////////////

// main class representing a search result
function SearchResult(par, doc, searchForm, pageSizes) {
    this.parent = par;
    this.document = doc;
    this.form = this.document.forms[searchForm];
    this.htmlBuilder = null;

    // general parameters
    this.infoTypeId = -1;
    this.isMO = false;           // true if currently selected infotype is a MO
    this.isVideoContent = false;    // true if the currently selected infotype is a MO and is video content
    this.propertyLabels = null;     // translated property labels for each displayed result column
    this.screenviewLabels = null;   // translated screenview property labels
    this.thumbnailLabels = null;    // translated thumbnail property labels
    this.listShowEmpty = null;      // array of boolean values representing the showEmpty property for list result properties
    this.screenviewShowEmpty = null;
    this.thumbnailShowEmpty = null;
    this.showStyles = true;   // show objects with a style?
    this.showLines = true;     // show objects with a line?
    this.showListLabels = true; // show labels in list view?
    this.showBorders = true;                 // show border around thumbnails?
    this.variableWidthThumbs = false; // allow variable width thumbs?
    this.showMainPic = false;       // show main picture in list view?
    this.enableCart = false;        // enable shopping cart for current result?
    this.enableLightBox = false;    // enable lightbox for the current result?
    this.enableRemoveFromLightBox = false;  // enable remove from lightbox for the current result (lightbox)?
    this.screenviewLabelsPosition = null;    // position of screenview labels
    this.resultBrowse = null;       // reference to BrowseNavigation for this search result
    this.resultBrowseBottom = null; // optional second BrowseNavigation that will also be synced to this result
    this.userId = -1;               // the current user ID
    this.emptyFieldMessage = null;  // empty field string (used to identify empty db values)
    this.loaderFrame = null;		// iframe for loading result rows (if this.lazyLoad==true)
    this.printTargetElement = null;		// set for asynchronous printing caused by lazy loading

    // available thumbnail scaling settings
    this.thumbScales = new Array(new ThumbScale(75, 75), new ThumbScale(120, 120), new ThumbScale(170, 170), new ThumbScale(300, 300));
    this.thumbScale = parseInt(this.form["thumbScale"].value); // current thumb scale

    this.rows = new ResultRowCollection(this);
    this.styleId = null;        // currently selected style id
    this.lineId = null;         // currently selected line id
    this.currentOffset = 0;     // current first row
    this.scrollTop = null;      // current scrollbar position (before repaint)
    this.styleLineLabels = new Object();    // associative array containing all style/line labels
    this.preloadedImages = new Array(); // keeps all preloaded images
    this.lazyLoad = true;		// load only currently visible rows

    // available page sizes
    this.pageSizes = pageSizes;		// array of available page sizes, indexed by thumbnail scale
    this.pageSize = parseInt(this.form["pageSize"].value);  // current page size

    // result config
    this.entriesPerPage = this.pageSizes[this.thumbScale][this.pageSize];     // entries per page
    this.detailTarget = null;       // target for instance.do
    this.fromSearch = false;        // is this a "standard" search result submitted from the search form?
    this.printMode = false;         // currently in "print" mode?

    // messages
    this.msg = {    currentWindow:          " of ",
                    addToCart:              "Add to cart",
                    addToCartEuro:          "Open price calculator",
                    removeFromCart:         "Remove from cart",
                    inCart:                 "This item already is in your shopping cart",
                    addToLightBox:          "Add to lightbox",
                    removeFromLightBox:     "Remove from lightbox",
                    downloadButton:         "Download",
                    downloadInlineButton:   "Download in new window",
                    showStoryboardTooltip:  "Show storyboard",
                    showScreenviewTooltip:  "Show screenview",
                    showMainPic:            "Show main picture",
                    showInstance:           "Show instance",
                    topics:                 "Topics"};

    // current view
    this.viewType = "list";
    this.resultType = parseInt(this.form["resultType"].value);  // type of search result
    this.availableViewTypes = new Array("list", "thumbs");
    this.relatedTopics = null;
}

// add the given ResultRow object to this result
SearchResult.prototype.addRow = function(row) {
    this.rows.add(row);
}

// clear all rows
SearchResult.prototype.clearRows = function() {
    this.rows = new ResultRowCollection(this);
}

SearchResult.prototype.init = function() {
    var viewType = this._getCookie(this._getViewTypeCookieName());
    if (viewType != "") {
        this.form["viewType"].value = viewType;
    }
    // check if this viewtype is supported by the current result
    var found = false;
    for (var i = 0; i < this.availableViewTypes.length; i++) {
        if (this.availableViewTypes[i] == this.form["viewType"].value) {
            found = true;
            break;
        }
    }
    if (!found) {
        // fallback: list view
        this.form["viewType"].value = "list";
    }

    // restore page size
    if (this._getCookie("pageSizeIdx") != "") {
        this.setPageSize(parseInt(this._getCookie("pageSizeIdx")));
    }
    // restore thumb scale
    if (this._getCookie("thumbScale") != "") {
        this.setThumbScale(parseInt(this._getCookie("thumbScale")));
    }
}

SearchResult.prototype.show = function() {
    this.viewType = this.form["viewType"].value;
    this.printMode = false;
    this.clearPreloadedImages();
    var pageNavVisible = this.document.getElementById("enlargeThumbs") != null;
    // update view type icons
    this._updateViewTypeButton();
    // enable/disable thumb size icons
    if (pageNavVisible) {
        var showThumbsIcons = this.viewType == "thumbs" || (this.viewType == "list" && this.showMainPic);
        if(this.viewType == "list") this.document.getElementById("toggleShowBorders").style.display = "none";
        if(this.viewType == "thumbs") this.document.getElementById("toggleShowBorders").style.display = "inline";
        this.document.getElementById("enlargeThumbs").style.display = showThumbsIcons ? "inline" : "none";
        this.document.getElementById("reduceThumbs").style.display = showThumbsIcons ? "inline" : "none";
        this.document.getElementById("toggleBorders").style.display = showThumbsIcons ? "inline" : "none";
        // enable/disable number of entries adjustment buttons
        var showEntriesIcons = this.viewType != "screenview" && this.viewType != "details";
        this.document.getElementById("lessentries").style.display = showEntriesIcons ? "inline" : "none";
        this.document.getElementById("moreentries").style.display = showEntriesIcons ? "inline" : "none";
        // update page navigation
        this.updateResultBrowse(this.resultBrowse);
        if (this.resultBrowseBottom != null) {
            this.updateResultBrowse(this.resultBrowseBottom);
        }
    }
    // get current search parameters
    if (this.styleId != null) this.setActiveLink("style" + this.styleId, true);      // reset style/line tabs
    if (this.lineId != null) this.setActiveLink("line" + this.lineId, true);
    // get container for search results
    var container = this.getResultDocument().getElementById("resultContainer");
    // generate results
    var rows = this.getDisplayedRows();
    // save scrollbar position
    this.scrollTop = getScrollTop(this.isEmbedded() ? this.parent.document : this.document);
    // replace dynamic content
    container.innerHTML = this._getRowsHtml(rows, this.viewType, ("thumbs" == this.viewType) ? " " : "");
    // resize frame in embedded mode, if necessary
    this.adjustEmbeddedFrame();
    this.adjustDetailFrame();
    // (pre-)load images
    var i;
    if ("thumbs" == this.viewType || ("list" == this.viewType && this.showMainPic)) {
        for (i = 0; i < rows.length; i++) {
            rows[i].preloadImage();
        }
    }
    this.updateCookies();
}

SearchResult.prototype.updateResultBrowse = function(resultBrowse) {
    resultBrowse.currentOffset = this.currentOffset;
    resultBrowse.rowsPerPage = this.getEntriesPerPage();
    if (!this.lazyLoad) {
        resultBrowse.totalRows = this.getCurrentRows().length;
    }
    resultBrowse.update(true);
}

// return the document containing the search result HTML output
SearchResult.prototype.getResultDocument = function() {
    return this.isEmbedded() ? this.parent.document : this.document;
}

SearchResult.prototype.isEmbedded = function() {
    return !this.fromSearch;    // "embedded" results?
}

SearchResult.prototype.clearPreloadedImages = function() {
    for (var i in this.preloadedImages) {
        var image = this.preloadedImages[i];
        if (image != null && image.parentNode == null) {
            // image not displayed - remove src to prevent loading
            image.src = null;
        }
    }
    this.preloadedImages = new Array();
}

SearchResult.prototype.updateCookies = function() {
    // update cookies
    this._setCookie(this._getViewTypeCookieName(), this.viewType);
    this._setCookie("pageSizeIdx", this.pageSize);
    this._setCookie("thumbScale", this.thumbScale);
}

SearchResult.prototype.printView = function(targetDoc, allPages, targetElement) {
	if (this.lazyLoad && allPages) {
		this.printTarget = targetDoc;
		this.printTargetElement = targetElement;
		this.loadRows(true);
	} else {
		this.processPrint(targetDoc, allPages, targetElement);
	}
}

SearchResult.prototype.processPrint = function(targetDoc, allPages, targetElement) {
	function printString(s) {
		outBuffer.push(s);
	}
	var outBuffer = new Array();
    var displayedRows = new Array();
    this.printMode = true;
    this.printTarget = targetDoc;
    this.preloadedImages = new Array();
    if (allPages) {
        // show all pages, regardless of current offset
        if (this.styleId == "all" || this.lineId == "all") {
            // no style/line info available - show all rows (including those
            // without line or style)
            printString(this._getRowsHtml(this.rows.rows, this.viewType, " "));
            displayedRows = this.rows.rows;
            /*
            // all images by style/line: add headers
            var rows = this.styleId == "all" ? this.rows.rowsByStyle : this.rows.rowsByLine;

            for (var rowIndex in rows) {
                if (rowIndex != "all") {
                    printString("<br clear=\"all\"><h4>" + this.styleLineLabels[rowIndex] + "</h4>");
                    printString(this._getRowsHtml(rows[rowIndex], this.viewType, " "));
                    displayedRows = displayedRows.concat(rows[rowIndex]);
                }
            }*/
        } else {
            var rows = this.getCurrentRows();
            printString(this._getRowsHtml(rows, this.viewType, " "));
            displayedRows = rows;
        }
    } else {
        // show only current view
        var rows = this.getDisplayedRows();
        printString(this._getRowsHtml(rows, this.viewType, " "));
        displayedRows = rows;
    }
    if (targetElement != null) {
    	targetElement.innerHTML = outBuffer.join("");
    } else {
    	targetDoc.write(outBuffer.join(""));
    }
    if ("thumbs" == this.viewType || this.showMainPic) {
        for (i = 0; i < displayedRows.length; i++) {
            displayedRows[i].preloadImage();
        }
    }
    this.printMode = false;
}

SearchResult.prototype.toggleShowBorders = function() {
    // update user config
    getTop().backgroundLoad(getBase() + "search.do?action=toggleShowBorders&showBorders=" + this.showBorders);
    this.showBorders = !this.showBorders;
    this._updateToggleButton("toggleBorders", this.showBorders);
    this.show();
}

SearchResult.prototype.getEntriesPerPage = function() {
    return (this.viewType == "screenview" || this.viewType == "details") ? 1 : this.entriesPerPage;
}

SearchResult.prototype.adjustEmbeddedFrame = function() {
    if (!this.fromSearch) {
        // resize iframe in "embedded" mode
        var frame = this.parent.document.getElementById("searchframe");
        var innerDoc = frame.contentDocument ? frame.contentDocument : frame.contentWindow.document;
        var objToResize = frame.style ? frame.style : frame;
        //var newHeight = Math.min(innerDoc.documentElement.scrollHeight, innerDoc.body.scrollHeight);

        // get navigation height
        var navWrapper = this.document.getElementById("navigationWrapper");
        if (navWrapper == null)
            return;
        var newHeight = 0;
        if (navWrapper.scrollHeight && navWrapper.offsetHeight)
            newHeight = Math.max(navWrapper.scrollHeight, navWrapper.offsetHeight);
        else if (navWrapper.scrollHeight)
            newHeight = navWrapper.scrollHeight;
        else if (navWrapper.offsetHeight)
            newHeight = navWrapper.offsetHeight;
        objToResize.height = (newHeight + 20) + "px";
        // show result container
        var resultContainer = this.parent.document.getElementById("resultContainer");
        resultContainer.style.visibility = "visible";
    }
}

SearchResult.prototype.adjustDetailFrame = function() {
    var container = this.document.getElementById("detailContainer");
    if (container == null)
        container = this.parent.document.getElementById("detailContainer");
    if (this.viewType == "details" && container) {
        var contentWidth = trimPx(this.document.body.clientWidth) - 30;
        var contentHeight = trimPx(getTop().contentHeight) - container.offsetTop - 13;
        container.style.width = contentWidth + "px";
        container.style.height = contentHeight + "px";
    } else if (container) {
        container.style.width = container.style.height = "0px";
    }
}

SearchResult.prototype.setStyleId = function(styleId, refresh) {
    this.setActiveLink("line" + this.lineId, false);
    if (styleId != null && this.styleId == styleId) {      // toggle style switch - disabled
        //this.styleId = null;
        //this.setActiveLink("style" + styleId, false);
    } else {
        this.setActiveLink("style" + this.styleId, false);
        this.setActiveLink("style" + styleId, true);
        this.styleId = styleId;
    }
    this.lineId = null;
    this.currentOffset = 0;
    if (this.lazyLoad) {
    	this.form["resultStyleId"].value = styleId == "all" ? -1 : styleId;
    	this.form["resultLineId"].value = -1;
    }
    if (refresh)
    	this._refreshView();
}

SearchResult.prototype.setLineId = function(lineId, refresh) {
    this.setActiveLink("style" + this.styleId, false);
    if (lineId != null && this.lineId == lineId) {  // toggle line switch - disabled
        //this.lineId = null;
        //this.setActiveLink("line" + lineId, false);
    } else {
        this.setActiveLink("line" + this.lineId, false);
        this.setActiveLink("line" + lineId, true);
        this.lineId = lineId;
    }
    this.styleId = null;
    this.currentOffset = 0;
    if (this.lazyLoad) {
    	this.form["resultStyleId"].value = -1;
    	this.form["resultLineId"].value = lineId == "all" ? -1 : lineId;
    }
    if (refresh) {
    	this._refreshView();
    }
}

SearchResult.prototype._refreshView = function() {
   	if (this.lazyLoad) {
   		this.loadRows();
    } else {
        this.show();
    }
}

SearchResult.prototype.setCurrentOffset = function(val) {
    var valInt = parseInt(val);
    if (isNaN(valInt) || valInt < 0) {
        alert("Invalid number entered");
        this.show();
        return;
    }
    if (valInt == this.currentOffset) {
        return;
    }
    this.currentOffset = Math.max(0, Math.min(this.resultBrowse.totalRows - 1, valInt));
	this._refreshView();
}

// request rows for lazy loading
SearchResult.prototype.loadRows = function(printMode) {
   	var oldTarget = this.form.target;
   	this.form.target = this.loaderFrame;
   	if (printMode) {
   		this.printMode = true;
   		this.form["action"].value = "loadRowsForPrint";
   	} else {
		this.form["rowStart"].value = this.currentOffset;
		this.form["rowEnd"].value = this.currentOffset + this.entriesPerPage;
		this.form["action"].value = "loadRows";
	}
	this.form.submit();
	this.form.target = oldTarget;
}

// increases or decreased entriesPerPage by the given value
SearchResult.prototype.adjustEntriesPerPage = function(delta) {
    if (delta < 0 && this.pageSize > 0) {
        this.setPageSize(this.pageSize - 1);
    } else if (delta > 0 && this.pageSize < this.pageSizes[this.thumbScale].length - 1) {
        this.setPageSize(this.pageSize + 1);
    }
    this._refreshView();
}

SearchResult.prototype.setPageSize = function(pageSize) {
    this.pageSize = pageSize;
    this.entriesPerPage = this.pageSizes[this.thumbScale][this.pageSize];
    this.form["pageSize"].value = this.pageSize;
}

SearchResult.prototype.adjustThumbScale = function(delta) {
    if (delta < 0 && this.thumbScale > 0) {
        this.setThumbScale(this.thumbScale - 1);
    } else if (delta > 0 && this.thumbScale < this.thumbScales.length - 1) {
        this.setThumbScale(this.thumbScale + 1);
    }
    this.loadRows();
    //this.show();
}

SearchResult.prototype.setThumbScale = function(thumbScale) {
    this.thumbScale = thumbScale;
    this.form["thumbScale"].value = this.thumbScale;
    // update entries per page
    this.setPageSize(this.pageSize);
}

// highlight selected link (for style/line filters)
SearchResult.prototype.setActiveLink = function(elName, enabled) {
    var el = this.document.getElementById(elName);
    if (el != null)
        el.className = enabled ? "tabsselected" : "tabs";
}

// open screen view
SearchResult.prototype.openScreenView = function(oid, version, view, offset) {
    if (view == null) view = "screenview";
    var location = getBase() + "instance/load_mo.jsp?action=instance.load&id=" + oid + "&view=" + view
                + "&resultType=" + this.resultType;
    if (offset != null)
        location += "&currentOffset=" + (this.lazyLoad ? offset - this.currentOffset : offset);
    openScreenViewWindow(location, "screenview" + oid);
}

// returns the current row selection (without page navigation, i.e. offset)
SearchResult.prototype.getCurrentRows = function() {
    return this.rows.getRows(this.styleId, this.lineId);
}

// returns the currently displayed rows
SearchResult.prototype.getDisplayedRows = function() {
    return this.rows.getRowRange(this.styleId, this.lineId,
    	this.lazyLoad ? 0 : this.currentOffset, this.getEntriesPerPage());
}

// update the cart icon (which is dependent on the shopping cart content)
SearchResult.prototype.updateCartIcon = function(oid) {
    var rows = this.getDisplayedRows();
    for (var i = 0; i < rows.length; i++) {
        var row = rows[i];
        if (row.oid == oid) {
            this.htmlBuilder.resultRow = row;
            this.htmlBuilder.updateCartIcon();
        }
    }
}

// update the lightbox icon ONLY for the given oid(which is dependent on the lightbox content)
SearchResult.prototype.updateLightBoxIcon = function(oid) {
    var rows = this.getDisplayedRows();
    for (var i = 0; i < rows.length; i++) {
        var row = rows[i];
        if (row.oid == oid) {
            this.htmlBuilder.resultRow = row;
            this.htmlBuilder.updateLightBoxIcon();
        }
    }
}

// update the ALL lightbox icons(which is dependent on the lightbox content)
SearchResult.prototype.updateLightBoxIcons = function() {
    var rows = this.getDisplayedRows();
    for (var i = 0; i < rows.length; i++) {
        this.htmlBuilder.resultRow = rows[i];
        this.htmlBuilder.updateLightBoxIcon();
    }
}

SearchResult.prototype.isVariableWidthThumbs = function() {
    return this.variableWidthThumbs && !this.showBorders;
}

// ------------- "private" functions -------------

// gets html output for all given rows
SearchResult.prototype._getRowsHtml = function(rows, viewType, delim) {
    var out = new Array();
    var i;
    var thumbScale = this.thumbScales[this.thumbScale];
    for (i = 0; i < rows.length; i++) {
        out.push((i > 0 ? delim : "") + rows[i].toHtml(viewType, thumbScale, this.showBorders, i + this.currentOffset, i));
    }
    return out.join("");
}

SearchResult.prototype._updateViewTypeButton = function() {
    var buttons = new Array("viewthumbs", "viewlist", "viewscreenview", "viewdetails");
    for (var i in buttons) {
        this._updateToggleButton(buttons[i], "view" + this.viewType == buttons[i]);
    }
}

SearchResult.prototype._updateToggleButton = function(button, enabled) {
    var elem = this.document.getElementById(button);
    if (elem != null) {
        elem.className = enabled ? "tabsiconselected" : "tabsicon";
    }
}

SearchResult.prototype._getViewTypeCookieName = function() {
    return (this.isMO ? "mo" : "ko") + "ViewType";
}

// default cookie setter
SearchResult.prototype._setCookie = function(name, value) {
    set_cookie(name, value, new Date(new Date().getTime() + 1000 * 60 * 60 * 24));
}

SearchResult.prototype._getCookie = function(name) {
    return get_cookie(name);
}


// ////////////////////////////////////////////////
// ----------------- ResultRowCollection ----------
// ////////////////////////////////////////////////

// class containing all data items and providing (filtered) access to then
function ResultRowCollection(searchResult) {
    this.searchResult = searchResult;
    this.rows = new Array();            // all loaded result rows
    this.rowsByStyle = new Array();     // all rows grouped by style id
    this.rowsByLine = new Array();      // all rows grouped by line id
}

ResultRowCollection.prototype.clear = function() {
	this.rows = new Array();
	this.rowsByStyle = new Array();
	this.rowsByLine = new Array();
}

// adds the given result row to the collection
ResultRowCollection.prototype.add = function(resultRow) {
/*    if ((resultRow.styleId == null && resultRow.lineId == null) ||
        (this.searchResult.showStyles && resultRow.styleId != null) ||
        (this.searchResult.showLines && resultRow.lineId != null)) {
        // filter rows by style and/or line, if present*/
        this.rows.push(resultRow);
        _addToMap(this.rowsByStyle, resultRow.styleId, resultRow);
        _addToMap(this.rowsByLine, resultRow.lineId, resultRow);
//    }
}

function _addToMap(map, id, resultRow) {
    if (id == null || id == -1)
        return;
    if (map[id] == null)
        map[id] = new Array();
    map[id].push(resultRow);
    if (map["all"] == null)
        map["all"] = new Array();
    map["all"].push(resultRow);     // also push row to "all" entry
}

// return a selection of rows
ResultRowCollection.prototype.getRowRange = function(styleId, lineId, begin, maxRows) {
    var rows = this.getRows(styleId, lineId);
    var rowSel = new Array();
    var i;
    for (i = begin; i < Math.min(begin + maxRows, rows.length); i++)
        rowSel.push(rows[i]);
    return rowSel;
}

// return all rows
ResultRowCollection.prototype.getRows = function(styleId, lineId) {
    var hasStyle = (styleId != null && styleId != -1 && styleId != "all");
    var hasLine = (lineId != null && lineId != -1 && lineId != "all");
    if (hasStyle)   // return rows by style if requested
        return (this.rowsByStyle[styleId] != null) ? this.rowsByStyle[styleId] : new Array();
    if (hasLine)    // return rows by line if requested
        return (this.rowsByLine[lineId] != null) ? this.rowsByLine[lineId] : new Array();
    // else: return all rows
    return this.rows;
}

// ////////////////////////////////////////////////
// ----------------- ResultRow --------------------
// ////////////////////////////////////////////////

// a single result row
function ResultRow(searchResult, oid, version, styleId, lineId, licenseTypeId, title, data, screenviewData, thumbnailData, showListLabels, showDownloadButton, keywords, keywordsPos,showTopics,topicsPos,keywordsBeforeTopics) {
    this.searchResult = searchResult;
    this.oid = oid;
    this.version = version;
    this.styleId = styleId;
    this.lineId = lineId;
    this.licenseTypeId = licenseTypeId;
    this.title = title;
    this.data = data;
    this.data.unshift(title);    // also display title as "normal" property in list view
    this.screenviewData = screenviewData;
    this.thumbnailData = thumbnailData;
    this.thumbScale = null;
    this.showListLabels = showListLabels;
    this.showDownloadButton = showDownloadButton;
    this.inlineDownloadAllowed = allowInlineDownload(this.searchResult.infoTypeId, this.oid, this.version);
    this.keywords = keywords;
    if (keywordsPos || keywordsPos == 0)
        this.keywordsPos = keywordsPos;
    else
        this.keywordsPos = -1;
    if (showTopics) {
        this.showTopics = showTopics;
    } else {
        this.showTopics = false;
    }
    if (topicsPos || topicsPos == 0)
        this.topicsPos = topicsPos;
    else
        this.topicsPos = -1;
    this.keywordsBeforeTopics = keywordsBeforeTopics;
}

// return HTML representation
ResultRow.prototype.toHtml = function(viewType, thumbScale, showBorders, rowNumber, topicsIndex) {
    this.thumbScale = thumbScale;
    this.searchResult.htmlBuilder.resultRow = this; // update builder context
    if ("thumbs" == viewType)
        return this.asThumbEntry(showBorders, rowNumber);
    else if ("screenview" == viewType){
        // get only the topics for the current row
        var topics = new Array();
        if (this.showTopics) {
            for(var y = 0; y < this.searchResult.relatedTopics[topicsIndex].length; y++){
                topics.push(this.searchResult.relatedTopics[topicsIndex][y]);
            }
        }
        return this.asScreenviewEntry(rowNumber, topics); // pass topics
    } else if ("details" == viewType)
        return this.asDetailEntry(rowNumber);
    else
        return this.asListEntry(rowNumber);
}

// returns list representation of this row
ResultRow.prototype.asListEntry = function(rowNumber) {
    var href = null;
    var tooltip = "";
    var builder = this.searchResult.htmlBuilder;

    if (this.searchResult.printMode) {
        href = "javascript:void(0)";
    } else if (this.searchResult.isMO) {
        href = "javascript:" + this.getOpenScreenViewUrl("screenview", rowNumber);
        tooltip = this.getMainPicTooltip();
    } else {
        href = "instance.do?action=instance.load&searchResult=" + this.searchResult.fromSearch + "&id=" + this.oid +
               "&resultInfoTypeId=" + this.searchResult.form["resultInfoTypeId"].value +
               "&resultType=" + this.searchResult.resultType;
        tooltip = this.searchResult.msg.showInstance;
    }
    var target = this.searchResult.detailTarget != null ? " target=\"" + this.searchResult.detailTarget  + "\"" : "";

    var out = new Array();
    if (!this.searchResult.isMO && this.data.length == 1 && !this.showListLabels && !this.searchResult.showMainPic) {
        // show only a single line per datarow
        if (this.searchResult.enableCart || this.showDownloadButton) {
            // add cart/download buttons
            builder.pushStyledDiv(out, builder.styles.listButtons, null, builder.getButtons());
        }
        builder.pushStyledDiv(out, builder.styles.listRow, null,
                "<a href=\"" + href + "\" class=\"main\" " + target + " title=\"" + tooltip + "\">" + this.data[0] + "</a>");
    } else {
        builder.styles.listRow.styleClass = "listRow" + (rowNumber % 2 + 1);
//        rowNumber % 2 == 0 ? builder.styles.listRow.styleClass = "listrow" : builder.styles.listRow.styleClass="listrow2";
        out.push("<table " + builder.getStyleHtml(builder.styles.listRow) + "><tr>");
        if (this.searchResult.showMainPic) { // add main picture
            var width = this.thumbScale.width;
            var height = this.thumbScale.height + 6;
            out.push("<td valign=\"top\" ");
            out.push(builder.getStyleHtml(builder.styles.listThumbnail, "width:" + width + "px;"));
            out.push("><a href=\"" + href + "\"" + target + " title=\"" + this.getMainPicTooltip() + "\">");
            out.push("<img id=\"image" + this.oid + "\" src=\"images/dummy.gif\" border=\"0\"></a></td>");
        }
        out.push("<td valign=\"top\">");
        builder.pushPropertyTable(out, this.data, this.searchResult.propertyLabels, null, this.searchResult.listShowEmpty,
                href, tooltip, target);
        out.push("</td></tr></table>");

    }
    return out.join("");
}

// returns thumb representation of this row - outputs placeholder and loads image in the background
ResultRow.prototype.asThumbEntry = function(showBorders, rowNumber) {
    var builder = this.searchResult.htmlBuilder;
    var divWidth = this.thumbScale.width;
    var divHeight = this.thumbScale.height;
    var labelTop = !this.searchResult.isVariableWidthThumbs() && this.searchResult.thumbnailLabels.length > 0 && this.searchResult.thumbnailLabels[0] != "-1" ?
                   this.searchResult.thumbnailLabels[0] : null;
    var labelBottom = !this.searchResult.isVariableWidthThumbs() && this.searchResult.thumbnailLabels.length > 1 && this.searchResult.thumbnailLabels[1] != "-1" ?
                      this.searchResult.thumbnailLabels[1] : null;
    var labelTooltip = !this.searchResult.isVariableWidthThumbs() && this.searchResult.thumbnailLabels.length > 2 && this.searchResult.thumbnailLabels[2] != "-1" ?
                      this.searchResult.thumbnailLabels[2] : null;
    if (this.searchResult.printMode) {
        showBorders = false;
    }
    var containerHeight = divHeight;
    var containerPadding = builder.dimensions.containerPadding;
    if (!this.searchResult.isVariableWidthThumbs()) {
        divWidth += builder.dimensions.imagePadding * 2;      // account for image padding
        if (showBorders) {
            divHeight += builder.dimensions.thumbButtonRowHeight;    // add height of icon row
        }
        containerHeight = divHeight;
        if (labelTop != null) {
            containerHeight += builder.dimensions.thumbLabelHeight;
            containerPadding = builder.dimensions.containerPadding * 2;
        }
        if (labelBottom != null) {
            containerHeight += builder.dimensions.thumbLabelHeight;
            containerPadding = builder.dimensions.containerPadding * 2;
        }
    }
    var divWidthAttr = (this.thumbScale.width > 0 && !this.searchResult.isVariableWidthThumbs()) ? "width:" + divWidth  + "px;": "";
    var divHeightAttr = (this.thumbScale.height > 0 && !this.searchResult.isVariableWidthThumbs()) ? "height:" + divHeight + "px;" : "";
    var containerHeightAttr = (this.thumbScale.height > 0 && !this.searchResult.isVariableWidthThumbs()) ? "height:" + containerHeight + "px;" : "";
    var containerPaddingAttr = containerHeightAttr != "" ? "padding:" + containerPadding + "px;" : "";

    var divStyle = divWidthAttr + divHeightAttr;
    var containerStyle = " style=\"" + divWidthAttr + containerHeightAttr + containerPaddingAttr + "\"";

    var caption = null;
    // create thumbnail mouseover text
    if (labelTop != null || labelBottom != null || labelTooltip != null) {
        caption = "";
        if (labelTooltip != null) {
            caption += this.thumbnailData[2];
        } else {
            if (labelTop != null) {
                caption += this.thumbnailData[0];
                if (labelBottom != null) {
                    caption += " | ";
                }
            }
            if (labelBottom != null) {
                caption += this.thumbnailData[1];
            }
        }
    } else if (this.title != null) {
        caption = this.title;
    }
    caption = caption != null ? " alt=\"" + caption + "\" title=\"" + caption + "\" " : "";
    var openScreenViewLink = null;
    if (this.searchResult.printMode) {
        openScreenViewLink = "void(0)";
    } else {
        openScreenViewLink = "getTop().searchResult" + this.searchResult.resultType + ".openScreenView(" + this.oid + ", " + this.version + ", 'screenview', " + rowNumber + ")";
    }
    var out = new Array();
    builder.startStyledDiv(out, builder.styles.thumbnailContainer);
    if (labelTop != null) {
        // add thumbnail header property
        builder.pushStyledDiv(out, builder.styles.thumbnailHeader, "width:" + divWidth + "px", this.thumbnailData[0]);
    }
    builder.startStyledDiv(out, showBorders ? builder.styles.thumbnailWithBorders : builder.styles.thumbnail, divStyle);
    out.push("<img id=\"image" + this.oid + "\" src=\"images/dummy.gif\" onclick=\"" +
        openScreenViewLink + "\"" + caption + ">");
    if (showBorders) {
        // add buttons
        var footerWidth = divWidth + 4;
        builder.pushStyledDiv(out, builder.styles.thumbnailButtons, "width:" + footerWidth + "px", builder.getButtons());
    }
    out.push("</div>");
    if (labelBottom != null) {
        // add thumbnail footer property
        builder.pushStyledDiv(out, builder.styles.thumbnailFooter, "width:" + divWidth + "px", this.thumbnailData[1]);
    }
    out.push("</div>");
    return out.join("");
}

// returns screenview representation
ResultRow.prototype.asScreenviewEntry = function(rowNumber, topics) {
    var builder = this.searchResult.htmlBuilder;
    var onload = "document.documentElement.scrollTop=" + this.searchResult.scrollTop;
    var out = new Array();
    out.push("<td valign=\"top\">");

    // add image
    out.push("<a href=\"javascript:" + this.getOpenScreenViewUrl("screenview", rowNumber) + "\" title=\"" + this.getMainPicTooltip() + "\"><img src=\"" + this.getThumbnailUrl(3) + "\" onload=\"" + onload + "\" border=\"0\"></a></td>");

    // position properties according to configuration
    var tdAlign = "";
    var propTableAlign = null;
    var propTableWidth = 450;
    if (this.searchResult.screenviewLabelsPosition.charAt(1) == "l")
        propTableAlign = "left";
    else if (this.searchResult.screenviewLabelsPosition.charAt(1) == "r") {
        propTableAlign = "right";
    } else if (this.searchResult.screenviewLabelsPosition.charAt(1) == "t") {
        tdAlign = "valign=\"top\"";
        propTableWidth = 350;
    }
    else if (this.searchResult.screenviewLabelsPosition.charAt(1) == "b") {
        tdAlign = " valign=\"bottom\"";
        propTableWidth = null;
    }

    var propTable = new Array();
    propTable.push("<td " + tdAlign + ">");
    builder.pushPropertyTable(propTable, this.screenviewData, this.searchResult.screenviewLabels, (this.showTopics ? topics : null),
            this.searchResult.screenviewShowEmpty, null, null, null, propTableAlign, propTableWidth, this.keywords,this.keywordsPos,this.topicsPos,this.keywordsBeforeTopics);
    propTable.push("</td>");
    if (this.searchResult.screenviewLabelsPosition.charAt(0) == "b") {
        out.splice(0, 0, "<tr>");
        out.push("</tr><tr>");
        out = out.concat(propTable);
        out.push("</tr>");
    } else if (this.searchResult.screenviewLabelsPosition.charAt(0) == "t") {
        propTable.splice(0, 0, "<tr>");
        propTable.push("</tr><tr>");
        out = propTable.concat(out);
        out.push("</tr>");
    } else if (this.searchResult.screenviewLabelsPosition.charAt(0) == "l") {
        propTable.splice(0, 0, "<tr>");
        out = propTable.concat(out);
        out.push("</tr>");
    } else {
        out.splice(0, 0, "<tr>");
        out = out.concat(propTable);
        out.push("</td></tr>");
    }

    // compose final HTML
    var result = new Array();
    result.push(builder.getButtons());
    //result.push("<div style=\"clear:both\"><br/>&nbsp;</div>");
    result.push("<table " + builder.getStyleHtml(builder.styles.screenviewTable) + " cellspacing=\"0\" cellpadding=\"0\">");
    result = result.concat(out);
    result.push("</table>");
    return result.join("");
}

// return detail representation
ResultRow.prototype.asDetailEntry = function(rowNumber) {
    // don't render anything, but load detail view in detailContainer div
    var frameElement = this.searchResult.document.getElementById("detailContainer");
    if (frameElement == null)
        frameElement = this.searchResult.parent.document.getElementById("detailContainer");
    if (frameElement) {
        frameElement.contentWindow.location.href = "instance/load_mo.jsp?embeddedMode=1&action=instance.load&id=" + this.oid;
    }
    return "";
}

// --- Thumbnail helper functions ---

// get thumbnail url for this object. if thumbVersion is null, the thumbScale-generated thumbnail version is used
ResultRow.prototype.getThumbnailUrl = function(thumbVersion) {
    // thumbnail servlet should lookup main pic only in KO mode
    var thumbMainPicLookup = this.searchResult.showMainPic && !this.searchResult.isMO;
    var appendCache = '&_userId=' + this.searchResult.userId;
    return "Thumbnail?oid=" + this.oid + "&showMainPic=" + thumbMainPicLookup +
        "&version=" + this.version + "&thumbnailVersion=" +
        (thumbVersion == null ? this.thumbScale.getThumbVersion() : thumbVersion) + appendCache;
}

ResultRow.prototype.getOpenScreenViewUrl = function(view, rowNumber) {
    return "getTop().searchResult" + this.searchResult.resultType + ".openScreenView(" + this.oid + ", " + this.version + ", '"
        + (view != null ? view : 'screenview') + "', " + rowNumber + ")";
}

ResultRow.prototype.getMainPicTooltip = function() {
    var tooltip;
    if (this.searchResult.isMO) {
        tooltip = this.searchResult.isVideoContent ?
                      this.searchResult.msg.showStoryboardTooltip : this.searchResult.msg.showScreenviewTooltip;
    } else {
        tooltip = this.searchResult.msg.showMainPic;
    }
    return tooltip;
}

// preload image
ResultRow.prototype.preloadImage = function() {
    // create local event handler
    function adjust() {
        image.onload = null;
        adjustElement(searchResult, resultDoc, oid, image, thumbScale, variableWidthThumbs, verticalCenter);
    }

    // create local variables used for parameterizing the event handler
    var searchResult = this.searchResult;
    var oid = this.oid;
    var thumbScale = this.thumbScale;
    var resultDoc = null;
    if (this.searchResult.printMode) {
        resultDoc = this.searchResult.printTarget;
    } else if (this.searchResult.fromSearch) {
        resultDoc = this.searchResult.document;
    } else {
        resultDoc = this.searchResult.parent.document;
    }
    var resultImage = resultDoc.getElementById("image" + oid);
    var image = browserInfo.isSafari ? new Image() : resultImage != null ? resultImage.cloneNode(true) : null;
    if (image == null) {
        return; // no image target available
    }
    var variableWidthThumbs = this.searchResult.viewType == "thumbs" && this.searchResult.isVariableWidthThumbs();
    var verticalCenter = this.searchResult.viewType == "thumbs" && !variableWidthThumbs;
    // bind local event handler
    image.onload = adjust;
    // load image
    image.src = this.getThumbnailUrl();
    this.searchResult.preloadedImages.push(image);
}

// adjust given image to requested size - not bound to an instance!
function adjustElement(searchResult, resultDoc, oid, img, thumbScale, variableWidthThumbs, verticalCenter) {
    if (img == null) return;
    // remove from preloaded images list to help GC
    for (var i = 0; i < searchResult.preloadedImages.length; i++) {
        if (searchResult.preloadedImages[i] == img) {
            searchResult.preloadedImages[i] = null;
        }
    }
    // scale image
    var scaleX = (!variableWidthThumbs && thumbScale.width != -1) ? thumbScale.width / img.width : 999999;
    var scaleY = (thumbScale.height != -1) ? thumbScale.height / img.height : 999999;
    var width = (img.width * Math.min(scaleX, scaleY));
    // keep height 10 for dummy images
    var height = img.height * Math.min(scaleX, scaleY);
    // copy to existing img element
    try {
        var elem = resultDoc.getElementById("image" + oid);
        if (elem == null)
            return;     // page may have disappeared in the meantime
        var targetElem = browserInfo.isSafari ? elem : img;
        targetElem.width = width;
        targetElem.height = height;
        // center element
        if (!variableWidthThumbs && verticalCenter) {
            //elem.style.marginLeft = (thumbScale.width - width) / 2;
            targetElem.style.marginTop = ((thumbScale.height - height) / 2) + "px";
        }
        if (browserInfo.isSafari) {
            elem.src = img.src;
        } else {
            elem.parentNode.replaceChild(img, elem);
        }
     } catch (e) {
        return; // IE throws an exception when the element disappears...
     }
}

// ////////////////////////////////////////////////
// ----------------- ThumbScale -------------------
// ////////////////////////////////////////////////

// a thumbnail scaling setting
function ThumbScale(width, height) {
    this.width = width;
    this.height = height;
    this.thumbVersion = -1; // auto-calculated
}

// returns  the best thumbnail preview version for the given box size
ThumbScale.prototype.getThumbVersion = function() {
    if (this.thumbVersion != -1)
        return this.thumbVersion;       // return cached value
    if (this.width == -1 && this.height == -1)
        this.thumbVersion = 1;       // fallback
    else {
        if (this.height != -1 && this.height <= 100)
            this.thumbVersion = 1;
        else if (this.height != -1 && this.height <= 200 || this.width != -1 && this.width <= 200)
            this.thumbVersion = 2;
        else
            this.thumbVersion = 3;
    }
    return this.thumbVersion;
}
