// Standard JavaScript Utility Methods
// $Id: ctaUtilities.js,v 1.12 2009/05/22 14:22:05 john Exp $

function CTA_Popup(URL, target, args) {
  // Create/lookup the window by target.
  var newWin = window.open(URL, target, args);
  // Ensure the window is focused.
  newWin.focus();
}

function CTA_updateClock (stime, diffTime, prefix) {
  var currentTime = new Date ();
  var clientTime = new Date ();
  if (stime == 0) {
    currentTime.setTime(currentTime.getTime() + diffTime);
  } else {
    currentTime = new Date(stime);
    diffTime = (currentTime.getTime() - clientTime.getTime())/1000;
    diffTime = Math.floor(diffTime) * 1000;
  }
  // Update the time display
  document.getElementById(prefix + "serverclock").firstChild.nodeValue = currentTime.toUTCString().replace(/,/, "").replace(/:[0-9][0-9] /, " ");
  document.getElementById(prefix + "clientclock").firstChild.nodeValue = clientTime.toLocaleString().replace(/:[0-9][0-9] /, " ").replace(/:[0-9][0-9]$/, "");
  return diffTime;
}

function CTA_togglevisibility(element) {
  e = document.getElementById(element);
  if (e.style.visibility=='visible') {
    e.style.visibility='hidden';
  } else {
    e.style.visibility='visible';
  }
}

/** Helper used initially by DojoDialogFormActionHandler.
 * This does the job of opening a dialog, but also ensuring any script contents
 * are eval'd and the cancel buttons just close the dialog rather than doing a server roundtrip.
 */
function CTA_showDojoDialog(dojoDialogId, evalScriptNodes) {
  var dojoDialog = dijit.byId(dojoDialogId);
  if (!dojoDialog) {
    console.error("Could not locate dialog: " + dojoDialogId);
  } else {
    if (evalScriptNodes) {
      // dijit.Dialog doesn't use dojox ContentPane, and so doesn't have script support.
      dojo.connect(dojoDialog, 'onLoad', this, function() {
        var dojoDialogNode = dojo.byId(dojoDialogId);
        CTA_evalScriptNodes(dojoDialogNode);
      });
    }

    // Hookup any 'cancel' button to the dialog close function.
    dojo.connect(dojoDialog, 'onLoad', this, function() {
      var dojoDialogNode = dojo.byId(dojoDialogId);
      var cancelButtons = dojo.query("div.btn input[name*='cancel']", dojoDialogNode);
      cancelButtons.forEach(function(cancelButton) {
        dojo.connect(cancelButton, 'onclick', this, function(event) {
          // Stop the click from going any further.
          event.stopPropagation();
          event.preventDefault();
          dojo.stopEvent(event);

          // Close the dialog.
          dojoDialog.hide();
        });
      });
    });

    dojoDialog.show();
  }
}

/** Find script blocks in the supplied container eval them.
 * This is useful when asynchronously requesting some HTML and wishing to integrate it in a page.
 * Please note this function REQUIRES DOJO.
 * @param containerNode DOM node containing script tags to execute.
 */
function CTA_evalScriptNodes(containerNode) {
  if (containerNode) {
    var appendNode = dojo.doc.body;
    dojo.query("script", containerNode).forEach(function(scriptNode) {
      // Execute script element, technique from dojox.layout.ContentPane.evalInGlobal function.
      // Do not pull in the src if it is a dojo.js import, we should never call dojo.js twice.
      if (!(scriptNode.src && scriptNode.src.match(/dojo.js/))) {
        var newScriptNode = appendNode.ownerDocument.createElement('script');
        newScriptNode.type = "text/javascript";
        appendNode.appendChild(newScriptNode);
        if (scriptNode.src) {
          newScriptNode.src = scriptNode.src;
        } else {
          newScriptNode.text = scriptNode.innerHTML;
        }
      }
    });
  }
}

/** Used by ComponentExtenderWeb.PerformTask to ensure onclick methods in a wrapped UC are executed
 * if the transition button will call that UC action.
 */
function CTA_performWorkflowTransitionOnClick(ucButtonOnClickId) {
  var ucButtonQuery = dojo.query("input[name='" + ucButtonOnClickId + "']");
  if (ucButtonQuery[0]) {
    // Detect if button has an onclick event.
    var ucButton = ucButtonQuery[0];
    var ucButtonOnClickFunction = ucButton.onclick;
    if (ucButtonOnClickFunction) {
      // Execute the function within the current scope.
      var hitchedFunction = dojo.hitch(this, ucButtonOnClickFunction);
      return hitchedFunction();
    }
  }
  // If we could not locate the onclick then default to allowing the transition to continue.
  console.debug("Could not locate onclick for button: " + ucButtonOnClickId);
  return true;
}

/** Following dojo pattern here. Require these to setup pseudo-namespaces.
 */
/** Hack around chicken and egg problem with packaging. */
var jctal;
if (!jctal) {
jctal = {}
}

