// JavaScript routines for the MediaArchive Tool.
// Authors:
//   Christian d'Heureuse (chdh@inventec.ch)
//   Juergen Ragaller (ragaller@null-oder-eins.ch)

// JSLint declarations:
/*jslint browser: true, devel: true */
/*global
   window: false, ActiveXObject: false,
   language: false, archive: false,
   selectionSize: false, urlQueryStringSel: false,
   playMode: true */

var screenRefreshMs = 100;                       // 100 ms delay seems to be necessary for a reliable screen refresh

//--- language-specific texts -------------------------------------------------

function lngText (textDe, textEn) {
   switch (language) {
      case "de": return textDe;
      default:   return textEn; }}

var textOpen                = lngText( "&ouml;ffnen",
                                       "open");
var textClose               = lngText( "schliessen",
                                       "close");
var textOpenInfo            = lngText( "Beschreibung anzeigen",
                                       "display description");
var textCloseInfo           = lngText( "Beschreibung schliessen",
                                       "close description");
var textOpenAllInfo         = lngText( "alle Beschreibungen anzeigen",
                                       "display all descriptions");
var textCloseAllInfo        = lngText( "alle Beschreibungen schliessen",
                                       "close all descriptions");
var textOpenHint            = lngText( "Hinweis anzeigen",
                                       "show hint");
var textCloseHint           = lngText( "Hinweis schliessen",
                                       "hide hint");
var textOpenLegend          = lngText( "Legende \u00f6ffnen",
                                       "display legend");
var textCloseLegend         = lngText( "Legende schliessen",
                                       "close legend");
var textOpenQueryParmsInfo  = lngText( "Suchparameter anzeigen",
                                       "display search parameters");
var textCloseQueryParmsInfo = lngText( "Suchparameter-Anzeige schliessen",
                                       "hide search parameters");
var textOpenAll             = lngText( "alle &ouml;ffnen",
                                       "open all");
var textLoading             = lngText( "wird geladen...",
                                       "loading...");
var textDescription         = lngText( "Bezeichnung",
                                       "Description");
var textNoOfImages          = lngText( "Anzahl Bilder",
                                       "No. of Images");
var textImages              = lngText( "Bilder",
                                       "Images");
var textCookieProblem       = lngText( "Cookie kann nicht gesetzt werden. Bitte \u00E4ndern Sie Ihre Web-Borser-Einstellungen um Cookies f\u00FCr diese Website zu erlauben.",
                                       "Unable to set Cookie. Please change your web browser settings to allow cookies for this web site.");
var textInvalidNumber       = lngText( "Ung\u00FCltiger Zahlenwert",
                                       "Invalid number");
var textInvalidInteger      = lngText( "Ung\u00FCltiger Ganzzahlenwert",
                                       "Invalid integer value");
var textInvalidIntegerList  = lngText( "Ung\u00FCltige Ganzzahlenwerteliste",
                                       "Invalid integer list value");
var textNothingChanged      = lngText( "Es wurde nichts ge\u00E4ndert.",
                                       "There are no changes.");
var textPromptNotSaved0     = lngText( "Die \u00C4nderungen wurden nicht gespeichert!",
                                       "The modifications have not been saved!");
var textPromptNotSaved      = lngText( "Achtung: "+textPromptNotSaved0+"\n\nWeiterfahren ohne zu speichern?",
                                       "Warning: "+textPromptNotSaved0+"\n\nContinue without saving?");
var textNoImageSelection    = lngText( "Keine aktive Bildauswahl.",
                                       "No current image selection.");
var textNoBulkCat           = lngText( "Keine Kategorie gew\u00E4hlt.",
                                       "No category selected.");
var textConfirmBulkCat      = lngText( "Achtung: Die Kategorie %cat% wird bei allen %count% Bildern der Bildauswahl %op%.",
                                       "Warning: Category %cat% will be %op% all %count% images in the current selection.");
var textConfirmBulkCatOp1   = lngText( "hinzugef\u00FCgt",
                                       "assigned to");
var textConfirmBulkCatOp2   = lngText( "entfernt",
                                       "removed from");

