var CCC = window.CCC || {};

//-----------------------------------------------------------------------------
// Returns the namespace specified and creates it if it doesn't exist
//
// CCC.namespace("property.package");
// CCC.namespace("CCC.property.package");
//
// Either of the above would create CCC.property, then CCC.property.package
//-----------------------------------------------------------------------------
CCC.namespace = function(ns) {

    if (!ns || !ns.length) {
        return null;
    }

    var levels = ns.split(".");
    var nsobj = CCC;

    // CCC is implied, so it is ignored if it is included
    for (var i=(levels[0] === "CCC") ? 1 : 0; i<levels.length; ++i) {
        nsobj[levels[i]] = nsobj[levels[i]] || {};
        nsobj = nsobj[levels[i]];
    }

    return nsobj;
};

//-----------------------------------------------------------------------------
// Construct the default namespace 'util'
//-----------------------------------------------------------------------------
CCC.namespace("util");
CCC.util.dom = function() {
  var that = CCC.util;

  return {
    get_element : function(id) {
      //---------------------------------------------------------------------
      // deprecated -- hill -- 20070516
      // use YAHOO.util.Dom.get || document.getElementById
      //---------------------------------------------------------------------
      return(YAHOO.util.Dom.get(id));
      /*
      var elem = (document.getElementById) ?
        document.getElementById(id) : ((document.all) ?
          document.all[id] : null);
  
      return(elem);
      */
    },
  
    toggle_disabled : function(obj) {
      var len = obj.fields.length;
      var elem;
  
      for (var i=0; i<len; i++) {
        elem = YAHOO.util.Dom.get(obj.fields[i]);
        if (!elem) {
          continue;
        }
        elem.disabled = obj.disabled;
      }
    },
  
    toggle_display : function(obj) {
      var elem = YAHOO.util.Dom.get(obj.id);
        
      if (!elem) {
        return false;
      }
        
      if (!obj.display) {
        elem.style.display = (elem.style.display === "block") ? 
          "none" : "block";
      } else {
        elem.style.display = (obj.display) ? "block" : "none";
      }
    },
  
    set_focus : function(obj) {
      obj = obj || {};
      var elem;
      var len;
      var i;
  
      if (!obj.id) {
        return false;
      }
  
      if (typeof obj.id != 'string' && !(obj.id instanceof Array)) {
        if (obj.id.value.length > 0) {
          obj.id.select();
        } else {
          obj.id.focus();
        }
        return true;
      } else if (typeof obj.id === 'string') {
        elem = YAHOO.util.Dom.get(obj.id);
        return this.set_focus({id:elem});
      } else {
        len = obj.id.length;
        for (i=0; i<len; i++) {
          if (typeof obj.id[i] === 'string') {
            elem = YAHOO.util.Dom.get(obj.id[i]);
          } else {
            elem = obj.id[i];
          }
  
          if (!elem) {
            continue;
          }
  
          if (elem.value.length <= 0) {
            elem.focus();
            return true;
          }
        }
      }
      return false;
    },
  
    get_child_nodes : function(name,id) {
      var cn;
      var arr = [];
      var elem;
  
      if (!name) {
      throw new Error("name is not defined");
      }
  
      if (!id) {
      throw new Error("id is not defined");
      }
  
      if (typeof(id) === "string") {
        elem = YAHOO.util.Dom.get(id);
        if (elem) {
          cn = elem.childNodes;
        } else {
          return(arr);
        }
      } else {
        cn = id.childNodes;
      }
  
      name = name.toUpperCase();
  
      for (var j = 0; j < cn.length; j++) {
        if (cn[j].tagName === name) {
          arr.push(cn[j]);
        }
      }
      return(arr);
    }
  };
}();