jctal.fx = {
  /** Utility for 'throbbing' a node.
   * @param nodeToThrob The DOM node to be throbbed.
   * @param throbBgColor Color to throb to, supply a CSS compatible string.
   */
  throb: function(nodeToThrob, throbBgColor) {
    // Dojo fx highlight animation goes straight to full bg color and eases back.
    // Prefer to 'throb' the highlight, so use two animateProperty calls.
    var nodeBgColor = dojo.style(nodeToThrob, "backgroundColor");
    if (nodeBgColor == "transparent") {
      // Quick fix, this probably needs reverting back to original after animation.
      nodeBgColor = dojo.Color.named.white;
    }
    console.debug("About to throb, from colour '" + nodeBgColor + "' to: " + throbBgColor);
    var animThrobIn = dojo.animateProperty({
      node: nodeToThrob, duration: 500,
      properties: {backgroundColor: {start: nodeBgColor, end: throbBgColor}}
    });
    var animThrobOut = dojo.animateProperty({
      node: nodeToThrob, duration: 500,
      properties: {backgroundColor: {start: throbBgColor, end: nodeBgColor}}
    });
    dojo.connect(animThrobIn, "onEnd", function() {
      animThrobOut.play();
    });
    var throbOutConnect = dojo.connect(animThrobOut, "onEnd", function() {
      // Play throbIn again so we repeat the throb once.
      animThrobIn.play();
      // Disconnect onEnd on animThrobOut to stop endless loop.
      dojo.disconnect(throbOutConnect);
    });
    animThrobIn.play();
  }
}

/** Utility for performing row highlights when mouseover a table row. Also supports a
 * 'sticky' highlight, e.g. a permanent selection.
 */
jctal.fx.rowHighlight = {

  // Cache for the row colour before it was highlighted.
  _cacheOriginalColor: new Array(),
  // Keep track of the rows which must stay permanently highlighted, regardless of mouse events.
  _cacheStickyHighlight: new Array(),

  _rowMouseEnter: function() {
    // If there is not an override colour for this row then continue.
    if (!jctal.fx.rowHighlight._cacheStickyHighlight[this.id]) {
      // Only apply a highlight if the current colour can be discerned.
      var currentColor = jctal.fx.rowHighlight._cacheCurrentColor(this);
      if (currentColor) {
        // Generate a darker version of the original colour for highlighting.
        dojo.require("dojox.color");
        var newColor = new dojox.color.Color(currentColor);
        var newColorHSL = newColor.toHsl();
        newColorHSL.l *= 0.9; // Reduce luminosity.
        newColor = dojox.color.fromHsl(newColorHSL.h, newColorHSL.s, newColorHSL.l);
        jctal.fx.rowHighlight._applyColor(this, newColor);
      }
    }
  },
  _rowMouseLeave: function() {
    // If there is not an override colour for this row then continue.
    if (!jctal.fx.rowHighlight._cacheStickyHighlight[this.id]) {
      jctal.fx.rowHighlight._restoreOriginalColor(this);
    }
  },

  _cacheCurrentColor: function(trNode) {
    var tdQuery = dojo.query("td", trNode);
    // Take the colour of the row to be the bgColor of the first cell.
    if (tdQuery[0]) {
      var currentColor = dojo.style(tdQuery[0], "backgroundColor");
      if (!trNode.id) {
        dojo.require("dojox.uuid.generateRandomUuid");
        trNode.id = dojox.uuid.generateRandomUuid();
      }
      jctal.fx.rowHighlight._cacheOriginalColor[trNode.id] = currentColor;
      return currentColor;
    } else {
      // Cannot cache row colour, no td tags located. Maybe a header (th) row.
      return false;
    }
  },
  _applyColor: function(trNode, newColor) {
    if (trNode) {
      // IE can screw up if we are passed an RGBA color, so convert to hex.
      if (newColor instanceof dojox.color.Color) {
        dojo.query("td", trNode).style("backgroundColor", newColor.toHex());
      } else {
        dojo.query("td", trNode).style("backgroundColor", newColor);
      }
    }
  },
  _restoreOriginalColor: function(trNode) {
    if (trNode.id) {
      // If there is not an override colour for this row then continue.
      if (!jctal.fx.rowHighlight._cacheStickyHighlight[trNode.id]) {
        var cachedColour = jctal.fx.rowHighlight._cacheOriginalColor[trNode.id];
        if (cachedColour) {
          jctal.fx.rowHighlight._applyColor(trNode, cachedColour);
          jctal.fx.rowHighlight._cacheOriginalColor[trNode.id] = null;
        }
      }
    }
  },

  /** Apply mouse roll over highlight function to the supplied table.
   */
  connect: function(tableNode) {
    if (tableNode) {
      dojo.query("tr", tableNode).forEach(function(trNode) {
        dojo.connect(trNode, "onmouseenter", jctal.fx.rowHighlight._rowMouseEnter);
        dojo.connect(trNode, "onmouseleave", jctal.fx.rowHighlight._rowMouseLeave);
      });
    }
  },
  addSticky: function(trNode) {
    if (!trNode.id) {
      dojo.require("dojox.uuid.generateRandomUuid");
      trNode.id = dojox.uuid.generateRandomUuid();
    }
    // If we do not have an original bg color then cache the current. We cannot just blindly cache the current
    // color- it might be the highlight color.
    var currentColor = jctal.fx.rowHighlight._cacheOriginalColor[trNode.id];
    if (!currentColor) {
      currentColor = jctal.fx.rowHighlight._cacheCurrentColor(trNode);
    }
    // Generate and cache the sticky, then apply it.
    dojo.require("dojox.color");
    var newColor = new dojox.color.Color(currentColor);
    var newColorHSL = newColor.toHsl();
    newColorHSL.l *= 0.7; // Reduce luminosity.
    newColor = dojox.color.fromHsl(newColorHSL.h, newColorHSL.s, newColorHSL.l);
    jctal.fx.rowHighlight._cacheStickyHighlight[trNode.id] = newColor;
    jctal.fx.rowHighlight._applyColor(trNode, newColor);
  },
  removeSticky: function(trNode) {
    if (trNode.id) {
      // Clear the sticky cache and return to the original colour.
      if (jctal.fx.rowHighlight._cacheStickyHighlight[trNode.id]) {
        jctal.fx.rowHighlight._cacheStickyHighlight[trNode.id] = null;
        jctal.fx.rowHighlight._restoreOriginalColor(trNode);
      }
    }
  }
}