//--- Misc. utility routines --------------------------------------------------

// Registers an event handler.
function registerEventHandler (node, eventName, eventHandler) {
   if (node.addEventListener) {                            // DOM compatible
      node.addEventListener (eventName, eventHandler, true); }
    else if (node.attachEvent) {                           // IE6
      node.attachEvent ("on"+eventName, eventHandler); }
    else {                                                 // old browsers
      node["on"+eventName] = eventHandler; }}

function getTime() {
   return new Date().getTime(); }

// Returns the elapsed time in milliseconds.
function getElapsedTime (startTime) {
   if (startTime === undefined) {
      return undefined; }
   return getTime() - startTime; }

function setFocus (elementId) {
   document.getElementById(elementId).focus(); }

function searchArray (a, e) {
   for (var p=0; p<a.length; p++) {
      if (a[p] == e) {
         return p; }}
   return -1; }

// A FIFO queue implemented as a linked list.
function Fifo() {}
Fifo.prototype = {
   put: function (v) {
      var e = {value: v};
      if (this.tail === undefined) {
         this.head = e; }
       else {
         this.tail.next = e; }
      this.tail = e; },
   // Returns undefined if the queue is empty.
   get: function() {
      var e = this.head;
      if (e === undefined) {
         return undefined; }
      var next = e.next;
      this.head = next;
      if (next === undefined) {
         this.tail = undefined; }
      return e.value; },
   clear: function() {
      this.head = undefined;
      this.tail = undefined; }};

function getWindowWidth() {
   if (window.innerWidth) {
      return window.innerWidth; }
    else if (document.documentElement && document.documentElement.clientWidth) {
      return document.documentElement.clientWidth; }
    else if (document.body) {
      return document.body.clientWidth; }
    else {
      return 1020; }}

function getWindowHeight() {
   if (window.innerHeight) {
      return window.innerHeight; }
    else if (document.documentElement && document.documentElement.clientHeight) {
      return document.documentElement.clientHeight; }
    else if (document.body) {
      return document.body.clientHeight; }
    else {
      return 620; }}

//--- Type checking and string routines ---------------------------------------

// Returns true if the argument string contains a valid number.
function isNumber (s) {
   return !isNaN(Number(s)); }

// Returns true if the argument string contains a valid integer value.
function isInteger (s) {
   var n = Number(s);
   if (isNaN(n)) {
      return false; }
   if ((n%1)!==0) {
      return false; }
   return true; }

// Removes leading and trailing blanks from a string value.
function trimString (s) {
   return s.replace(/^\s+/, "").replace(/\s+$/, ""); }

function skipListDelimiters (s, p, mode) {
   while (p < s.length) {
      var c = s.charAt(p);
      var i = s.charCodeAt(p);
      if ((c === ' ' || c == ',' || c == ';' || c == '+' || i == 9) != mode) {
         break; }
      p++; }
   return p; }

// Returns true if the argument string contains an integer list.
function isIntegerList (s) {
   var p = 0;
   var cnt = 0;
   while (true) {
      var p0 = skipListDelimiters(s, p, true);
      if (p0 >= s.length) {
         break; }
      p = skipListDelimiters(s, p0, false);
      if (!isInteger(s.substring(p0, p))) {
         return false; }
      cnt++; }
   return cnt > 0; }

function combineStrings (s1, delimiter, s2) {
   var s = (s1 === null) ? "" : s1;
   if (s2 !== null && s2 != "") {
      if (s != "") {
         s += delimiter; }
      s += s2; }
   return s; }

//--- Cookies -----------------------------------------------------------------

var cookiePrefix = "MAT_";

function deleteCookie (cookieName, path) {
   var s = cookieName + "=";
   if (path) {
      s += "; path=" + path; }
   // s += "; max-age=0";             // max-age=0 is DOM compatible but does not work with Safari 3.1.2
   s += "; expires=Thu, 01-Jan-70 00:00:01 GMT";
   document.cookie = s; }

