

if (typeof PMD == "undefined") {
    /**
     * The PMD global namespace object.  If PMD is already defined, the
     * existing PMD object will not be overwritten so that defined
     * namespaces are preserved.
     * @class PMD
     * @static
     */
    var PMD = {};
}

PMD.namespace = function() {
    var a=arguments, o=null, i, j, d;
    for (i=0; i<a.length; i=i+1) {
        d=a[i].split(".");
        o=PMD;

        // PMD is implied, so it is ignored if it is included
        for (j=(d[0] == "PMD") ? 1 : 0; j<d.length; j=j+1) {
            o[d[j]]=o[d[j]] || {};
            o=o[d[j]];
        }
    }

    return o;
};

PMD.namespace('lang');
PMD.namespace('Ajax');


// Add the Array map method if it doesn't exist
if (!Array.prototype.map)
{
  Array.prototype.map = function(fun /*, thisp*/)
  {
    var len = this.length;
    if (typeof fun != "function")
    {
      throw new TypeError();
    }

    var res = new Array(len);
    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in this)
      {
        res[i] = fun.call(thisp, this[i], i, this);
      }
    }

    return res;
  };
}



/**
 * Applies properties from the object literal o to "this" object.
 * 
 * This function is intended to be "mixed-in" to other objects, using
 * syntax similar to:
 * PMD.example.MyClass.prototype = {
 *   ...
 *   _config: PMD.lang.config,
 *   ...
 * };
 */
PMD.lang.config = function(o) {

   // apply config values
   if (o) {
      for (var i in o) {
         if(o.hasOwnProperty(i)) {
           this[i] = o[i];
         }
      }
   }
};

if(typeof window.console === "undefined")
{
  console = {
    debug: function() {}
  };
}



PMD.Ajax.extractScripts = function(str)
{
  var matchAll = new RegExp('<script[^>]*>([\\S\\s]*?)<\/script>', 'img');
  var matchOne = new RegExp('<script[^>]*>([\\S\\s]*?)<\/script>', 'im');
  return (str.match(matchAll) || []).map(function(scriptTag) {
    return (scriptTag.match(matchOne) || ['', ''])[1];
  });
};

PMD.Ajax.evalScripts = function(str)
{
  return this.extractScripts(str).map(function(script) { return eval(script); });
};


PMD.Ajax.loadJs = function(url, callbackSuccess, callbackFailure, callbackScope)
{
  if(typeof PMD.Ajax.loadJsLoaded === "undefined") { PMD.Ajax.loadJsLoaded = ""; }

  // Nothing to do if script is already loaded
  if(PMD.Ajax.loadJsLoaded.indexOf("["+url+"]") !=-1) { return; }
  PMD.Ajax.loadJsLoaded+="["+url+"]";
  
  YUI().use("get", function(Y)
  {
     Y.Get.script(url, {
        onSuccess: callbackSuccess,
        onFailure: callbackFailure,
        scope: (callbackScope || window)
     });
  });
};


function PMD_setup_faq()
{
  YUI().use('node-base', 'node-style', function(Y)
  {
    if(location.hash && location.hash.substr(0,4)=="#faq")
    {
      var faqId = location.hash.substr(4);
      if(faqId && faqId == parseInt(faqId, 10))
      {
         var ddNode = Y.one('#dd_faq_'+faqId);
         if(ddNode) { ddNode.addClass('expanded'); }
      }
    }

    // Setup click event listeners
    var dts = Y.all('.faq > dt > a');
    dts.on('click', function(e)
    {
      e.preventDefault();
      var ddNode = e.currentTarget.ancestor('dt').next('dd');
      if(ddNode.hasClass('expanded'))
      {
         ddNode.removeClass('expanded');
      }
      else
      {
         ddNode.addClass('expanded');
      }
    });
  });
}






