function dynarchCalendar_setup(params, inputElemId, dateFormat)
  {
  var cal = Calendar.setup(params);
  
  if (params.flat)
    {
    if (!cal)
      {
      alert('A "fixed" version of the Calendar.setup() function is expected!');
      return;
      }
    
    // Do some hacking to fix the broken things and the things we don't like.
    dynarchCalendar_fixSelectionIssues(cal, inputElemId, dateFormat);

    // Also make sure that this happens every time the calendar is rebuilt
    // (specifically, we're interested in month/year changes and "first day
    // of week" changes).
    var initFunc = cal._init;
    cal._init = function()
      {
      initFunc.apply(this, arguments);
      dynarchCalendar_fixSelectionIssues(cal, inputElemId, dateFormat);
      }
    }
  else
    {
  	var triggerEl = params.button || params.displayArea || params.inputField;
  	var previousClickFunc = triggerEl['onclick'];
    triggerEl['onclick'] = function()
      {
      previousClickFunc();
      var cal = window.calendar;
      if (!cal) return false;

      // Apply the same fixes as for the "flat" version.
      dynarchCalendar_fixSelectionIssues(cal, inputElemId, dateFormat);

      var initFunc = cal._init;
      cal._init = function()
        {
        initFunc.apply(this, arguments);
        dynarchCalendar_fixSelectionIssues(cal, inputElemId, dateFormat);
        }
      }
      
      return false;
    }
    
  return cal;
  }

function dynarchCalendar_fixSelectionIssues(cal, inputElemId, dateFormat)
  {
  var currentDateString = document.getElementById(inputElemId).value;
  
  if ((!cal.currentDateEl) || (cal.currentDateEl.caldate.print(dateFormat) != currentDateString))
    {
    // Fix the broken state when the date to be selected happens to be disabled.
    if (!cal.currentDateEl)
      {
      cal.currentDateEl = dynarchCalendar_traverseDom(
          function(elem) { if (elem.caldate) return elem; },
          cal.element);
      }

    // Remove current selection, find out whether the current date is visible.
    var currentDateIfVisible = false;
    dynarchCalendar_traverseDom(
        function(elem) 
          {
          if (!elem.caldate) return;
          if ((elem.caldate.print(dateFormat) == currentDateString) && (!elem.disabled)) currentDateIfVisible = elem.caldate;
          if (elem.className && /selected/.test(elem.className)) elem.className = elem.className.replace('selected', ''); 
          },
        cal.element);
    
    // If the current date is visible, select it.
    if (currentDateIfVisible)
      {
      cal.setDate(currentDateIfVisible);
      }
    }
  }

function dynarchCalendar_makeFlatCallback(inputElemId, dateFormat, maybeAdditionalUpdateFunc)
  {
  return function(cal)
    {
    if (cal.dateClicked) 
      {
      document.getElementById(inputElemId).value = cal.date.print(dateFormat);
      if (maybeAdditionalUpdateFunc)
        maybeAdditionalUpdateFunc(cal);
      } 
    }
  }

function dynarchCalendar_makeDisableFuncFromDates(dateStrings, isDisallowedList)
  {
  var dateStringHash = {};
  for (var i = 0; i < dateStrings.length; ++i)
    {
    dateStringHash[dateStrings[i]] = true;
    }
  
  if (isDisallowedList)
    return function(date) { return dateStringHash[date.print('%Y%m%d')]; }
  else
    return function(date) { return !dateStringHash[date.print('%Y%m%d')]; }
  }

function dynarchCalendar_makeDisableFuncFromAllowedFunction(isDateAllowedFunction)
  {
  return function(date) { return !isDateAllowedFunction(date); }
  }

function dynarchCalendar_disableAlways(date)
  {
  return true;
  }

function dynarchCalendar_disableNever(date)
  {
  return false;
  }

function dynarchCalendar_traverseDom(func, startNode)
  {
  var node = 
    ( null != startNode
      ? startNode
      : document.documentElement );
  
  var firstEntry = true;
      
  while(true)
    {
    if(firstEntry)
      firstEntry = false;
    else
      {
      var result = func(node);
      if(result)
        return result;
      }
    
    // Moving down the tree while we can, calling the function
    // for all children.
    while(null != node.firstChild)
      {
      var result = func(node.firstChild);
      if(result)
        return result;
      node = node.firstChild;
      }
    
    // Now we have a childless node.
    
    // Moving to the next node if we can.
    if(null != node.nextSibling)
      {
      node = node.nextSibling;
      continue;
      }
    
    // No more siblings, so we move up until we have a node 
    // that does have the next sibling.
    while(true)
      {
      node = node.parentNode;
      if(null == node)
        // End of the game.
        return false;
      
      if(null != node.nextSibling)
        {
        node = node.nextSibling;
        break;
        }
      }
    
    // At this point we have not-yet-explored node.
    }
  }