function setCookie (cookieName, cookieValue, permanent, path) {
   if (cookieValue == "") {
      deleteCookie (cookieName, path);
      return; }
   var s = cookieName + "=" + encodeURIComponent(cookieValue);
   if (path) {
      s += "; path=" + path; }
   if (permanent) {
      s += "; expires=Thu, 31-Dec-2037 23:00:00 GMT; max-age=315360000"; } // (IE6 needs "expires")
   document.cookie = s; }

function getCookie (cookieName, defaultValue) {
   var m = document.cookie.match("(^|;)\\s*"+cookieName+"=([^;]*)");
   if (!m) {
      return defaultValue; }
   var s = m[2];
   if (!s) {
      return defaultValue; }
   return decodeURIComponent(s); }

//--- Stylesheets -------------------------------------------------------------

function addStyleRule (selector, declaration) {
   var rule = selector+" {"+declaration+"}";
   var ss = document.styleSheets[0];
   // if (navigator.userAgent.indexOf("AppleWebKit")>=0) {    // Safari
   //   ss.ownerNode.appendChild (document.createTextNode(rule));
   //   return; }
   if (ss.insertRule) {                                    // DOM
      ss.insertRule (rule, ss.cssRules.length);
      return; }
   if (ss.addRule) {                                       // IE6
      ss.addRule (selector, declaration);
      return; }
   /* ignore */ }

function getEffectiveStyle (element, stylePropName, cssPropName) {
   if (cssPropName === undefined) {
      cssPropName = stylePropName; }
   if (window.getComputedStyle) {                          // DOM 2
      return window.getComputedStyle(element, null).getPropertyValue(cssPropName); }
   if (element.currentStyle) {                             // IE6
      return element.currentStyle[stylePropName]; }
   return element.style[stylePropName]; }                  // fallback for Safari: (not the effective style)

// (no longer in use)
function enableStyleSheet (id, enabled) {
   var l = document.getElementById(id);
   if (l) {
      l.disabled = !enabled;
      return; }
   var ssl = document.styleSheets;                            // for old browsers
   if (ssl) {
      for (var i=0; i<ssl.length; i++) {
         var sh = ssl[i];
         if (sh.ownerNode && sh.ownerNode.id == id) {        // Gecko
            sh.disabled = !enabled; }
         else if (sh.id == id) {                             // IE6
            sh.disabled = !enabled; }}}}

// (no longer in use)
function enableStyleSheetGroup (prefix, suffixes, enabledSuffix) {
   for (var p=0; p<suffixes.length; p++) {
      enableStyleSheet (prefix+suffixes[p], false); }       // for Safari 3.1.2, all Stylesheets of the group have to be disabled first before the selected stylesheet is enabled
   enableStyleSheet (prefix+enabledSuffix, true); }

//--- Form field validation ---------------------------------------------------

// Validates a numeric form field.
function validateNumberField (f) {
   var s = trimString(f.value);
   if (s == "") {
      return true; }
   if (!isNumber(s)) {
      alert (textInvalidNumber + " \"" + s + "\".");
      f.focus();
      return false; }
   return true; }

// Validates an integer form field.
function validateIntegerField (f) {
   var s = trimString(f.value);
   if (s == "") {
      return true; }
   if (!isInteger(s)) {
      alert (textInvalidInteger + " \"" + s + "\".");
      f.focus();
      return false; }
   return true; }

// Validates an integer list form field.
function validateIntegerListField (f) {
   var s = trimString(f.value);
   if (s == "") {
      return true; }
   if (!isIntegerList(s)) {
      alert (textInvalidIntegerList + " \"" + s + "\".");
      f.focus();
      return false; }
   return true; }

//--- Form field utilities ----------------------------------------------------

function resetSelectElement (f) {
   var a = f.options;
   for (var p=0; p<a.length; p++) {
      var e = a[p];
      e.selected = e.defaultSelected; }}

// Returns the number of changes in a form.
function countFormChanges (form) {
   var i, e;
   var changes = 0;
   var a = form.getElementsByTagName("input");
   for (i=0; i<a.length; i++) {
      e = a[i];
      switch (e.type) {
         case "checkbox":
            if (e.checked != e.defaultChecked) {
               changes++; }
            break;
         case "text":
            if (e.value != e.defaultValue) {
               changes++; }
            break; }}
   a = form.getElementsByTagName("textarea");
   for (i=0; i<a.length; i++) {
      e = a[i];
      if (e.value != e.defaultValue) {
         changes++; }}
   return changes; }