// Things that require YUI
if(typeof YUI !== "undefined")
{



/**
 * Allows rotating between multiple background images by fading each image
 * in to the next.
 * 
 * Because background-images cannot be stacked using a single element, two
 * elements must be provided.  These elements (elA and elB) should be stacked
 * on top of each other using absolute positioning and positioned behind page
 * content using the z-index property.
 * Only one element will be visible at a time except when transitioning.
 * During a transition, both elements will be visible, and opacity will change.
 * 
 * It is important that no content be placed in elA and elB.  Content should be
 * placed in a seperate element positioned on top of elA and elB (and stacked
 * higher using z-index).
 * 
 * @param <string> selector - the CSS selector for element A (e.g. "#divA")
 * @param <string> selector - the CSS selector for element B (e.g. "#divB")
 * @param <Array> imgSrcAry - an array of image URL's to rotate between 
 * 
 */
PMD.BackgroundImageRotate = function(elA, elB, imgSrcAry)
{
  var Me = this;

  this.bgImageSrc = imgSrcAry;
  this.bgImages = [];
  this.fadeDiv = elB;
  this.showDiv = elA;
  
  YUI().use('node-base', 'node-style', function(Y) { Y.on("domready", Me.init, Me, Y); });
};

PMD.BackgroundImageRotate.prototype = 
{
  Y: null,
  
  loaded: false,
  
  startPending: false,
  switchBgPending: false,

  bgImages: null,
  bgImageSrc: null,
  bgIndex: 0,
  
  fadeDiv: null,
  showDiv: null,
  
  /** The number of seconds between image transitions */
  switchInterval: 5,
  switchTimer: null,
  switchRunning: false,
  
  preload: true,
  
  paused: false,

  animVal: null,
  animFPS: 25,
  animDuration: 0.5,
  animTimer: null,
  animRunning: false,
  
  init: function(Y) {
    this.Y = Y;
    
    this.fadeDiv = Y.one(this.fadeDiv);
    this.showDiv = Y.one(this.showDiv);
    
    this.loaded = true;
    
    if(this.startPending)
    {
      this.startPending = false;
      this.start();
    }
  },
  

  
  start: function() {
    if(!this.loaded) { this.startPending = true; return; }
    
    this.switchRunning = true;
    this.switchTimer = this.Y.later(this.switchInterval * 1000, this, this.switchBg, null, true);
    
    // Preload first image
    if(this.preload && !this.bgImages[this.bgIndex])
    {
      this.bgImages[this.bgIndex] = new Image();
      this.bgImages[this.bgIndex].src = this.bgImageSrc[this.bgIndex];
    }
  },
  
  stop: function() {
   this.switchRunning = false;
   this.switchTimer.cancel();
   this.switchTimer = null;
  },
  
  pause: function() {
    this.paused = true;
  },
  
  unPause: function() {
    this.paused = false;
    if(this.switchBgPending) { this.switchBg(); }
  },
  
  
  switchBg: function() {
    // If we are already running an animation, skip
    if(this.animRunning) { return; }
   
    // If image isn't loaded yet, skip this iteration
    if(this.bgImages[this.bgIndex] && !this.bgImages[this.bgIndex].complete) { return; }
    
    // If we are paused skip this iteration
    if(this.paused) { this.switchBgPending = true; return; }
    
    this.switchBgPending = false;
    
    var imgUrl = this.bgImageSrc[this.bgIndex];
    this.bgIndex++;
    this.bgIndex %= this.bgImageSrc.length;
   
    var tmp = this.fadeDiv;
    this.fadeDiv = this.showDiv;
    this.showDiv = tmp;
    
    this.fadeDiv.setStyle('opacity', '1');
    this.showDiv.setStyle('backgroundImage', "url('"+imgUrl+"')");
    this.showDiv.setStyle('opacity', '0');
    this.showDiv.removeClass('hidden');

    this.animVal = 0;
    this.animRunning = true;
    this.animTimer = this.Y.later(1000 / this.animFPS, this, this.animateBg, null, true);

  },
  
  animateBg: function() {
    if(this.animRunning)
    {
      this.animVal += 1 / (this.animFPS * this.animDuration);
      if(this.animVal >= 1)
      {
        this.animRunning = false;
        this.animTimer.cancel();
        this.animTimer = null;
        this.finishBgSwitch();
      }
      else
      {
        this.fadeDiv.setStyle('opacity', 1 - this.animVal);
        this.showDiv.setStyle('opacity', this.animVal);
      }
    }
  },
  
  finishBgSwitch: function()
  {
    this.fadeDiv.addClass('hidden');
    this.fadeDiv.setStyle('opacity', '0');
    this.showDiv.setStyle('opacity', '1');
    
    // Preload next image if it isn't already loaded
    if(this.preload && !this.bgImages[this.bgIndex])
    {
       this.bgImages[this.bgIndex] = new Image();
       this.bgImages[this.bgIndex].src = this.bgImageSrc[this.bgIndex];
    }
  }
                            
};




PMD.HomePageVideo = function(elStaticVideo, elAnimVideo, opts)
{
  var Me = this;
  this.elStaticVideo = elStaticVideo;
  this.elAnimVideo = elAnimVideo;
  
  this._config(opts);
  
  YUI().use('node-base', 'node-style', 'node-screen', 'anim-base', 'anim-easing', 'anim-xy', function(Y) { Y.on("domready", Me.init, Me, Y); });
};

PMD.HomePageVideo.prototype = {

  Y: null,
  
  // USER DEFINED ATTRIBUTES
  width: 608,
  height: 342,
  top: 174,
  duration: 0.75,
  /** Callback function or Array[Callback, scope] */
  beforeToggle: null,
  /** Callback function or Array[Callback, scope] */
  afterToggle: null,
  swfFile: '/flash/jsflvplay.swf',
  flvFile: '/flash/videos/brandfilm.flv',

  togglePending: false,
  
  elStaticVideo: null,
  elAnimVideo: null,
  
  expanded: false,
  
  elFlash: null,
  elFlashId: null,
  
  _config: PMD.lang.config,  

  init: function(Y)
  {
    this.Y = Y;
    
    this.elStaticVideo = Y.one(this.elStaticVideo);
    this.elAnimVideo = Y.one(this.elAnimVideo);
    this.elVideoContainer = Y.one(this.elVideoContainer);
      
    
    this.elStaticVideo.on("click", this.toggleVideo, this);
    this.elAnimVideo.on("click", this.toggleVideo, this);
    
    this.loaded = true;
    
    if(this.togglePending)
    {
       this.togglePending = false;
       this.toggleVideo();
    }
  },
  
  callBeforeToggle: function()
  {
    if(this.beforeToggle)
    {
       if(this.Y.Lang.isArray(this.beforeToggle))
       {
         this.beforeToggle[0].call(this.beforeToggle[1]);
       }
       else
       {
         this.beforeToggle.call(window);
       }
    }
  },
  
  callAfterToggle: function()
  {
    if(this.afterToggle)
    {
       if(this.Y.Lang.isArray(this.afterToggle))
       {
         this.afterToggle[0].call(this.afterToggle[1]);
       }
       else
       {
         this.afterToggle.call(window);
       }
    }
  },
  
  toggleVideo: function()
  {
    if(!this.loaded) { this.togglePending = true; return; }

    if(this.expanded)
    {
      this.hideVideo();
    }
    else
    {
      this.showVideo();
    }
  },
  
  
  showVideo: function()
  {
    this.callBeforeToggle();
   
    var anim = new this.Y.Anim({
      node: this.elAnimVideo,
      to: {
        width: this.width,
        height: this.height,
        top: this.top,
        left: Math.round((this.elAnimVideo.get('winWidth') - this.width) / 2)
      },
      easing: this.Y.Easing.backOut,
      duration: this.duration
    });
    anim.on('end', function() {
      this.elAnimVideo.setStyle('left', '50%');
      this.elAnimVideo.setStyle('marginLeft', '-'+Math.round(this.width / 2)+'px');
      this.expanded = true;
      this.insertVideo();
      this.callAfterToggle();
    }, this);
    
    this.elAnimVideo.setXY(this.elStaticVideo.getXY());
    this.elAnimVideo.setStyle('visibility', 'visible');
    this.elStaticVideo.setStyle('visibility', 'hidden');
    
    anim.run();
  },
  
  hideVideo: function()
  {
    this.callBeforeToggle();
    
    var xy = this.elStaticVideo.getXY();
    
    var anim = new this.Y.Anim({
      node: this.elAnimVideo,
      to: {
        width: this.elStaticVideo.get('clientWidth'),
        height: this.elStaticVideo.get('clientHeight'),
        top: xy[1],
        left: xy[0]
      },
      easing: this.Y.Easing.backIn,
      duration: this.duration
    });
    anim.on('end', function() {
      this.expanded = false;
      this.elStaticVideo.setStyle('visibility', 'visible');
      this.elAnimVideo.setStyle('visibility', 'hidden');
      this.callAfterToggle();
    }, this);
    
    this.removeVideo();
    this.elAnimVideo.setStyle('left', Math.round((this.elAnimVideo.get('winWidth') - this.width) / 2) + "px");
    this.elAnimVideo.setStyle('marginLeft', '0');
    
    anim.run();
  },
  
  insertVideo: function()
  {
    if(!this.elFlash)
    {
      //this.elFlash = swfobject.createSWF(
      //  { data:"/flash/singleflvplay.swf", width:this.width, height:this.height },
      //  { flashvars: "flvfile:/flash/videos/brandfilm.flv" }
      //  { id: this.elVideoContainer.id }
      //);
      
      var nodeId = 'PMDVideoContainer' + Math.floor(Math.random()*100000);
      var node = this.Y.Node.create('<div id="'+nodeId+'"></div>');
      this.elAnimVideo.appendChild(node);
      
      var thisObj = this;
      swfobject.embedSWF(
        this.swfFile,
        nodeId,
        this.width, this.height,
        '9.0.0',
        null,
        {flvfile: this.flvFile},
        null,
        {id: nodeId, name: nodeId},
        function(e) {
          if(e.success)
          {
            thisObj.elFlash = e.ref;
            thisObj.elFlashId = e.id;
          }
          else
          {
            alert("I'm sorry, there was an error loading the video.  Please try again later.");
            thisObj.hideVideo();
          }
        }
      );
    }
    
  },
  
  removeVideo: function()
  {
    if(this.elFlash)
    {
      swfobject.removeSWF(this.elFlashId);
      this.elFlash = null;
      this.elFlashId = null;
    }
  }

};





YUI().add("pmdDialog", function(Y) {
    
   function PmdDialog(config)
   {
      // Chain constructors
      PmdDialog.superclass.constructor.call(this, config);
   }
   
   PmdDialog.NAME = "pmdDialog";
   
   PmdDialog.ATTRS = {
     title: { value: "" },
     bodyContent:  { value: '' },
     bodyHeight: { value: '' },
     loading: { value: true }
   };

   PmdDialog.HEADER_CLASS = "hd";
   PmdDialog.BODY_CLASS = "bd";
   PmdDialog.LOADING_CLASS = "loading";
   PmdDialog.CLOSE_BTN_CLASS = "closebtn";
   
   PmdDialog.CLOSE_BTN_TEMPLATE = '<a href="#" title="Close"><img src="/images/close_icon.gif" width="16" height="16" alt="Close" /></a>';
   
   Y.extend(PmdDialog, Y.Widget, {
      
     closeLink: null,
      
     initializer: function(config)
     {
       if(typeof config.zIndex === "undefined") { config.zIndex = 10; }
       if(typeof config.centered === "undefined" &&
          typeof config.align === "undefined" &&
          typeof config.x === "undefined" &&
          typeof config.y === "undefined" &&
          typeof config.xy === "undefined") { config.centered = true; }
       
       //console.debug("PmdDialog.initializer");
     },
      
     destructor: function()
     {
       //console.debug("PmdDialog.destructor");
     },
     
     renderUI: function()
     {
       //console.debug("PmdDialog.renderUI");
       
       this._renderTitle();
       this._renderBody();
     },
     
     
     _renderTitle: function()
     {
       var contentBox = this.get("contentBox");
       
       
       var title = Y.Node.create("<div>" + this.get("title") + "</div>");
       title.addClass(this.getClassName(PmdDialog.HEADER_CLASS));
       
       var closeBtn = this._createCloseBtn(); 
       title.appendChild(closeBtn);
       
       contentBox.appendChild(title);
       
       this.closeLink = closeBtn;
     },
     
     _renderBody: function()
     {
       var contentBox = this.get("contentBox");
       
       var body = Y.Node.create("<div>" + this.get("bodyContent") + "</div>");
       body.addClass(this.getClassName(PmdDialog.BODY_CLASS));
       contentBox.appendChild(body);
       
       this.set('bodyContentBox', body);
     },
     
     _createCloseBtn: function()
     {
       var btn = Y.Node.create(PmdDialog.CLOSE_BTN_TEMPLATE);
       btn.addClass(this.getClassName(PmdDialog.CLOSE_BTN_CLASS));
       
       return btn;
     },
     
     
     bindUI: function()
     {
       //console.debug("PmdDialog.bindUI");
       this.after('loadingChange', this._afterLoadingChange);
       this.after('bodyContentChange', this._afterBodyChange);
       this.after('bodyHeightChange', this._afterBodyHeightChange);
       
       this.closeLink.on('click', this._onCloseLinkClick, this);
     },
     
     syncUI: function()
     {
       //console.debug("PmdDialog.syncUI");
       this._uiSetLoading(this.get('loading'));
       this._uiSetBodyHeight(this.get('bodyHeight'));
     },
     
     /**
      * Sets the height of the widget by setting the height of the body
      * 
      * @override
      */
     _uiSetBodyHeight: function(val)
     {
       if (Y.Lang.isNumber(val))
       {
          val = val + this.DEF_UNIT;
       }
       this.get('bodyContentBox').setStyle('height', val);
       
       var align = this.get('align');
       if(align) { this.align(align.node, align.points); }
     },
     
     /**
      * Sets the loading state for the UI
      *
      * @param <boolean> val
      * 
      * @protected
      */
     _uiSetLoading: function(val)
     {
       var box = this.get('boundingBox'),
           sClassName = this.getClassName(PmdDialog.LOADING_CLASS);
       
       if (val === true)
       {
         box.addClass(sClassName);
       }
       else
       {
         box.removeClass(sClassName);
       }
     },
     
     /**
      * Default loading attribute state change handler
      * 
      * @param <EventFacade> evt The event facade for the attribute change
      */
     _afterLoadingChange: function(evt)
     {
       this._uiSetLoading(evt.newVal);
     },
     
     _afterBodyChange: function(evt)
     {
       if (evt.src !== Y.Widget.UI_SRC)
       {
          var elBody = this.get('bodyContentBox');
          elBody.setContent(evt.newVal);
          
          var align = this.get('align');
          if(align) { this.align(align.node, align.points); }
       }
     },
     
     _afterBodyHeightChange: function(evt)
     {
       this._uiSetBodyHeight(evt.newVal);
     },
     
     _onCloseLinkClick: function(evt)
     {
       evt.preventDefault();
       this.set('visible', false);
     }
     
   });
   
   PMD.Dialog = Y.Base.build("pmdDialog", PmdDialog, [Y.WidgetPosition, Y.WidgetStack, Y.WidgetPositionExt]);
     
}, "0.0.1", {requires: ["oop", "widget", "widget-position", "widget-position-ext", "widget-stack"]});
   





PMD.EmailAFriend = function(opts)
{
  var Me = this;
  this._config(opts);
  
  YUI().use('pmdDialog', 'io-base', 'io-form', 'json-parse', function(Y) { Y.on("domready", Me.init, Me, Y); });
};

PMD.EmailAFriend.prototype = {

  Y: null,
  
  elLiContainer: "email_friend_li",
  
  elSendBtnId: "email_friend_send_btn",
  
  elCloseBtnId: "email_friend_close_btn",
  
  linkText: "Send to a Friend",
  
  defaultBodyHeight: "284px",
  
  defaultWidth: "600px",
  
  dialog: null,
  
  formLoaded: false,
  
  formGetUri: null,
  
  formSendUri: null,
  
  _config: PMD.lang.config,
  
  init: function(Y)
  {
    this.Y = Y;
    
    // TODO: Fix this!
    // Because two ReCAPTCHAs can't exist on the same page, for now if the
    // current page has a ReCAPTCHA, don't enable the send to a friend link
    if(document.getElementById('recaptcha_response_field')) { return; }
    
    // We currently don't support IE6
    if(navigator.appName == 'Microsoft Internet Explorer')
    {
       var ua = navigator.userAgent;
       var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
       if (re.exec(ua) != null)
       {
          rv = parseFloat( RegExp.$1 );
       }
       if (rv < 7.0) { return; }
    }
    
        
    if(Y.Lang.isString(this.elLiContainer))
    {
       this.elLiContainer = Y.one("#"+this.elLiContainer);
    }
    
    if(!this.elLiContainer) { return; }
    
    var elLink = Y.Node.create("<a href=\"#\">" + this.linkText + "</a>");
    this.elLiContainer.appendChild(elLink);
    
    elLink.on("click", function(e) {e.preventDefault(); this.toggle();}, this);
    
    //this.createDialog();
  },
  
  createDialog: function()
  {
    var Y = this.Y;
    this.dialog = new PMD.Dialog({
      title: "Tell a friend about this page",
      align: {node: this.elLiContainer, points: [Y.WidgetPositionExt.BR, Y.WidgetPositionExt.BR]},
      visible: false,
      width: this.defaultWidth,
      bodyHeight: this.defaultBodyHeight
    });
    this.dialog.render();
    this.dialog.after('visibleChange', this._afterDialogVisibleChange, this);
  },
  
  toggle: function()
  {
    if(typeof this.dialog==="undefined" || this.dialog===null || this.dialog.get('visible')===false) { this.show(); }
    else { this.hide(); }
  },
  
  show: function()
  {
    if(!this.dialog) { this.createDialog(); }
    this.dialog.set("visible", true);
  },
  
  hide: function()
  {
    this.dialog.set("visible", false);
  },
  
  error: function(num, msg)
  {
    var str = "<p class=\"error\">We're sorry, an unknown error occurred.  Please try again later.</p>";
    if(msg || num)
    {
       str += "<p style=\"color: #999999;\">";
       if(msg) { str += msg; }
       if(num) { str += (msg ? " ("+num+")" : num); }
       str += "</p>";
    }
    
    this.dialog.set('loading', false);
    //this.dialog.set('bodyHeight', null);
    this.dialog.set('bodyContent', str);
  },
  
  _afterDialogVisibleChange: function(evt)
  {
    if(evt.newVal===true && !this.formLoaded)
    {
      this.loadForm();
    }
    
    if(evt.newVal===false)
    {
      this.destroyContent();
    }
  },
  
  loadForm: function()
  {
    var Y = this.Y;
    
    if(!this.formGetUri || !this.formSendUri)
    {
       this.error("0x80001004", "Invalid configuration");
       return;
    }
    
    this.dialog.set('loading', true);
    if(this.dialog.get('bodyHeight')!==this.defaultBodyHeight) { this.dialog.set('bodyHeight', this.defaultBodyHeight); }
    if(this.dialog.get('width')!==this.defaultWidth) { this.dialog.set('width', this.DEFAULT_WIDTH); }

    var request = Y.io(this.formGetUri, {context: this, on: {
       failure: function(tId, response) {this.error('0x80001000', "Cannot load form"); },
       success: this._onGetFormSuccess
    }});
  },
  
  destroyContent: function()
  {
    var Y = this.Y;
    
    if(this.formLoaded) { this.unregisterForm(); }
    if(typeof Recaptcha !== "undefined") { Recaptcha.destroy(); }
    Y.detach('click', null, "#"+this.elCloseBtnId);
    
    this.dialog.set('bodyContent', "&nbsp;");
  },
  
  _onGetFormSuccess: function(tId, response)
  {
    this.dialog.set('loading', false);
    
    var responseData = this.parseJsonResponse(response);
    if(!responseData) return;
    
    if(this.displayResponse(responseData, true))
    {
      this.registerForm();
    }
  },
  
  parseJsonResponse: function(response)
  {
    var Y = this.Y;
    var responseData;
    
    try
    {
       responseData = Y.JSON.parse(response.responseText);
       if(!Y.Lang.isObject(responseData))
       {
          this.error("0x80001001", "Response invalid");
          return null;
       }
    }
    catch (e)
    {
       this.error("0x80001007", "Cannot parse response");
       return null;
    }
    
    return responseData;
  },
  
  displayResponse: function(responseData, resize)
  {
    var Y = this.Y;
    var content;
    
    if(typeof responseData.content === "undefined")
    {
      this.error("0x80001008", "No content in response");
      return false;
    }
    
    this.dialog.set('bodyContent', responseData.content);

    if(resize) { this.dialog.set('bodyHeight',null); }
    
    if(typeof responseData !== "undefined" && typeof responseData.js !== "undefined")
    {
       try
       {
          PMD.Ajax.evalScripts(responseData.js);
       }
       catch (ex)
       {
          this.dialog.error("0x80001002", "Cannot execute response scripts");
          return false;
       }
    }
    
    return true;
  },
  
  registerForm: function()
  {
    var Y = this.Y;
    var rootEl = this.dialog.get('contentBox');
    
    var sendBtn = rootEl.one("#" + this.elSendBtnId);
    if(!sendBtn)
    {
       this.error("0x80001003", "Cannot register form");
       return;
    }
    
    sendBtn.on('click', this.submitForm, this);
    this.formLoaded = true;
  },
  
  unregisterForm: function()
  {
    var Y = this.Y;
    var rootEl = this.dialog.get('contentBox');
    
    Y.detach('click', null, "#"+this.elSendBtnId);
    this.formLoaded = false;   
  },
  
  submitForm: function(evt)
  { 
    var Y = this.Y;
   
    // Prevent the default action
    evt.preventDefault();

    if(!this.formGetUri || !this.formSendUri)
    {
       this.error("0x80001004", "Invalid configuration");
       return;
    }
    
    var elForm = this.dialog.get('contentBox').one('form');
    if(!elForm) { this.error("0x80001005", "Cannot find form"); return; }
       
    var request = Y.io(this.formSendUri, {
       context: this,
       on: {
         failure: function(tId, response) {this.error('0x80001006', "Cannot send form"); },
         success: this._onSubmitFormSuccess
       },
       method: 'POST',
       form: { id: elForm }
    });
    
    this.dialog.set('loading', true);
    if(this.dialog.get('bodyHeight')!==this.defaultBodyHeight) { this.dialog.set('bodyHeight', this.defaultBodyHeight); }
    if(this.dialog.get('width')!==this.defaultWidth) { this.dialog.set('width', this.DEFAULT_WIDTH); }
    this.destroyContent();
    
  },
  

  
  _onSubmitFormSuccess: function(tId, response)
  {
    this.dialog.set('loading', false);
    
    var responseData = this.parseJsonResponse(response);
    if(!responseData) return;

    if(typeof responseData.success === "undefined"
        || (responseData.success===false && typeof responseData.permanentError === "undefined"))
    {
      this.error("0x80001009", "Invalid response");
      return;
    }
    
    if(responseData.success===true || responseData.permanentError===true)
    {
      if(this.displayResponse(responseData, false))
      {
         // Attach close button
         var rootEl = this.dialog.get('contentBox');
         var closeBtn = rootEl.one("#" + this.elCloseBtnId);
         if(!closeBtn)
         {
           this.error("0x8000100A", "Cannot register close button");
           return;
         }
     
         closeBtn.on('click', function(e) {e.preventDefault(); this.hide();}, this);
      }
    }
    else
    {
      if(this.displayResponse(responseData, true))
      {
        this.registerForm();
      }
    }
  }
};



/*
 * PlaceholderInput
 *
 * Adapted from:
 * http://devthought.com/projects/mootools/placeholderinput/
 * Author: Guillermo Rauch
 * License: MIT-style license
 */

PMD.PlaceholderInput = function(el, txt, opts) {
  var Me = this;
  this.el = el;
  this.txt = txt;
  this._config(opts);
  
  YUI().use('node-base', 'node-style', 'event-base', 'event-focus', function(Y) { Y.on("domready", Me.init, Me, Y); });
};
PMD.PlaceholderInput._instances = [];
PMD.PlaceholderInput.findFor = function(el)
{
   var Y = YUI();
   var instances = PMD.PlaceholderInput._instances;
   for(var i=0; i<instances.length; i++)
   {
     if(instances[i].el._node === el._node) { return instances[i].obj; }
   }
   return null;
};
PMD.PlaceholderInput.prototype = {

  /** @var HTMLElement */
  el: null,

  /** @var string */
  txt: null,

  /** @var string */
  cssClass: 'placeholder',

  /** @var boolean */
  active: false,
  
  _config: PMD.lang.config,
  
  init: function(Y)
  {
    this.Y = Y;

    if(Y.Lang.isString(this.el))
    {
      this.el = Y.one("#" + this.el);
    }
    
    this.el.on('focus', this.focus, this);
    this.el.on('blur', this.blur, this);
    this.blur();
    
    // Store a reference to this placeholder so it can be found
    // using the PMD.PlaceholderInput.findFor() method.
    PMD.PlaceholderInput._instances.push({
       el: this.el,
       obj: this
    });
  },

  focus: function()
  {
    var txtValue = this.el.get('value');
    if(this.txt && txtValue == this.txt && this.active)
    {
      this.el.set('value', '');
      this.el.removeClass(this.cssClass);
      this.active = false;
    }
  },

  blur: function()
  {
    var txtValue = this.el.get('value');
    if(this.txt && (txtValue == '' || txtValue == this.txt))
    {
      this.el.addClass(this.cssClass);
      this.el.set('value', this.txt);
      this.active = true;
    }
  },
  
  externalValueChange: function()
  {
    var txtValue = this.el.get('value');
    if(this.txt && (txtValue == '' || txtValue == this.txt))
    {
       this.el.addClass(this.cssClass);
       this.el.set('value', this.txt);
       this.active = true;
    }
    else if(this.txt)
    {
       this.el.removeClass(this.cssClass);
       this.active = false;
    }
       
    
  },

  reset: function()
  {
    this.focus();
    this.blur();
    return this;
  }
};




PMD.NpiLookup = function(elNpi, opts) {
  var Me = this;
  this.el = elNpi;
  this._config(opts);
  
  YUI().use('node-base', 'node-style', 'node-event-simulate', 'io-base', 'event-base', 'event-focus', 'json-parse', function(Y) { Y.on("domready", Me.init, Me, Y); });
};

PMD.NpiLookup.prototype = {

  Y: null,
  
  /** @var HTMLElement */
  el: null,
  
  url: "/api/npi/-_npi_-.json",

  elLoading: null,

  fields: {},

  cache: {},
  
  lastLookup: null,

  _config: PMD.lang.config,
  
  init: function(Y)
  {
    this.Y = Y;

    if(Y.Lang.isString(this.el))
    {
      this.el = Y.one("#" + this.el);
    }
    
    if(Y.Lang.isString(this.elLoading))
    {
       this.elLoading = Y.one("#" + this.elLoading);
    }
    
    for (var key in this.fields)
    {
      if(Y.Lang.isString(this.fields[key]))
      {
        this.fields[key] = Y.one("#" + this.fields[key]);
      }
    }
    
    this.el.on('keyup', this.onUpdate, this);
    this.el.on('blur', this.onUpdate, this);
  },

  onUpdate: function()
  {
    var val = this.el.get('value');
    if(val.length != 10) return;
    if(val === this.lastLookup) return;
    this.lookup(val);
  },
  
  process: function(val, npiObj)
  {
    if(npiObj.entity_type == 2)
    {
       npiObj.fname = npiObj.authorized_fname;
       npiObj.mname = npiObj.authorized_mname;
       npiObj.lname = npiObj.authorized_lname;
    }
    
    for (var key in this.fields)
    {
      if(this.fields[key] && npiObj[key])
      {
        if(!this.fields[key].get('value') || this.fields[key].hasClass('placeholder'))
        {
           this.fields[key].set('value', npiObj[key]);
           if(PMD.PlaceholderInput.findFor)
           {
              var placeholder = PMD.PlaceholderInput.findFor(this.fields[key]);
              if(placeholder) placeholder.externalValueChange();
           }
        }
      }
    }
   
    //alert("NPI Lookup Result\n\nNPI #: "+npiObj.npi+"\nOrganization: "+npiObj.organization_name+"\nName: "+npiObj.fname+" "+npiObj.lname+" "+npiObj.suffix);
    this.hideLoading();
  },
  
  /**
   * Fetches the given NPI Number (from the local cache or via the API)
   * and calls process()
   */
  lookup: function(val)
  {
    this.showLoading();
    this.lastLookup = val;
    if(typeof this.cache[val] !== "undefined")
    {
      this.Y.later(0, this, this.process, [val, this.cache[val]], false);
      return;
    }
    
    var request = this.Y.io(this.url.replace('-_npi_-', val), {context: this, on: {
      failure: function(tId, response) {this.hideLoading(); },
      success: function(tId, response) {
        var Y = this.Y;
        var responseData;
        try
        {
           responseData = Y.JSON.parse(response.responseText);
        }
        catch (e)
        {
           this.hideLoading();
           return;
        }
        if(!Y.Lang.isObject(responseData) || responseData.npi != val) { this.hideLoading(); return; }
        
        this.cache[val] = responseData;
        this.process(val, responseData);
      }
    }});
    
  },
  
  showLoading: function()
  {
    if(this.elLoading)
    {
       this.elLoading.setStyle('visibility', 'visible');
    }
  },
  
  hideLoading: function()
  {
    if(this.elLoading)
    {
       this.elLoading.setStyle('visibility', 'hidden');
    }
  }

  
};


} // End this that require YUI
  