CCC.util.event = function() {
  var that = CCC.util;

  function load_unload_event(type,func) {
    var load = (type === "onload") ? 'onload' : 'onunload';
    var oldonload = window[load];

    if (typeof window[load] != 'function') {
      window[load] = func;
    }  else {
      window[load] = function() {
        oldonload();
        func();
      };
    }
  }
  
  return {
    add_load_event : function(func) {
      load_unload_event('onload',func);
    },
    add_unload_event : function(func) {
      load_unload_event('onunload',func);
    }
  };
}();
//-----------------------------------------------------------------------------
// CCC.util.html requires the following in the HTML
//
// <script src="http://code.cinergycom.net/javascript/process/ \
//   yui/js/yahoo-min.js, yui/js/event-min.js, yui/js/dom-min.js \
//   yui/js/dragdrop-min.js, yui/js/animation-min.js, \
//   yui/js/container-min.js \
//   CCC/js/CCC.js, CCC/js/dom.js, CCC/js/misc.js">
//
// <link href="http://code.cinergycom.net/javascript/process/ \
//   yui-2.2.0a/css/container.css" rel="stylesheet type="text/css" />
//
//-----------------------------------------------------------------------------
CCC.util.html = function() {
  var that = CCC.util;

  //---------------------------------------------------------------------------
  // This is a private function used by stripe_table.  It is needed to work 
  // around a bug in IE related to element attributes.
  //---------------------------------------------------------------------------
  function has_class(obj) {
    var result = false;
    if (obj.getAttributeNode("class") !== null) {
        if (obj.getAttributeNode("class").value === "tfoot") {
          return true;
        }
    }
    return result;
  }

  return {
    create_wait_panel : function(obj) {
      obj               = obj || {};
      obj.width         = obj.width || '300px';
      obj.fixedcenter   = (obj.fixedcenter === undefined) ? 
        true : obj.fixedcenter;
      obj.underlay      = obj.underlay || 'shadow';
      obj.close         = obj.close || false;
      obj.visible       = (obj.visible === undefined) ? true : obj.visiable;
      obj.draggable     = (obj.draggable === undefined) ? true : obj.dragable;
      obj.modal         = (obj.modal === undefined) ? true : obj.modal;
      obj.dismiss_timer = obj.dismiss_timer || 0.35;

      var panel = new YAHOO.widget.Panel("panel", {
        width               : obj.width,
        fixedcenter         : obj.fixedcenter,
        underlay            : obj.underlay,
        close               : obj.close,
        visible             : obj.visible,
        draggable           : obj.draggable,
        modal               : obj.modal
        /*
        effect              : {
           effect : 
               YAHOO.widget.ContainerEffect.FADE, duration:obj.dismiss_timer
        }  
        */
      });

      obj.header = (!obj.header) ? 'Loading, please wait ...' : obj.header;
      obj.body = (obj.body) ? obj.body : '<div>&nbsp;</div>';

      panel.setHeader(obj.header);
      panel.setBody(obj.body);

      var id = (!obj.id) ? 
        document.body : YAHOO.util.Dom.get(obj.id);

      panel.render(id);

      panel.parameters = obj;

      return(panel);
    },

    destroy_wait_panel : function(panel) {
      if (panel) {
        setTimeout(
          function() { panel.hide(); }, panel.parameters.dismiss_timer
        );
      }
      //if (panel) panel.hide();
    },

    create_simple_dialog_panel : function(obj) {
      //-----------------------------------------------------------------------
      // See requirements for create_wait_panel
      //-----------------------------------------------------------------------
      obj = obj || {};
      obj.width       = obj.width || '375px';
      obj.height      = obj.height || null;
      obj.fixedcenter = (obj.fixedcenter === undefined) ? 
        true : obj.fixedcenter;
      obj.underlay    = obj.underlay || 'shadow';
      obj.close       = obj.close || false;
      obj.visible     = (obj.visible === undefined) ? true : obj.visiable;
      obj.draggable   = (obj.draggable === undefined) ? true : obj.dragable;
      obj.modal       = (obj.modal === undefined) ? true : obj.modal;
      obj.header      = obj.header || 'Error:';
      obj.postmethod  = obj.postmethod || 'none';
      obj.body        = obj.body || 'Undefined';
  
      var dialog = new YAHOO.widget.SimpleDialog("dlg",{
        width       : obj.width,
        height      : obj.height,
        fixedcenter : obj.fixedcenter,
        modal       : obj.modal,
        draggable   : obj.draggable,
        visible     : obj.visible,
        underlay    : obj.underlay,
        postmethod  : obj.postmethod,
        close       : obj.close
      });
    
      var hide_panel = that.misc.create_closure(
        this.destroy_simple_dialog_panel,
        true,
        this,
        { dialog : dialog, parameters : obj }
      );

      dialog.setHeader(obj.header);
      dialog.setBody(obj.body);
      dialog.cfg.queueProperty("icon",obj.icon);
      dialog.cfg.queueProperty(
        "buttons",
        [{text : "Ok", handler: hide_panel, isDefault: true}]
      );

      //-----------------------------------------------------------------------
      // Accept escape key to dismiss the dialog window
      //-----------------------------------------------------------------------
      var listeners = new YAHOO.util.KeyListener(
        document,
        { keys : 27 },
        { fn : hide_panel }
      );
      dialog.cfg.queueProperty("keylisteners", listeners);
    
      var id = (!obj.id) ? document.body : YAHOO.util.Dom.get(obj.id);

      dialog.render(id);

      return(dialog);
    },

    destroy_simple_dialog_panel : function(obj) {
      obj = obj || {};
      if (obj.dialog) {
        obj.dialog.hide();
      }

      return false;
    },
    
    //-------------------------------------------------------------------------
    // The functions 'stripe_table and 'has_class' were taken from A List 
    // Apart http://www.alistapart.com/articles/zebratables/
    //
    // I have modified them to meet my needs.
    //-------------------------------------------------------------------------
    stripe_table : function(obj) {
      var id = obj.id;

      //-----------------------------------------------------------------------
      // the flag we'll use to keep track of whether the current row is odd 
      // or even
      //-----------------------------------------------------------------------
      var even = false;

      //-----------------------------------------------------------------------
      // if arguments are provided to specify the colours of the even & odd 
      // rows, then use the them; otherwise use the following defaults:
      //-----------------------------------------------------------------------
      var odd_color = obj.odd_color ? obj.odd_color : "#FAFAFA";
      var even_color = obj.even_color ? obj.even_color : "#F0F0F0";
      var use_class  = (obj.odd_class && obj.even_class) ? true : false;
            
      //-----------------------------------------------------------------------
      // obtain a reference to the desired table if no such table exists, abort
      //-----------------------------------------------------------------------
      var table = YAHOO.util.Dom.get(id);
      if (!table) { return; }

      //-----------------------------------------------------------------------
      // by definition, tables can have more than one tbody element, so we'll 
      // have to get the list of child tbodies
      //
      // In order to handle nested tables, I have modified the code only
      // get the child level elements to the ID passed into the function
      //-----------------------------------------------------------------------
      var tbodies = that.dom.get_child_nodes("tbody",table);

      //-----------------------------------------------------------------------
      // and iterate through them...
      //-----------------------------------------------------------------------
      var trs, i, tds, j, mytd;
      for (var h = 0; h < tbodies.length; h++) {
        //---------------------------------------------------------------------
        // find all child tr elements...
        //---------------------------------------------------------------------
        trs = that.dom.get_child_nodes("tr",tbodies[h]);

        //---------------------------------------------------------------------
        // ... and iterate through them
        //---------------------------------------------------------------------
        for (i = 0; i < trs.length; i++) {
          //-------------------------------------------------------------------
          // avoid rows that have a class attribute
          // or backgroundColor style
          //-------------------------------------------------------------------
          if (
            obj.override || 
            (!has_class(trs[i]) && !trs[i].style.backgroundColor)
          ) {
            //-----------------------------------------------------------------
            // get all the cells in this row...
            //-----------------------------------------------------------------
            tds = that.dom.get_child_nodes("td",trs[i]);

            //-----------------------------------------------------------------
            // and iterate through them...
            //-----------------------------------------------------------------
            for (j = 0; j < tds.length; j++) {
              mytd = tds[j];

              //---------------------------------------------------------------
              // avoid cells that have a tbody class name or backgroundColor 
              // style.  Use override to ignore those conditions.
              //---------------------------------------------------------------
              if (
                obj.override || 
                (!has_class(mytd) && !mytd.style.backgroundColor)
              ) {
                if (!use_class) {
                  mytd.style.backgroundColor = even ? even_color : odd_color;
                } else {
                  YAHOO.util.Dom.addClass(
                    mytd,
                    even ? obj.even_class : obj.odd_class
                  );
                }
              } 
            }
          }
          //-------------------------------------------------------------------
          // flip from odd to even, or vice-versa
          //-------------------------------------------------------------------
          even = !even;
        }
      }
    }
  };
}();