function countAllFormChanges (formIdPrefix) {
   var a = document.getElementsByTagName("form");
   var changes = 0;
   for (var i=0; i<a.length; i++) {
      var e = a[i];
      if (e.id && e.id.substring(0, formIdPrefix.length) == formIdPrefix) {
         changes = changes + countFormChanges(e); }}
   return changes; }

//--- URL building and navigation ---------------------------------------------

function combineQueryStrings (/*...*/) {
   var s = "";
   for (var p=0; p<arguments.length; p++) {
      var t = arguments[p];
      if (t) {
         if (s) {
            s = s + "&"; }
         s = s + t; }}
   return s; }

// Builds an URL from form field values and sets it as the new location.
function setLocationFromForm (frm, baseUrl, baseQueryString) {
   var qs = "";
   for (var i=0; i<frm.elements.length; i++) {
      var f = frm.elements[i];
      if (f.name != "" && f.value != "") {
         if (qs != "") {
            qs += "&"; }
         qs += encodeURIComponent(f.name) + "=" + encodeURIComponent(f.value); }}
   location.href = baseUrl + "?" + combineQueryStrings(baseQueryString, qs); }

// Validates all form fields as integers and calls setLocationFromForm().
function setLocationFromFormInt (frm, baseUrl, baseQueryString) {
   for (var i=0; i<frm.elements.length; i++) {
      var f = frm.elements[i];
      if (!validateIntegerField(f)) {
         return false; }}
   setLocationFromForm (frm, baseUrl, baseQueryString);
   return true; }

function gotoQueryPage (newPageNo, currentPageNo, totalPages, urlQueryStringWithoutStartPos, playMode) {
   if (newPageNo<1 || newPageNo > totalPages || newPageNo==currentPageNo) {
      return; }
   location.href = 'query?' + combineQueryStrings(urlQueryStringWithoutStartPos, 'page='+newPageNo, playMode?"play=1":null); }

function setEntriesPerPage (frm, layoutName, baseQueryString) {
   var f = frm.elements[0];
   if (!validateIntegerField(f)) {
      return; }
   var n = Number(trimString(f.value));
   if (n <= 200) {    // (we don't save very large values that are only used temporarilly to cache images)
      setCookie (cookiePrefix+"EntriesPerPage_"+layoutName, n, true); }
   setLocationFromForm (frm, 'query', baseQueryString); }

function refreshPage() {
   location.reload(); }

//--- Show / hide elements and text -------------------------------------------

function setElementText (elementId, text) {
   document.getElementById(elementId).firstChild.nodeValue = text; }

function getElementText (elementId) {
   return document.getElementById(elementId).firstChild.nodeValue; }

function setElementTitle (elementId, title) {
   document.getElementById(elementId).title = title; }

function showElementObj (element, visible, visibleDisplayAttrib) {
   if (visible === undefined) {
      visible = true; }
   if (visibleDisplayAttrib === undefined) {
      visibleDisplayAttrib = "block"; }
   var newDisplay = visible ? visibleDisplayAttrib : "none";
   try {
      element.style.display = newDisplay; }
    catch (x) {
      element.style.display = "block"; }}                   // for IE6

function showElement (elementId, visible, visibleDisplayAttrib) {
   var e = document.getElementById(elementId);
   if (!e) {
      alert ("showElement: Element \""+elementId+"\" not found.");
      return; }
   showElementObj (e, visible, visibleDisplayAttrib); }

function isElementVisible (elementId, defaultState) {
   if (defaultState === undefined) {
      defaultState = false; }
   var e = document.getElementById(elementId);
   var s = getEffectiveStyle(e, "display");
   if (s == "none") {
      return false; }
   if (s == "") {
      return defaultState; }
   return true; }

function toggleElementVisibility (elementId, visibleDisplayAttrib) {
   var v = isElementVisible(elementId);
   showElement (elementId, !v, visibleDisplayAttrib); }

function toggleVisibilityWithButton (contentId, buttonId, buttonText1, buttonText2, buttonTitle1, buttonTitle2, visibleDisplayAttrib) {
   var v = isElementVisible(contentId);
   showElement (contentId, !v, visibleDisplayAttrib);
   setElementText (buttonId, v?buttonText1:buttonText2);
   setElementTitle (buttonId, v?buttonTitle1:buttonTitle2); }

function showLegend (mediaObjKey, on) {
   toggleVisibilityWithButton ("legend"+mediaObjKey, "legendOpenButton"+mediaObjKey, "i", "-", textOpenLegend, textCloseLegend); }

function toggleQueryParmsInfo() {
   toggleVisibilityWithButton ("queryParmsInfo", "queryParmsInfoButton", "i", "-", textOpenQueryParmsInfo, textCloseQueryParmsInfo); }
   // scrollTo (0, 0);

function toggleSearchInfo() {
   toggleVisibilityWithButton ("searchInfo", "searchInfoButton", "i", "-", textOpenHint, textCloseHint); }

//--- Popups ------------------------------------------------------------------

var activePopup;
var closedPopup;
var popupOpenTime;
var popupCloseTime;
var popupCloseEventHandlerRegistered;
var mouseInPopup;

function closePopup() {
   if (activePopup === undefined) {
      return; }
   showElement (activePopup, false);
   closedPopup = activePopup;
   activePopup = undefined;
   mouseInPopup = false;
   popupCloseTime = getTime(); }

function popupCloseEventHandler() {
   if (activePopup === undefined || mouseInPopup) {
      return; }
   if (getElapsedTime(popupOpenTime) < 200) {
      return; }
   closePopup(); }

function popupMouseOverEventHandler() {
   mouseInPopup = true; }

function popupMouseOutEventHandler (e) {
   // (This event handler is also called when the mouse moves out of a
   // sub-element of the popup, but we ignore that because the mouseOver
   // event is called immediately afterwards in this case).
   mouseInPopup = false; }

function togglePopup (popupId, focusElementId) {
   if (activePopup == popupId) {
      closePopup(); return; }
   if (activePopup === undefined && closedPopup == popupId) {  // the mousedown event has closed the popup
      if (getElapsedTime(popupCloseTime) < 200) {
         return; }}
   closePopup();
   showElement (popupId);
   if (focusElementId !== undefined) {
      setFocus (focusElementId); }
   activePopup = popupId;
   mouseInPopup = false;
   var e = document.getElementById(popupId);
   e.onmouseover = popupMouseOverEventHandler;
   e.onmouseout = popupMouseOutEventHandler;
   if (!popupCloseEventHandlerRegistered) {
      registerEventHandler (document, "mousedown", popupCloseEventHandler);
      popupCloseEventHandlerRegistered = true; }
   popupOpenTime = getTime(); }

//--- Display medium size image in layout specific html -----------------------

function buildMedContainer(mediaObjKey, imageUrl_med) {
   var e = document.getElementById("med_"+mediaObjKey);
   var c = "";
       c += '<td colspan="5" style="border-bottom: 1px solid #202020;">'+
             '<a href="#" class="helper_anchor" onclick="return false">'+
              '<img src="'+imageUrl_med+'" border="0"/>'+
             '</a>'+
            '</td>';
   e.innerHTML = c;
   e = document.getElementById("low_"+mediaObjKey);
   e.setAttribute('onclick', "hideMedContainer('"+mediaObjKey+"', '"+imageUrl_med+"')"); }

function hideMedContainer(mediaObjKey, imageUrl_med) {
   var c = document.getElementById("med_"+mediaObjKey);
   c.firstChild.style.display = "none";
   var d = document.getElementById("low_"+mediaObjKey);
   d.setAttribute('onclick', "buildMedContainer('"+mediaObjKey+"', '"+imageUrl_med+"')"); }

//--- HTTP communication routines ----------------------------------------------

var asyncHttpRequestQueue = new Fifo();
var asyncHttpRequestActive = false;