//-----------------------------------------------------------------------------
// Example instantiation:  var vi = CCC.util.html.visual_indicator();
//   Note: there is no need to use the 'new' keyword to construct this object.
//
// The visual_indicator object.  This object will provide visual cues to a 
// user that form values have been changed, but not saved
//
// Creation of the object enacts monitoring for all form elements.
// You can disable element monitoring by settings an element's class value
// to 'no_vi' or the value specified in the 'params : ignore_class' object
//
// Settings (passed in via an object {})
//   change_class : this is the CSS class that will be used to provide a 
//                  visual cue to the user.  The default is 'changed'
//                  Example style sheet setting:
//                    .changed {
//                        background-color: #FFFFE0 !important;
//                    }
//   ignore_class : If this class is set on an element then visual indicator
//                  will ignore that element.  Default is 'no_vi'
//   label : radio and checkboxes can not be updated via the standard
//           indicator mechanism, therefore, this will allow you to define
//           label to be appended to the 'ID' of the radio or checkbox
//           and this value will have the class applied to it.  This will
//           allow a <span> to be created around the label (or text) 
//           that goes with the radio or checkbox.  The default is '_lbl'
//   monitor_tags : This is an array containing the form tag names you want 
//                  to monitor.  The default is 
//                  [ 'input', 'select', 'textarea' ]
//   context : is an element that defines an area of the page to setup 
//             visaul indicators on. Default is 'document.body' -- the 
//             entire page.
//-----------------------------------------------------------------------------
CCC.util.html.visual_indicator = function(params) {
  params = params || {};
  var storage      = [];
  var change_class = params.change_class || 'changed';
  var label        = params.label || '_lbl';
  var ignore_class = params.ignore_class || 'no_vi';
  var monitor_tags = params.monitor_tags || ['input','select','textarea'];
  var context      = params.context || document.body;

  function enable_monitoring() {
    var obj = {};
    obj.method = function(elem,type,callback) {
      add_listener(elem,type,callback);
      initialize_storage(elem);
    };
    obj.context = context;
    walk_elements(obj);
  }

  function visualize_change(event,obj) {
    var id = obj.elem.id;
    var arr, len, i;

    if (obj.elem.type === "checkbox") {
      //-----------------------------------------------------------------------
      // Checkbox objects need to compare their 'checked' property instead of 
      // the 'value' property
      //-----------------------------------------------------------------------
      if (storage[id] != obj.elem.checked) {
        YAHOO.util.Dom.addClass(obj.elem.id+label,change_class);
      } else {
        YAHOO.util.Dom.removeClass(obj.elem.id+label,change_class);
      }
    } else if (obj.elem.type === "radio") {
      //-----------------------------------------------------------------------
      // Radio objects need to compare their 'checked' property
      // instead of the 'value' property.  They also need to be
      // considered as a group.
      //-----------------------------------------------------------------------
      arr = document.getElementsByName(obj.elem.name);
      len = arr.length;
      for (i=0; i<len; i++) {
        if (storage[arr[i].id] != arr[i].checked) {
          if (!arr[i].checked) {
            continue;
          }

          YAHOO.util.Dom.addClass(arr[i].id+label,change_class);
        } else {
          YAHOO.util.Dom.removeClass(arr[i].id+label,change_class);
        }
      }
    } else {
      if (storage[id] != obj.elem.value) {
        YAHOO.util.Dom.addClass(obj.elem,change_class);
      } else {
        YAHOO.util.Dom.removeClass(obj.elem,change_class);
      }
    }
    return false;
  }

  function handle_indicators(obj) {
    obj = obj || {};
    obj.context = obj.context || context;

    if (!obj.method) {
      throw new Error("handle_indicators method not defined");
    }

    var len = monitor_tags.length;
    var arr, len1, j;
    for (var i=0; i<len; i++) {
      arr = obj.context.getElementsByTagName(monitor_tags[i]);
      len1 = arr.length;
      for (j=0; j<len1; j++) {
        if (YAHOO.util.Dom.hasClass(arr[j],ignore_class)) {
          continue;
        }

        obj.method(arr[j]);
      }
    }
  }

  function handle_reset_indicators(elem) {
    if (elem.type === "checkbox" || elem.type === "radio") {
      YAHOO.util.Dom.removeClass(elem.id+label,change_class);
    } else  {
      YAHOO.util.Dom.removeClass(elem,change_class);
    }
  }

  function handle_sync_indicators(elem) {
    if (elem.type === "checkbox" || elem.type === "radio") {
      storage[elem.id] = elem.checked;
    } else  {
      storage[elem.id] = elem.value;
    }
  }

  function walk_elements(obj) {
    obj = obj || {};
    obj.context = obj.context || context;

    if (!obj.method) {
      throw new Error("handle_indicators method not defined");
    }

    var len = monitor_tags.length;
    var arr, len1, j, callback, evt_type;
    for (var i=0; i<len; i++) {
      //----------------------------------------------------------------------
      // There is a problem with the getElementsByTagName call where it will
      // fail to pick up elements that were dynamically created.  I haven't
      // yet figured out a work around for this.
      //
      // BUG / need to fix
      //----------------------------------------------------------------------
      arr = obj.context.getElementsByTagName(monitor_tags[i]);
      len1 = arr.length;

      for (j=0; j<len1; j++) {
        if (YAHOO.util.Dom.hasClass(arr[j],ignore_class)) {
          continue;
        }

        if (!arr[j].id) {
          YAHOO.util.Dom.generateId(arr[j],'visual_indicator_generated_id');
        }

        //---------------------------------------------------------------------
        // Monitoring 'keyup' will give the user instant feedback
        //---------------------------------------------------------------------
        if (arr[j].id) {
          callback = function(e, obj) {
            visualize_change(e,obj);
          };
 
          evt_type = 'keyup';
          if (monitor_tags[i] === "select") {
            evt_type = 'change';
          } else if (arr[j].type === "radio" || arr[j].type === "checkbox") {
            evt_type = 'click';
          }

          obj.method(arr[j],evt_type,callback);
        }
      }
    }
  }

  function add_listener(elem,type,callback) {
    YAHOO.util.Event.addListener(
      elem,
      type,
      callback,
      {elem: elem},
      true
    );
  }

  function remove_listener(elem,type,callback) {
    YAHOO.util.Event.removeListener(elem,type,callback);
  }

  function initialize_storage(elem) {
    if (elem.type === "checkbox" || elem.type === "radio") {
      storage[elem.id] = elem.checked;
    } else {
      storage[elem.id] = elem.value;
    }
  }
  enable_monitoring();

  return {
    //-------------------------------------------------------------------------
    // Use this method to clear down the visual indicator
    //-------------------------------------------------------------------------
    reset_indicators : function(obj) {
      obj = obj || {};
      obj.context = obj.context || context;

      obj.method = handle_reset_indicators;
      handle_indicators(obj);
    },

    //-------------------------------------------------------------------------
    // Use this method to update the stored values 
    //-------------------------------------------------------------------------
    sync_values : function(obj) {
      obj = obj || {};
      obj.context = obj.context || context;

      obj.method = handle_sync_indicators;
      handle_indicators(obj);
    },

    //-------------------------------------------------------------------------
    // Use this method to update the stored values and to clear down the visual
    // indicator
    //-------------------------------------------------------------------------
    sync_and_reset : function(obj) {
      obj = obj || {};
      obj.context = obj.context || context;

      obj.method = function(elem) {
        handle_reset_indicators(elem);
        handle_sync_indicators(elem);
      };
      handle_indicators(obj);
    },

    //-------------------------------------------------------------------------
    // This method will disable visual indicators.
    //-------------------------------------------------------------------------
    destroy : function(obj) {
      obj = obj || {};
      obj.context = obj.context || context;

      obj.method = remove_listener;
      walk_elements(obj);
    },

    //-------------------------------------------------------------------------
    // There is a bug where the event handler doesn't fire when it is added to
    // an object that is set to 'display: none'.
    //
    // This method is intended to allow you to reattach the event handlers once
    // you begin displaying the element.
    //-------------------------------------------------------------------------
    reattach_listeners : function(obj) {
      obj = obj || {};
      obj.context = obj.context || context;

      obj.method = function(elem,type,callback) {
        remove_listener(elem,type,callback);
        add_listener(elem,type,callback);
      };
      walk_elements(obj);
    }
  };
};
CCC.util.misc = function() {
  var that    = CCC.util;
  var cookies = null;

  return {
    //-------------------------------------------------------------------------
    // create closure has been updated to work better with object scoping
    // A new boolean parameter 'scoped' has been added.  If true, then the
    // third un-named argument is expected to be the scope in which to 
    // execute the callback.  If false, then default scope (the 'window' 
    // object) will be used.
    //-------------------------------------------------------------------------
    create_closure : function(func,scoped) {
      var args;
      var scope;
      if (scoped) {
        args = Array.prototype.slice.apply(arguments,[3]);
        scope = arguments[2];
      } else {
        args = Array.prototype.slice.apply(arguments,[2]);
      }
      return(function() {
        if (scoped) {
          func.apply(scope,args);
        } else {
          func.apply(window,args);
        }
      });
    },

    get_cookies : function(obj) {
      obj = obj || {};
      var parts = document.cookie.split(/\s*;\s*/);

      if (!obj.override && cookies) {
        return cookies;
      }

      cookies = {};

      var len = parts.length;
      var nvp;
      for (var i=0; i < len; i++) {
        nvp = parts[i].split(/\s*=\s*/);

        cookies[nvp[0]] = decodeURIComponent(nvp[1]);
      }
      return cookies;
    },

    get_cookie : function(obj) {
      obj = obj || {};

      if (!obj.name) {
        throw new Error("Cookie name is not defined");
      }

      if (!obj.override && cookies && cookies[obj.name]) {
        return(cookies[obj.name]);
      }

      cookies = this.get_cookies(obj);

      return(cookies[obj.name]);
    },

    //-------------------------------------------------------------------------
    // Params :
    //   name    : string
    //   value   : string
    //   max_age : seconds (optional)
    //   domain  : string  (optional)
    //   path    : string  (optional)
    //   secure  : boolean (optional)
    //-------------------------------------------------------------------------
    set_cookie : function(obj) {
      obj = obj || {};

      if (!obj.name) {
        throw new Error("Cookie name is undefined");
      }

      //-----------------------------------------------------------------------
      // Update the internal cookie storage.  We want to add the cookie
      // to internal storage if max_age is not set or max_age is greater 
      // than 0.  Otherwise, if max_age is equaled to 0 then we need to 
      // remove the cookie from internal storage.
      //-----------------------------------------------------------------------
      if (!obj.hasOwnProperty('max_age') || 
         (obj.hasOwnProperty('max_age') && obj.max_age > 0)
      ) {
        if (!cookies) {
          cookies = {};
        }
        cookies[obj.name] = obj.value;
      } else if ((obj.hasOwnProperty('max_age') && obj.max_age <= 0)) {
        if (cookies) {
          delete cookies[obj.name];
        }
      }

      var my_cookie = obj.name + "=" + encodeURIComponent(obj.value);

      if (obj.hasOwnProperty('max_age')) {
        my_cookie += "; max-age=" + obj.max_age;
      }
      if (obj.path) {
        my_cookie += "; path=" + obj.path;
      }
      if (obj.domain) {
        my_cookie += "; domain=" + obj.domain;
      }
      if (obj.secure) {
        my_cookie += "; secure";
      }

      document.cookie = my_cookie;
    },

    //-------------------------------------------------------------------------
    // Remove a cookie.  The same params used to create the cookie, need to
    // be supplied in order to remove it.
    //
    // Params :
    //   name    : string
    //   domain  : string  (optional)
    //   path    : string  (optional)
    //   secure  : boolean (optional)
    //-------------------------------------------------------------------------
    remove_cookie : function(obj) {
      obj.max_age = 0;
      this.set_cookie(obj);
    },

    getStandardTimezoneOffset : function() {
      var date = new Date();
      var msec = date.getTime();
      var offset = -999999;
      for (var j = 0; j < 4; ++j) {
        date.setTime(msec + j * 7884000000);
        offset = Math.max(offset, date.getTimezoneOffset());
      } 
      return offset;
    },
    
    isDST : function() {
      var date = new Date();
      if (
        date.getTimezoneOffset() === CCC.util.misc.getStandardTimezoneOffset()
      ) {
        return true;
      } else {
        return false;
      }
    }
  };
}();
//-----------------------------------------------------------------------------
// Logging singleton (via object literal)
//-----------------------------------------------------------------------------
CCC.util.log = function() {
  var that    = CCC.util;
  var enabled = false;
  var logger  = null;

  return {
    enable : function(bool) {
      enabled = bool;
      if (enabled && !logger) {
        logger = new YAHOO.widget.LogReader();
      }
      return(enabled);
    },

    writer : function(msg,category,source) {
      if (!enabled || !msg) {
        return;
      }
      if (!category) {
        category = 'info';
      }
      if (!source) {
        source = 'CCC.util.log';
      }
  
      YAHOO.log(msg,category,source);
    }
  };
}();