var startNextAsyncHttpRequest;                             // forward declaration

function handleAsyncHttpRequestEvent (req, job) {
   if (req.readyState != 4) {
      return; }
   asyncHttpRequestActive = false;
   var s;
   if (req.status == 200) {
      s = req.responseText; }
    else {
      s = "Error while retrieving "+job.url+": "+req.statusText; }
   job.resultProcessingFunction (s);
   startNextAsyncHttpRequest(); }

// Returns: true = ok, false = error.
function startNextAsyncHttpRequest() {
   if (asyncHttpRequestActive) {
      return true; }
   var job = asyncHttpRequestQueue.get();
   if (job === undefined) {
      return true; }
   var req;
   if (window.XMLHttpRequest) {
      req = new XMLHttpRequest(); }
    else if (window.ActiveXObject) {
      req = new ActiveXObject("Microsoft.XMLHTTP"); }
    else {
      alert ("Unable to retrieve dynamic content because your browser does not support XMLHttpRequest.");
      return false; }
   req.onreadystatechange = function() {
      handleAsyncHttpRequestEvent (req, job); };
   req.open ("GET", job.url, true);
   req.send (null);
   asyncHttpRequestActive = true;
   return true; }

// Starts an asynchronous HTTP request.
// Returns: true = ok, false = error.
function startHttpRequest (url, resultProcessingFunction) {
   var job = {
      url: url,
      resultProcessingFunction: resultProcessingFunction};
   asyncHttpRequestQueue.put (job);
   return startNextAsyncHttpRequest(); }

//--- Load static content asynchronously ---------------------------------------

var asyncContentRequested = {};

// Returns true if the content for targetId has already been requested and possibly already loaded.
function isAsynchContentRequested (targetId) {
   return asyncContentRequested[targetId] !== undefined; }

// Gets static content via an asynchronous HTTP request and stores it in the document.
function loadAsynchContent (url, targetId) {
   asyncContentRequested[targetId] = true;
   function resultProcessingFunction (s) {
      document.getElementById(targetId).innerHTML = s; }
   startHttpRequest (url, resultProcessingFunction); }

//--- Menu functions ----------------------------------------------------------

var persistentSubMenuIds = ["menuBlockStatistics", "menuBlockLayout", "menuBlockSort", "menuBlockHelp", "menuBlockIndexes"];

function saveSubMenuStateInCookie (subMenuBlockId, v) {
   var i = searchArray(persistentSubMenuIds, subMenuBlockId);
   if (i == -1) {
      return; }
   setCookie (cookiePrefix+"SubMenu"+i, v?"1":""); }

function toggleSubMenu (subMenuBlockId) {
   var v = !isElementVisible(subMenuBlockId);
   showElement (subMenuBlockId, v);
   saveSubMenuStateInCookie (subMenuBlockId, v); }

function initSubMenus() {
   for (var i=0; i<persistentSubMenuIds.length; i++) {
      var v = getCookie(cookiePrefix+"SubMenu"+i);
      if (v) {
         var id = persistentSubMenuIds[i];
         addStyleRule ("#"+id, "display:block"); }}}

//--- "search" page -----------------------------------------------------------

function validateSearchForm2() {
   var f = document.getElementById("searchForm");
   if (!validateIntegerListField(f.obj)) {
      return false; }
   if (!validateIntegerField(f.mediaObjKeyLo)) {
      return false; }
   if (!validateIntegerField(f.mediaObjKeyHi)) {
      return false; }
   if (archive == "kellogg") {
      if (!validateIntegerListField(f.extId1)) {
         return false; }
      if (!validateIntegerField(f.extId1Lo)) {
         return false; }
      if (!validateIntegerField(f.extId1Hi)) {
         return false; }
      if (!validateIntegerListField(f.extId2)) {
         return false; }}
   if (archive == "eu" || archive == "as") {
      if (!validateNumberField(f.authorAgeLo)) {
         return false; }
      if (!validateNumberField(f.authorAgeHi)) {
         return false; }
      if (!validateIntegerListField(f.author)) {
         return false; }}
   return true; }

function validateSearchForm() {
   try {
      return validateSearchForm2(); }
    catch (e) {
      alert ("Error in validateSearchForm: "+e);
      return false; }}

function selectSearchFormCatalog2 (catalog) {
   var block = document.getElementById("categoryInputBlock");
   var sel = block.getElementsByTagName("select");
   for (var p=0; p<sel.length; p++) {
      var e = sel[p];
      var n = e.id;
      if (n.match("^catalog_")) {
         var selCat = n.substring(8);
         showElementObj (e, selCat==catalog); }}
   showElementObj (block, catalog!=""); }

function selectSearchFormCatalog (onlyIfSet) {
   var catSel = document.getElementById("catalogSelect");
   var catalog = catSel.value;
   if (onlyIfSet && catalog=="") {
      return; }
   selectSearchFormCatalog2 (catalog); }

function searchFormOnReset() {
   selectSearchFormCatalog2 (""); }

function searchPageOnLoad() {
   setFocus ('ImageNoInput');
   selectSearchFormCatalog (true); }

//--- Categories --------------------------------------------------------------

function setMruCatalog (catalog) {
   setCookie (cookiePrefix+"mruCatalog", catalog, true); }

function exportCategories() {
   var cat = document.getElementById("selCatalog").value;
   window.location.href = "exportCat?exportCatalog=" + encodeURIComponent(cat); }

//--- Categorization ----------------------------------------------------------

var suppressCategorizationSaveCheck = false;

// Returns false if the categorization fields have been changed but not saved and
// the user wants to abort the current operation.
function checkCategorizationSaved() {
   if (countAllFormChanges("updateCategories_") === 0) {
      return true; }
   if (confirm(textPromptNotSaved)) {
      suppressCategorizationSaveCheck = true;
      return true; }
   return false; }

function changeCategorizationCatalog (selCatalogCtl, baseQueryString) {
   if (!checkCategorizationSaved()) {
      resetSelectElement (selCatalogCtl);
      return; }
   var selCatalog = selCatalogCtl.value;
   setMruCatalog (selCatalog);
   location.href = "query?" + combineQueryStrings(baseQueryString, "selCatalog="+encodeURIComponent(selCatalog)); }

function validateFormUpdateCategories (form) {
   if (countFormChanges(form) === 0) {
      alert (textNothingChanged);
      return false; }
   suppressCategorizationSaveCheck = true;
   return true; }

function categorizationOnBeforeUnloadEvent (e0) {
   var e = e0 || window.event;
   if (suppressCategorizationSaveCheck) {
      return undefined; }
   if (countAllFormChanges("updateCategories_") === 0) {
      return undefined; }
   if (e) {
      e.returnValue = textPromptNotSaved0; }
   return textPromptNotSaved0; }

function categorizationInit() {
   window.onbeforeunload = categorizationOnBeforeUnloadEvent; }

function adjustLayoutEdit2() {
   var height = getWindowHeight() - 170;
   if (height < 300) {
      height = 300; }
   var a = document.getElementsByTagName("div");
   for (var i=0; i<a.length; i++) {
      var e = a[i];
      if (e.className == "categorizationCats") {
         e.style.height = height+"px"; }}}

//--- media object attributes edit --------------------------------------------

var suppressFormUpdateMediaObjAttrsSaveCheck = false;

function validateFormUpdateMediaObjAttrs (form) {
   if (countFormChanges(form) === 0) {
      alert (textNothingChanged);
      return false; }
   suppressFormUpdateMediaObjAttrsSaveCheck = true;
   return true; }

function editMediaObjAttrsOnBeforeUnloadEvent (e0) {
   var e = e0 || window.event;
   if (suppressFormUpdateMediaObjAttrsSaveCheck) {
      return undefined; }
   if (countAllFormChanges("updateMediaObjAttrs_") === 0) {
      return undefined; }
   if (e) {
      e.returnValue = textPromptNotSaved0; }
   return textPromptNotSaved0; }

function editMediaObjAttrsInit() {
   window.onbeforeunload = editMediaObjAttrsOnBeforeUnloadEvent; }

//--- bulk edit ---------------------------------------------------------------

function bulkCategorize (mode, urlQueryString) {
   if (selectionSize === 0) {
      alert (textNoImageSelection); return; }
   var cat = document.getElementById("bulkCategory").value;
   if (cat == "") {
      alert (textNoBulkCat); return; }
   var msg = textConfirmBulkCat.replace("%cat%", cat).replace("%count%", selectionSize).replace("%op%",mode?textConfirmBulkCatOp1:textConfirmBulkCatOp2);
   if (!confirm(msg)) {
      return; }
   location.href = "bulkAction?" + combineQueryStrings(urlQueryStringSel, (mode?"assignCat":"deassignCat")+"="+encodeURIComponent(cat)); }

//--- settings ----------------------------------------------------------------

function setColorScheme (colorScheme) {
   setCookie (cookiePrefix+"ColorScheme", colorScheme, true);
   refreshPage(); }

function setFontScheme (fontScheme) {
   setCookie (cookiePrefix+"FontScheme", fontScheme, true);
   refreshPage(); }

function setPageScheme (pageScheme) {
   setCookie (cookiePrefix+"PageScheme", pageScheme, true);
   refreshPage(); }

function setLeftColumnVisible (visible) {
   setCookie (cookiePrefix+"NoLeftColumn", visible?"":"1");
   refreshPage(); }

function setLayoutForIndividualImage (layout) {
   setCookie (cookiePrefix+"layoutForIndividualImage", layout, true); }

function setLayoutForImageSelections (layout) {
   setCookie (cookiePrefix+"layoutForImageSelections", layout, true); }

function setPlayerDelay (s0) {
   var s = trimString(s0);
   if (!isInteger(s)) {
      alert (textInvalidInteger + " \"" + s + "\".");
      return; }
   setCookie (cookiePrefix+"playerDelay", s, true); }

function setCatsUnlocked (s0) {
   var s = trimString(s0);
   setCookie (cookiePrefix+"catsUnlocked", s, true); }

//--- player / "show" layout --------------------------------------------------

var playerTimeoutId;

function setPlayButtonImage (playButtonMode) {
   var img = document.getElementById("playButtonImg");
   if (playButtonMode) {
      img.src = img.src.replace("_stop_", "_play_"); }
    else {
      img.src = img.src.replace("_play_", "_stop_"); }}

function stopPlayerTimer() {
   if (!playerTimeoutId) {
      return; }
   window.clearTimeout (playerTimeoutId);
   playerTimeoutId = undefined; }

function playerTimerEvent() {
   playerTimeoutId = undefined;
   var onclick = document.getElementById("playButtonLink").onclick;
   playMode = false;                                       // trick
   onclick(); }

function playButtonEvent (currentPageNo, totalPages, urlQueryStringWithoutStartPos) {
   if (!playMode) {
      gotoQueryPage (currentPageNo+1, currentPageNo, totalPages, urlQueryStringWithoutStartPos, true);
      return; }
   playMode = false;
   stopPlayerTimer();
   setPlayButtonImage (true); }

function startPlayerTimer() {
   var playerDelay = getCookie(cookiePrefix+"playerDelay", 3);
   playerTimeoutId = window.setTimeout(playerTimerEvent, playerDelay * 1000); }

function showPageOnLoad() {
   if (playMode) {
      startPlayerTimer(); }}

//--- other -------------------------------------------------------------------

function procLicenseAccepted() {
   setCookie (cookiePrefix+"License", "ok");
   if (!getCookie(cookiePrefix+"License")) {
      alert (textCookieProblem);
      return; }
   refreshPage(); }

// replaced by query Layout
function displayFullscreen (mediaObjKey, imgUrl) {
  // Nachteil von "layout=fullscreen": Bild wird nicht auf Bildschirm-Gr&ouml;sse gezoomt.
   // window.open ("query?layout=fullscreen&mediaObjKey="+mediaObjKey, "_blank", "scrollbars=0, fullscreen=1");
  window.open (imgUrl, "_blank", "scrollbars=0, fullscreen=1, status=0"); }

function preLoadInit() {
   initSubMenus(); }

preLoadInit();
