/*!
 * Blast Mojo Framework
 *
 * Copyright (c) 2009, Blast Radius, Inc.
 * All rights reserved.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/* 
  Class: stdlib.behavior.DisableBoxBehavior
  Author: Jaime Bueza
  
  Provides functionality to disable parts of the UI or the whole UI
  with a loading screen. Developers may specifiy the throbber className
  if they wish, but by default the generated throbber className will be
  "throbber". To define its presentation, do the following:
  
  Example:
    (start code)

    #disablebox {
      background: transparent  url("../../img/global/bg-loading-throbber.png") center center no-repeat;
      _background: transparent  url("../../img/global/bg-loading-throbber.gif") center center no-repeat; 
      _background: none;
      text-align: center;
    }
    #disablebox .throbber {
      position: absolute;
      background: url("../../img/global/icon-loading-throbber.gif");
      width: 16px;
      height: 16px;
    }
    
    (end)
  
  Parameters:
    target - {HTMLElement} The target element you wish to disable
    show - {Boolean} Shows the disablebox on/off
    throbberClass - {String} The specific className of the throbber.
    
    
    
    
    
*/
dojo.provide("stdlib.behavior.DisableBoxBehavior");
dojo.require("mojo.command.Behavior");

dojo.declare("stdlib.behavior.DisableBoxBehavior", mojo.command.Behavior,
{
  _box: null,
  execute: function(requestObj) {
    var params = requestObj.getParams();
    if (!this._box) {
      this._box = mojo.queryFirst("#disablebox");
      if (!this._box) { //recovery + creation
        this._box = document.createElement("div");
        this._box.id = "disablebox";
        document.body.appendChild(this._box);
        this._box.style.position = "absolute";
      }
    }
    
    //Clean up
    this._box.innerHTML = "";

    if (requestObj.getParams().show) {
      var throbber = document.createElement("div");
      throbber.className = params.throbberClass || "throbber";
    
      if (requestObj.getParams().target) {
        var offset = dojo.coords(requestObj.getParams().target, true);
        this._box.style.top = offset.y + "px";
        this._box.style.left = offset.x + "px";
        this._box.style.width = offset.w + "px";
        this._box.style.height = offset.h + "px";
        
        //Shift up and left 8 px since the loader gif is 16x16. --- RBA only 24x24, so
        //we need to swap em for -12 instead of -8 -- TODO: FIX THIS FOR PARAMETER INSTEAD
        throbber.style.left = ((offset.w / 2) - 16) + "px";
        throbber.style.top = ((offset.h / 2)  - 16) + "px";
  
        this._box.appendChild(throbber);
        
        
      } else {
        var offset = {h:0,w:0};
        this._box.style.top = "0px";
        this._box.style.left = "0px";
        this._box.style.width = "100%";
        this._box.style.height = (document.all) ? document.body.offsetHeight + "px" : "100%";
        
        throbber.style.left = ((offset.w / 2) - 16) + "px";
        throbber.style.top = ((offset.h / 2)  - 16) + "px";
        
        this._box.appendChild(throbber);
      }
      this._box.style.zIndex = "9999";
      this._box.style.display = "block";
    } else {
      this._box.style.display = "none";
    }
  }
});

dojo.provide("stdlib.behavior.MessagingBehavior");
dojo.require("mojo.command.Behavior");

dojo.declare("stdlib.behavior.MessagingBehavior", mojo.command.Behavior, 
{
  execute: function(requestObj) {
    mojo.Messaging.publish(requestObj.paramsObj.topic, requestObj.paramsObj.message);
  }
});

/* 
  Class: stdlib.behavior.PreventDefaultEventBehavior
  Author: Steven Luscher, Chad Oakenfold
  
  Attempts to stop the default event
*/
dojo.provide("stdlib.behavior.PreventDefaultEventBehavior");
dojo.require("mojo.command.Command");
dojo.declare("stdlib.behavior.PreventDefaultEventBehavior", mojo.command.Command, 
{
  execute: function(requestObj) {
    /* Cancel the default event if possible */
    try { 
      var e = requestObj.eventObj;
      if (e["preventDefault"]) e.preventDefault();
      if (e["stopPropagation"]) e.stopPropagation();
      e.returnValue = false;
      return false;   
    } catch(e) {}
  }
});
dojo.provide("stdlib.behavior.RedirectBehavior");
dojo.require("mojo.command.Behavior");
dojo.declare("stdlib.behavior.RedirectBehavior", mojo.command.Behavior,
{
  execute: function(requestObj) {
    //If you pass don't pass a URL, it can be assumed
    //that you intend to refresh the current page.
    var params    = requestObj.getParams();
    var delay     = 25;
    if (params) {
      var url   = params.url; //Location of the redirect
      var removeHash  = params.removeHash || false; //If removeHash doesn't exist, then it's false.
      var delay   = params.delay || 25; //25ms redirect delay by default
    }
    if(!url) {
      //We want to refresh the page.
      if (removeHash) {
        window.location = window.location.href.replace(/#.*/, "");
        setTimeout ("window.location.reload()", 750); //Safari hack to reload
      } else {
        window.location.reload();
      }
    } else {
      //We want to redirect the user to a specific URL.
      setTimeout(function() {
        window.location.href = url;
      }, delay);

    }
  }
});


dojo.provide("stdlib.behavior.TweenBehavior");
dojo.require("mojo.command.Behavior");

dojo.declare("stdlib.behavior.TweenBehavior", mojo.command.Behavior,
{
  onComplete:function() {},
  onStart:function() {},
  _effect: null,
  execute: function(requestObj) {
    // element
    // width, height, x, y

    // set properties of animation
    var props = {}, speed;
    
    if (requestObj.getParams().width != null) props.width = requestObj.getParams().width;
    if (requestObj.getParams().height != null) props.height = requestObj.getParams().height;
    if (dojo.isIE && props.height == 0) props.height = 0;
    if (requestObj.getParams().x != null) props.left = requestObj.getParams().x;
    if (requestObj.getParams().y != null) props.top = requestObj.getParams().y;
    if (requestObj.getParams().speed != null) speed = requestObj.getParams().speed;
    
    // normalize elements into array
    var elements = requestObj.getParams().element;
    if (!dojo.isArray(elements)) {
      elements = [elements];
    }
    var elementLength = elements.length;

    var thisObj = this;
    for (var i = 0; i < elementLength; i++) {
      if (elements[i]) {
        var anim = dojo.anim(elements[i], props, speed);
        dojo.connect(anim, "onEnd", function(){
          thisObj.onComplete();
        });
        anim.play();
      }
    }
  }
});
dojo.provide("stdlib.behavior.UpdateCssClassBehavior");
dojo.require("mojo.command.Behavior");

dojo.declare("stdlib.behavior.UpdateCssClassBehavior", mojo.command.Behavior,
{
  execute: function(requestObj) {

// element - DOM element to apply CSS action to
// action - action to perform [add|remove|set|toggle]
// cssClass - CSS Class to apply action to

    if (!requestObj.paramsObj) return;
    var elmLength;                      // empty var which will be used to store the length of the array
    var elms = requestObj.paramsObj.element;        // gets the parameter "element" from the controller
    var action = requestObj.paramsObj.action;
    var cssClass = requestObj.paramsObj.cssClass;


    // ERROR CHECKING
    if (!elms) {
      return;
    } else {
      if (typeof elms == 'object') {
        //check array to see that all items are objects
        if (dojo.isArray(elms) && elms.length > 0) {
          for (var i=0; i< elms.length; i++) {
            if (typeof elms[i] != 'object') {
              throw new Error('ERROR stdlib.behavior.UpdateCssClassBehavior - element parameter is not an array of type Object');
              break;
            }
          }
        }
      } else {
        throw new Error('ERROR stdlib.behavior.UpdateCssClassBehavior - element parameter is not a type Object');
      }
    }

    if (action == null || typeof action == 'undefined') {
      throw new Error('ERROR stdlib.behavior.UpdateCssClassBehavior - action parameter is required');
    } else {
      if (typeof action != 'string') {
        throw new Error('ERROR stdlib.behavior.UpdateCssClassBehavior - action parameter is not a type String');
      } else {
        if ((action != 'add') && (action != 'remove') && (action != 'set') && (action != 'toggle')) throw new Error('ERROR stdlib.behavior.UpdateCssClassBehavior - action parameter is invalid');
      }
    }

    if (cssClass == null || typeof cssClass == 'undefined') {
      throw new Error('ERROR stdlib.behavior.UpdateCssClassBehavior - CssClass parameter is required');
    } else {
      if (typeof cssClass == 'object') {
        //check array to see that all items are objects
        if (cssClass.length > 0) {
          for (var i=0; i< cssClass.length; i++) {
            if (typeof cssClass[i] != 'string') {
              throw new Error('ERROR stdlib.behavior.UpdateCssClassBehavior - CssClass parameter is not an array of type String');
              break;
            }
          }
        }
      } else {
        if (typeof cssClass != 'string') throw new Error('ERROR stdlib.behavior.UpdateCssClassBehavior - CssClass parameter is not a type String');
      }
    }



// checks to see that an element has been passed
    if (elms) {

// helper function. checks to see if the elms variable is an array.
      var isArray = function(srcObj) {
        if (!srcObj.constructor || srcObj.constructor.toString().toLowerCase().indexOf("array") == -1) return false;
        return true;
      };


// if elms is not an array, make it an array
      if (!isArray(elms)) elms = [elms];

// if cssClass is not an array, make it an array
      if (!isArray(cssClass)) cssClass = [cssClass];

// gets the length of the cssClass array for performance issues
      cssLength = cssClass.length;

// gets the length of the elms array for performance issues
      elmLength = elms.length;

// loops through the elements
      for (var i = 0; i < elmLength; i++) {
        elm = elms[i];
        // loops through the css classes
        for (var j = 0; j < cssLength; j++) {
          css = cssClass[j];
          // perform the CSS action
          if (action.length > 0){
            // just a nicer way of doing an If/Else
            switch(action) {
              case "add" :
                dojo.addClass(elm, css);
                break;
              case "remove" :
                dojo.removeClass(elm, css);
                break;
              case "set" :
                elm.className = "";
                dojo.addClass(elm, css);
                break;
              case "toggle" :
                dojo.toggleClass(elm, css);
                break;
            }
          }
        }
      }
    }
  },
  onResponse: function() {
  }
});
dojo.provide("stdlib.behavior.UpdateFormFieldBehavior");
dojo.require("mojo.command.Behavior");

dojo.declare("stdlib.behavior.UpdateFormFieldBehavior", mojo.command.Behavior, {
  execute: function(requestObj) {
    // this behavior will iterate thru a targeted form and assign "values" to
    // the appropriate form elements based on the element's "name"
    var formObj;
    var formChildren = new Array();
    var formArray = new Array();
    var formHTMLElements = ["INPUT", "SELECT", "TEXTAREA"]; // these are the valid form elements
    var params = requestObj.getParams();
    if (!params) params = {};
    var fields = params.fields; // 'fields' is an array of json objects that represent form input fields
    if (params.formId != null) formObj = mojo.queryFirst("#" + params.formId);
    if (params.formObj != null) formObj = params.formObj;

    if (formObj) {
      // getting the appropriate objects in the form
      for (var i = 0, iLen = formHTMLElements.length; i < iLen; i++) {
        var HTMLobj = mojo.query(formHTMLElements[i], formObj);

        for (var j = 0, jLen = HTMLobj.length; j < jLen; j++) {
          formChildren.push(HTMLobj[j]);
        }
      }

      // check fields and assign values
      for (var i = 0, iLen = fields.length; i < iLen; i++) {
        var objName = fields[i].name;
        var objValue = fields[i].value;
        for (var j = 0, jLen = formChildren.length; j < jLen; j++) {
          var fireOnChange = false;
        
          // fire onchange if values are different
//          if ((formChildren[j].tagName == "INPUT")&&(formChildren[j].value != objValue)) {
//            fireOnChange = true;
//          }

          if (formChildren[j].tagName == "SELECT") {
            if (formChildren[j].name == objName) {
              for (var k = 0, kLen = formChildren[j].options.length; k < kLen; k++) {
                var o = formChildren[j].options[k];
                if (o.value == objValue) formChildren[j].selectedIndex = k;
              }
            }
          } else if (formChildren[j].tagName == "TEXTAREA") {
            if (formChildren[j].name == objName) {
              if (formChildren[j].value == objValue) fireOnChange = true; //PC FF needs this
              if (formChildren[j].innerHTML == objValue) fireOnChange = true;
              formChildren[j].value = objValue; // PC FF needs this
              formChildren[j].innerHTML = objValue;
            }
          } else if (formChildren[j].tagName == "INPUT") {
            if (formChildren[j].name == objName) {
              if ((formChildren[j].type == "radio")||(formChildren[j].type == "checkbox")) {
                if (formChildren[j].value == objValue) {
                  formChildren[j].checked = "checked";
                } else {
                  formChildren[j].checked = "";
                }
              } else if ((formChildren[j].type == "text")||(formChildren[j].type == "password")||(formChildren[j].type == "hidden")) {
                if (formChildren[j].value != objValue) fireOnChange = true;
                formChildren[j].value = objValue;
              }
            }
          }

          if (fireOnChange) {
            //On IE
            if (formChildren[j].fireEvent) formChildren[j].fireEvent("onchange");

            //On Gecko based browsers
            if (document.createEvent) {
              var evt = document.createEvent("HTMLEvents");
              if(evt.initEvent) evt.initEvent("change", true, true);
              if(formChildren[j].dispatchEvent) formChildren[j].dispatchEvent(evt);
            }
          }

        }
      }


    }
  }
});
dojo.provide("stdlib.behavior.dialog.DialogBehavior");
dojo.require("mojo.command.Behavior");
dojo.declare("stdlib.behavior.dialog.DialogBehavior", mojo.command.Behavior, 
{
  _context: null,
  onClose: function() {
    mojo.Messaging.publish("dialog/close");
  },
  onComplete: function() {
    mojo.Messaging.publish("dialog/complete");
  },
  execute: function(requestObj) {
    //You may choose to pass in an ID or an HREF, if you pass in an
    //HREF, the dialog will fetch the content via xhr, else it grabs
    //the element's inner HTML of the specific ID, and shoves it into
    //the div.dialog's innerHTML.
    
    //Parameters
    // enabled: Boolean
    // width: Number
    // height: Number

    
    var params = requestObj.getParams();
    
    //Find the Underlay
    if(!dojo.isIE) {
      var underlay = mojo.queryFirst("#underlay");
      if(!underlay) {
        underlay = document.createElement("div");
        underlay.id = "underlay";
        document.body.appendChild(underlay);
      }
    }

    
    var container = mojo.queryFirst(".dialog-component");
    
    var thisObj = this;

    if (params.enabled) {
      
      if(params.href) {
        if(!params.cache) {
          params.href = params.href + "?nocache=" + new Date().getTime();
        }
        
        dojo.xhrGet({
          url: params.href,
          load: function(data) {
            var content = mojo.queryFirst(".dialog-content", container); //mojo.queryFirst(params.elContent, params.elContainer);
            
            content.innerHTML = data;
            
            //WTF dojo is buggy, can't change styles
            if (!dojo.isIE) {
              dojo.anim(underlay, { opacity: '.9', duration: 350, onEnd: function() {
                  dojo.style(underlay, 'display', 'block');
                }
              });
            }
            dojo.style(container, 'display', 'block');
            
            thisObj.onComplete();
            
          }
        });
      } 
      
      
    } else {      
      if(!dojo.isIE) {
        var dialogCloseAnimation = dojo.anim(underlay, { 'opacity': 0 }, 350);
        dojo.connect(dialogCloseAnimation, 'onEnd', function() {
          dojo.style(underlay, 'display', 'none');
        });
        dialogCloseAnimation.play();
      }     
      dojo.style(container, 'display', 'none'); 
      this.onClose();
    }
  }
});
/* 
  Class: EscapeKeyBehavior
  
  Provides functionality for intercepting the Escape (ESC) keystroke. 
  
  Note:
    Perhaps this can be deprecated and we can have a generalized "KeyBehavior" 
    in stdlib, where you pass in an array of keystrokes to intercept.
*/
dojo.provide("stdlib.behavior.dialog.EscapeKeyBehavior");
dojo.require("mojo.command.Behavior");

dojo.declare("stdlib.behavior.dialog.EscapeKeyBehavior", mojo.command.Behavior,
{
  execute: function(requestObj) {
    var e = requestObj.eventObj;
    var characterCode;
    if(e && e.which){
      e = e
      characterCode = e.which;
    } else{
      e = event
      characterCode = e.keyCode;
    }
    if(characterCode == 27){
      this.onResponse();
      return false 
    } else{
      return true 
    }
  },
  onResponse: function() {
  }
});
/*
  Class: PositionBehavior
  
*/
dojo.provide("stdlib.behavior.dialog.PositionBehavior");
dojo.require("mojo.command.Behavior");
dojo.declare("stdlib.behavior.dialog.PositionBehavior", mojo.command.Behavior, 
{
  execute: function(requestObj) {

    var params = requestObj.getParams();
    var underlay = mojo.queryFirst("#underlay");
    var container = mojo.queryFirst(".dialog-component");
    var content = mojo.queryFirst(".dialog-component .dialog-component-content");
    
    if(!container || !underlay || !content) {
      return;
    }

    var windowDimensions = {};
    var scrollPosition = 0;
    // the more standards compliant browsers (mozilla/netscape/opera/IE7) use window.innerWidth and window.innerHeight
    if (typeof window.innerWidth != 'undefined') {
        windowDimensions.w = window.innerWidth;
        windowDimensions.h = window.innerHeight;
      scrollPosition = window.scrollY + window.innerHeight;
    }
    // IE6 in standards compliant mode (i.e. with a valid doctype as the first line in the document)
    else if (typeof document.documentElement != 'undefined' && typeof document.documentElement.clientWidth != 'undefined' && document.documentElement.clientWidth != 0) {
        windowDimensions.w = document.documentElement.clientWidth,
        windowDimensions.h = document.documentElement.clientHeight;
      scrollPosition = /* (dojo.coords(mojo.queryFirst("body"), true)).h */ document.documentElement.scrollTop + document.documentElement.clientHeight;
    } else {
      windowDimensions.w = document.body.clientWidth;
      windowDimensions.h = document.body.clientHeight;
      scrollPosition = document.body.scrollTop + document.body.clientHeight;
    }

    //Remodulate the underlay dimensions.
    underlay.style.width = windowDimensions.w + "px"; 
    underlay.style.height = (dojo.coords(mojo.queryFirst("body"), true)).h /* windowDimensions.h */ + "px";

    //Remodulate the Dialog container dimensions.
    var containerCoords = dojo.coords(container, true);
    var contentCoords = dojo.coords(content, true);
    
    var centerY = Math.round(scrollPosition - (windowDimensions.h / 2)  - (containerCoords.h / 2));
    var centerX = Math.round((windowDimensions.w / 2) - (containerCoords.w / 2));

    container.style.top = centerY + "px";
    container.style.left = centerX + "px";
    
  }
});
dojo.provide("stdlib.command.AutoSuggest.GetSuggestionsCommand");
dojo.require("mojo.command.Command");
//dojo.require("mojo.Model");

dojo.declare("stdlib.command.AutoSuggest.GetSuggestionsCommand", mojo.command.Command, {
  query: null,
  _clearTimeout: null,
  _lastValue: null,
  execute: function(requestObj) {
    if (requestObj.getParams().query != this.query) {
      this.query = requestObj.getParams().query.replace(/\s*$/g, ""); // get rid of trailing spaces
      clearTimeout(this._clearTimeout);
      if (this.query.length > 0) { // handle empty
        var thisObj = this;
        dojo.require(requestObj.getParams().serviceLocator);
        this._clearTimeout = setTimeout(function() {
          if (thisObj._lastValue != thisObj.query) {
            thisObj._lastValue = thisObj.query;
            var locator = eval(requestObj.getParams().serviceLocator);
            locator.getInstance().getService(requestObj.getParams().serviceName).invoke({query: thisObj.query}, thisObj);
          }
        }, 400);
      } else {
        mojo.Model.remove(requestObj.getParams().model);
      }
    } 
  },
  onResponse: function(data) {
    var modelPath = (this.getRequest().getParams().modelPath) ? "." + this.getRequest().getParams().modelPath : "";
    mojo.Model.set(this.getRequest().getParams().model, eval("data" + modelPath));
  },
  onError: function(error) {
  }
});

/* 
  Class: stdlib.command.GenericServiceCommand
  Author: Jaime Bueza
  
  Provides a generic command that can be used against a service.
  
  Parameters:
    serviceName - {String}
    serviceLocator - {String}
    serviceParams - {Object}
    model - {String}
    
  Example:
    (start code)
      this.addObserver("a.login", "onclick", "GenericServiceCommand", function(context, caller) {
        return {
          serviceName: "LoginService",
          serviceLocator: "app.service.Locator",
          serviceParams: {
            username: mojo.queryFirst("input[name='username']", context).value,
            password: mojo.queryFirst("input[name='password']", context).value
          },
          model: "member.login"
        };
      });
    (end)
*/
dojo.provide("stdlib.command.GenericServiceCommand");
dojo.require("mojo.command.Command");
dojo.declare("stdlib.command.GenericServiceCommand", mojo.command.Command, {
  _model: null,
  execute: function(requestObj) {
    var params = requestObj.getParams();
    //Warn the developer if we're not passing any parameters to the Generic Service Command.
    if(!params) {
      console.log("stdlib.command.GenericServiceCommand - Warning - No params passed.");
    }
    
    //Set the command's model so that we can access the reference in the onResponse/onError events.
    this._model = params.model;
    //Fetch the application specific service locator.
    dojo.require(params.serviceLocator);
    //Invoke the service
    (eval(params.serviceLocator)).getInstance().getService(params.serviceName).invoke(params.serviceParams, this);
  },
  onResponse: function(data) {
    if(this._model) mojo.Model.set(this._model, data); //If we have a model to set, then we can set it here.
  },
  onError: function(errors) {
    if(this._model) mojo.Model.set(this._model + ".errors", errors);
  }
});

dojo.provide("stdlib.command.MapControllersCommand");
dojo.require("mojo.command.Command");

dojo.declare("stdlib.command.MapControllersCommand", mojo.command.Command, {
  execute: function(requestObj) {
    
    var contextObj = null;
    if(requestObj.getParams()) {
      
      // parameters: contextObj: String or HTMLElement
      contextObj = requestObj.getParams().contextObj;
    }
    
    mojo.controller.Map.mapControllers(contextObj);
    

    
  }
});

dojo.provide("stdlib.command.UpdateControllerParamCommand");
dojo.require("mojo.command.Command");

dojo.declare("stdlib.command.UpdateControllerParamCommand", mojo.command.Command, {
  execute: function(requestObj) {
    var __elm;
    var __control;
    var __parameter;
    var __value;

    var params = requestObj.getParams();
    if (params) {
      if (params.element != null) __elm = params.element;
      if (params.control != null) __control = params.control;
      if (params.params != null) __parameter = params.params;
      if (params.value != null) __value = params.value;
    }

    try {
      if ((__control!=null)&&(__parameter!=null)&&(__value!=null)) {
        if (__elm) {
          __elm.mojoControllers[__control].setValue(__parameter, __value);
        } else {
          requestObj.getController().getContextController(__control).setValue(__parameter, __value);
        }
      }
    } catch(err) {}

    
  },

  onResponse: function() {
  },

  onError: function() {
  }
});
dojo.provide("stdlib.command.UpdateObserversCommand");
dojo.require("mojo.controller.Controller");
dojo.require("mojo.command.Command");

dojo.declare("stdlib.command.UpdateObserversCommand", mojo.command.Command, {
  execute: function(requestObj) {
    var timeout = setTimeout(function() {
      mojo.controller.Controller.updateObservers(requestObj.getParams().controllerName);
      clearTimeout(timeout);
    }, 20);
    
    
  }
});
dojo.provide("stdlib.command.ValidateRulesCommand");
dojo.require("mojo.command.Command");
dojo.require("mojo.helper.Validation");
//dojo.require("mojo.helper.view.Error");
dojo.require("mojo.query");

dojo.declare("stdlib.command.ValidateRulesCommand", mojo.command.Command, {
  _targetElement: null, // error messages will appear INSIDE the target (container) element
  _checkAll: true,
  _output: function(errorList, targetElement) {
    
  },
  execute: function(requestObj) {

    var rules;
    var formSet;
    var params = requestObj.getParams();
    if (params) {
      if (params.targetElement != null) this._targetElement = params.targetElement;
      if (params.checkAll != null) this._checkAll = params.checkAll;
      if (params.rules != null) rules = params.rules;
      if (params.formSet != null) formSet = params.formSet;
    }

    if (rules) {
      
      if (this._targetElement != null) {
        this._targetElement.innerHTML = "";
        if (formSet) {
          var clearTags = ["label","inputs","textarea","select"];
          for (var i = 0; i < clearTags.length; i++) {
            var Tag = mojo.query(clearTags[i], formSet);
            for (var j = 0; j < Tag.length; j++) {
              dojo.removeClass(Tag[j], "error");
            }
          }
        }
      }
      if (typeof(rules) == "string") {
        dojo.require(rules);
        eval("requestObj.getParams().rules = " + rules);
      }
      var val = mojo.helper.Validation.getInstance();
      if ((formSet)&&(this._checkAll)) {
        var errorList = val.execute(requestObj.getParams().rules, formSet);
      } else {
        var errorList = val.execute(requestObj.getParams().rules, [requestObj.callerObj]);

      }
      
      if (errorList.length > 0) {
        if (this._targetElement != null) {
          mojo.helper.view.Error.showElementErrors(errorList, this._targetElement);
          for (var i=0; i<errorList.length; i++) {
            dojo.addClass(errorList[i].element, "error");
            if (errorList[i].element.parentNode.tagName == "LABEL") dojo.addClass(errorList[i].element.parentNode, "error");
          }
        } else {
        //  mojo.helper.view.Error.showElementErrors(errorList)
          for (var i = 0, len = errorList.length; i < len; i++) {
            var error = errorList[i];
            var err = document.createElement("span");
            err.className = "mojoValidationError";
            err.innerHTML = error.message;

            if(error.element.type == "checkbox") {
              if(error.element.parentNode.tagName == "LABEL") {
                dojo.place(err, error.element.parentNode, 'after');
              } else {
                dojo.place(err, error.element, 'after');
              }
            } else {
              dojo.place(err, error.element, 'after');
            }

            
          }
        }
        this.onError();
      } else if (requestObj.invocation) {
        this.onResponse();
        requestObj.invocation.proceed();
      }
    } else {
      console.debug("ERROR stdlib.command.ValidateRulesCommand - No rules passed");
    }
  },
  onResponse: function() {
    if(this._targetElement.style.display != "none") this._targetElement.style.display = "none";
    
  },
  onError: function() {
    if(this._targetElement.style.display != "block") this._targetElement.style.display = "block";
    
  }
});

dojo.provide("stdlib.controller.AccordionController");
dojo.require("mojo.controller.Controller");

dojo.declare("stdlib.controller.AccordionController", mojo.controller.Controller, 
{
  params: {
    selectedIndex: {
      required: false,
      defaultValue: 0,
      type: Number
    },
    activeOn: {
      required: false,
      defaultValue: "onclick"
    },
    toggleClose: {
      required: false,
      defaultValue: false
    },
    direction: {
      required: false,
      defaultValue: "vertical"
    }
  },
  addObservers: function() {
    var accordionPanels = mojo.query("> .accordion-panel", this.getContextElement());
    var accordions = mojo.query("> .accordion-panel > .accordion", this.getContextElement());
    var accordionContents = mojo.query("> .accordion-panel > .accordion-content", this.getContextElement());
    
    this.addObserver("> .accordion-panel > .accordion", this.getValue("activeOn"), "UpdateClass", function(context, caller) { 
      var tabs = accordions;
      var index = 0;
      for (var i = 0; i < tabs.length; i++) {
        if (tabs[i] == caller) {
          index = i;
          break;
        }
      }
      if (this.getController().getValue("toggleClose") && index == this.getController().getValue("selectedIndex")) {
        this.getController().setValue("selectedIndex", -1);
      } else {
        this.getController().setValue("selectedIndex", index);
      }
    });
    this.addObserver(this.getConfig("params").selectedIndex, "onChange", "Tween", function(context, caller, controller) {   
      return {
        height: (controller.getValue("direction") == "vertical") ? 0 : null,
        width: (controller.getValue("direction") == "horizontal") ? 0 : null,
        element: mojo.query("> .open > .accordion-content", context),
        speed: 200
      };
    });
    this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateClass", function(context, caller) { return {
      element: accordionPanels,
      action: "remove",
      cssClass: "open"
    }});
    this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateClass", function(context, caller) { return {
      element: accordionPanels[caller.getValue()],
      action: "add",
      cssClass: "open"
    }});
    this.addObserver(this.getConfig("params").selectedIndex, "onChange", "Tween", function(context, caller, controller) {
      var elm = accordionContents[caller.getValue()];
      if (!elm) return;
      return {
        speed: 200,
        element: elm,
        height: (controller.getValue("direction") == "vertical") ? elm.scrollHeight : null,
        width: (controller.getValue("direction") == "horizontal") ? elm.scrollWidth : null
      };
    });  
  },
  addCommands: function() {
    this.addCommand("UpdateClass", "stdlib.behavior.UpdateCssClassBehavior");
    this.addCommand("Tween", "stdlib.behavior.TweenBehavior");
  },
  addIntercepts: function() {

  }
});
dojo.provide("stdlib.controller.AutoSuggestController");
dojo.require("mojo.controller.Controller");

dojo.declare("stdlib.controller.AutoSuggestController", mojo.controller.Controller, 
{
  params: {
    model: {
      required: false,
      defaultValue: "suggestions"
    },
    modelPath: {
      required: false,
      defaultValue: "suggestions"
    },
    serviceLocator: {
      required: true,
      defaultValue: "sample.service.Locator"
    },
    serviceName: {
      required: false,
      defaultValue: "getSuggestions"
    },
    inputName: {
      required: false,
      defaultValue: "suggest-input"
    }
  },
  addObservers: function() {
    this.addObserver("input.suggest-input", "onkeyup", "GetSuggestions", function(context, caller) { return {
      query: caller.value,
      model: this.getController().getValue("model"),
      modelPath: this.getController().getValue("modelPath"),
      serviceLocator: this.getController().getValue("serviceLocator"),
      serviceName: this.getController().getValue("serviceName")
    };});
    this.addObserver("input.suggest-input", "onkeydown", "SuggestNavigation", function(context, caller) { return {
      suggestions: mojo.query(".suggestion", context)
    };});
    this.addObserver(this.getCommand("SuggestNavigation"), "onNav", "UpdateClass", function(context, caller) { return {
      element: mojo.query(".suggestion", context),
      action: "remove",
      cssClass: "selected"
    };});
    this.addObserver(this.getCommand("SuggestNavigation"), "onNav", "UpdateClass", function(context, caller) { return {
      element: caller.suggestion,
      action: "add",
      cssClass: "selected"
    };});
    this.addObserver(this.getCommand("SuggestNavigation"), "onNav", "UpdateForm", function(context, caller) {                                                                          
      return {
        formObj: context,
        fields: [{
          name: this.getController().getValue("inputName"),
          value: (caller.suggestion.innerHTML.split("\n")[0] || caller.suggestion.innerHTML.split("\n")[1]).replace(/\s*\<[^\>]+\>\s*/g, "")
        }]
      };
    });
    this.addObserver(".suggestion", "onmouseover", "UpdateForm", function(context, caller) { return {
      formObj: context,
      fields: [{
        name: this.getController().getValue("inputName"),
        value: (caller.innerHTML.split("\n")[0] || caller.innerHTML.split("\n")[1]).replace(/\s*\<[^\>]+\>\s*/g, "")
      }]
    };});
    this.addObserver(".suggestion", "onmouseover", "UpdateClass", function(context, caller) { return {
      element: caller, 
      action: "add",
      cssClass: "selected"
    };});
    this.addObserver(".suggestion", "onmouseout", "UpdateClass", function(context, caller) { return {
      element: caller,
      action: "remove",
      cssClass: "selected"
    };});
    this.addObserver("input.suggest-input", "onblur", "ClearModel", function(context, caller) { return {
      model: this.getController().getValue("model")
    };});
  },
  addCommands: function() {
    this.addCommand("SuggestNavigation", "stdlib.behavior.AutoSuggest.SuggestNavigationBehavior");
    this.addCommand("UpdateClass",  "stdlib.behavior.UpdateCssClassBehavior");
    this.addCommand("GetSuggestions", "stdlib.command.AutoSuggest.GetSuggestionsCommand");
    this.addCommand("ClearModel", "stdlib.command.ClearModelCommand");
    this.addCommand("UpdateForm", "stdlib.behavior.UpdateFormFieldBehavior");
  },
  addIntercepts: function() {

  }
});

dojo.provide("stdlib.controller.FilmStripController");
dojo.require("mojo.controller.Controller");

dojo.declare("stdlib.controller.FilmStripController", mojo.controller.Controller, 
{
  params: {
    selectedIndex: {
      required: false,
      defaultValue: 0,
      type: Number
    },
    loop: {
      required: false,
      defaultValue: false,
      type: Boolean
    }
  },
  addObservers: function() {
    var pages = function(context) {
      return mojo.query("> .filmstrip-viewer > .filmstrip-content > .filmstrip-page", context);
    };
    this.addObserver("> .filmstrip-next", "onclick", "UpdateClass", function(context, caller) { 
      var tabs = pages(context);
      var index = this.getController().getValue("selectedIndex");
      index++;
      if (index >= pages(context).length) {
        if (this.getController().getValue("loop")) {
          this.getController().setValue("selectedIndex", 0);
        }
      } else {
        this.getController().setValue("selectedIndex", index);
      }
    });
    this.addObserver("> .filmstrip-prev", "onclick", "UpdateClass", function(context, caller) { 
      var tabs = pages(context);
      var index = this.getController().getValue("selectedIndex");
      index--;
      if (index < 0) {
        if (this.getController().getValue("loop")) {
          this.getController().setValue("selectedIndex", pages(context).length-1);
        }
      } else {
        this.getController().setValue("selectedIndex", index);
      }
    });
    this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateClass", function(context, caller, controller) { return {
          element: mojo.query("> .filmstrip-next", context),
          action: (caller.getValue() >= pages(context).length-1) ? "add" : "remove",
          cssClass: "disabled"
    }});
    this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateClass", function(context, caller, controller) { return {
          element: mojo.query("> .filmstrip-prev", context),
          action: (caller.getValue() <= 0) ? "add" : "remove",
          cssClass: "disabled"
    }});
    this.addObserver(this.getConfig("params").selectedIndex, "onChange", "Tween", function(context, caller, controller) { return {
      x: (-1*pages(context)[caller.getValue()].offsetLeft),
      y: (-1*pages(context)[caller.getValue()].offsetTop),
      element: mojo.query("> .filmstrip-viewer > .filmstrip-content", context)
    }});
    this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateClass", function(context, caller) { return {
      element: pages(context),
      action: "remove",
      cssClass: "selected"
    }});
    this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateClass", function(context, caller) { return {
      element: pages(context)[caller.getValue()],
      action: "add",
      cssClass: "selected"
    }});
  },
  addCommands: function() {
    this.addCommand("UpdateClass", "stdlib.behavior.UpdateCssClassBehavior");
    this.addCommand("Tween", "stdlib.behavior.TweenBehavior");
  },
  addIntercepts: function() {

  }
});
dojo.provide("stdlib.controller.FormController");
dojo.require("mojo.controller.Controller");
dojo.declare("stdlib.controller.FormController", mojo.controller.Controller, 
{
  params: {
    isSubmitted: {
      required: false,
      defaultValue: false,
      type: Boolean
    },
    formSubmitCommand: {
      required: true,
      defaultValue: "FormSubmitCommand",
      type: String
    },
    formRules: {
      required: true,
      defaultValue: "stdlib.rules.Rules",
      type: String
    },
    modelErrors: {
      required: false,
      defaultValue: "stdlib.myModel",
      type: String
    },
    formId: {
      required: true,
      defaultValue: "#form",
      type: String
    },
    submitButtonId: {
      required: true,
      defaultValue: "#submit-form",
      type: String
    },
    cancelButtonId: {
      required: false,
      defaultValue: "#cancel-form",
      type: String
    }
  },
  addObservers: function() {
    //Parameters
    var rules = this.getValue("formRules"),
      errorsModel = this.getValue("modelErrors"),
      formId = this.getValue("formId");
    

    //Tooltips
    /*
    this.addObserver("span.info", "onmouseover", "ToolTip", function() { return { show: true }});
    this.addObserver("span.info", "onmouseout", "ToolTip", function() { return { show: false }});
    */
    
    //Handles all "Enter" key submits.
    this.addObserver("input", "onkeydown", "EnterKey"); 
    
    //Handles onblur validation only if the user has clicked "submit", but has errors in it.
    this.addObserver("input", "onblur", "ValidateRules", function(context, caller) {
      if(!this.getController().getValue("isSubmitted")) return { rules: {}, formSet: mojo.query(formId)};
      return {
        rules: rules,
        formSet: mojo.query(formId)
      }
    });
    this.addObserver("textarea", "onblur", "ValidateRules", function(context, caller) {
      if(!this.getController().getValue("isSubmitted")) return { rules: {}, formSet: mojo.query(formId)};
      return {
        rules: rules,
        formSet: mojo.query(formId)
      }
    });
    this.addObserver("select", "onchange", "ValidateRules", function(context, caller) {
      if(!this.getController().getValue("isSubmitted")) return { rules: {}, formSet: mojo.query(formId)};
      return {
        rules: rules,
        formSet: mojo.query(formId)
      }
    });

    //Handles form submission.
    /*
    this.addObserver(this.getCommand(this.getValue("formSubmitCommand")), "onError", "DisableBox", function(context, caller) { 
      return { 
        target: context, show: false
      }
    });*/
    this.addObserver(this.getCommand(this.getValue("formSubmitCommand")), "onResponse", "ClearModel", function() { 
      return { 
        model: errorsModel 
      }
    });
    /*
    this.addObserver(this.getCommand(this.getValue("formSubmitCommand")), "onResponse", "DisableBox", function(context, caller) { 
      return { 
        target: context, show: false
      }
    });*/

    //Add an observer to the onclick of Submit to update the Controller's parameters for isSubmitted = true.
    this.addObserver(this.getValue("submitButtonId"), "onclick", "UpdateControllerParam", function(context, caller, controller) {
      
      return {
        control: this.getController().declaredClass,
        params: "isSubmitted", 
        value: true, 
        element: context
      }
    });
    
    //Re-run ValidateRules when isSubmitted changes values. 
    this.addObserver(this.getConfig("params").isSubmitted, "onChange", "ValidateRules", function(context, caller) {
      if(!this.getController().getValue("isSubmitted")) return { rules: {}, formSet: mojo.query(formId)};
      return {
        rules: rules, 
        formSet: mojo.query(formId)
      }
    });
    
    /*
    //Cancel Button
    this.addObserver(this.getValue("cancelButtonId"), "onclick", "ClearErrors", function(context, caller) { 
      return { 
        className: ".mojoValidationError", 
        targetId: this.getController().getValue("formId")
      }
    });
    */
    this.addObserver(this.getValue("cancelButtonId"), "onclick", "ClearForm", function(context, caller) {
      return {
        formSet: mojo.queryFirst(this.getController().getValue("formId"),context)
      }
    });
    /*
    //Show DisableBox if we pass Validation.
    this.addObserver(this.getCommand("ValidateRules"), "onResponse", "DisableBox", function(context, caller) {
      return { 
        target: context, 
        show: true 
      }
    });*/
  },
  addCommands: function() { 
    //Add pre-made commands to automatically handle the following:
      //Messaging
      //EnterKey
      //UpdateControllerParam
      //DisableBox
      //ClearForm
      //ClearErrors
      //ClearModel
      //Refresh
      //ToolTip
      //Validate
      //DATA COMMANd
    this.addCommand("Messaging",        "stdlib.behavior.MessagingBehavior"); 
    this.addCommand("EnterKey",         "stdlib.behavior.EnterKeyBehavior");
    this.addCommand("UpdateControllerParam",  "stdlib.command.UpdateControllerParamCommand");
    this.addCommand("DisableBox",       "stdlib.behavior.DisableBoxBehavior");
    this.addCommand("ClearForm",        "stdlib.behavior.ClearFormBehavior");
/*    this.addCommand("ClearErrors",        "stdlib.command.RemoveObjectsCommand"); */
    this.addCommand("ClearModel",       "stdlib.command.ClearModelCommand");
    this.addCommand("Redirect",           "stdlib.behavior.RedirectBehavior");
/*    this.addCommand("ToolTip",          "stdlib.behavior.ToolTipBehavior"); */
    this.addCommand("ValidateRules",      "stdlib.command.ValidateRulesCommand");
  },
  addIntercepts: function() {
    this.addIntercept("around", this.getValue("formSubmitCommand"), "ValidateRules", { rules: this.getValue("formRules"), formSet: mojo.query(this.getValue("formId")) });
  }
});
dojo.provide("stdlib.controller.FormValidationController");
dojo.require("mojo.controller.Controller");
dojo.declare("stdlib.controller.FormValidationController", mojo.controller.Controller, 
{
  params: {
    isSubmitted: {
      required: false,
      defaultValue: false,
      type: Boolean
    },
    formRules: {
      required: true,
      defaultValue: "stdlib.rules.Rules",
      type: String
    },
    submitButtonId: {
      required: true,
      defaultValue: "#submit-form",
      type: String
    },
    cancelButtonId: {
      required: false,
      defaultValue: "#cancel-form",
      type: String
    },
    errorsContainerId: {
      required: false,
      defaultValue: "",
      type: String
    },
    showDisableBox: {
      required: false,
      defaultValue: true
    }
  },
  addObservers: function() {
    var formRules = this.getValue("formRules");
    var targetElement = (this.getValue("errorsContainerId") != "") ? mojo.queryFirst(this.getValue("errorsContainerId")) : null;
    
  
    //Handles all "Enter" key submits.
    this.addObserver("input", "onkeydown", "EnterKey");
    this.addObserver(this.getCommand("EnterKey"), "onResponse", "UpdateControllerParam", function(context, caller) {
      return {
        control: this.getController().declaredClass,
        params: "isSubmitted", 
        value: true, 
        element: context
      }
    });
    this.addObserver(this.getCommand("EnterKey"), "onResponse", "SubmitForm", function(context, caller) {
      return {
        form: this.getContextElement()
      }
    });
    
    //Handles onblur validation only if the user has clicked "submit", but has errors in it.
    this.addObserver(["input", "textarea"], "onblur", "ValidateRules", function(context, caller) {
      if(!this.getController().getValue("isSubmitted")) return { rules: {}, formSet: this.getContextElement()};
      return {
        rules: formRules,
        formSet: this.getContextElement(),
        targetElement: targetElement
      }
    });
    this.addObserver("select", "onchange", "ValidateRules", function(context, caller) {
      if(!this.getController().getValue("isSubmitted")) return { rules: {}, formSet: this.getContextElement()};
      return {
        rules: formRules,
        formSet: this.getContextElement(),
        targetElement: targetElement
      }
    });

    //Add an observer to the onclick of Submit to update the Controller's parameters for isSubmitted = true.
    this.addObserver(this.getValue("submitButtonId"), "onclick", "UpdateControllerParam", function(context, caller) {
      return {
        control: this.getController().declaredClass,
        params: "isSubmitted", 
        value: true, 
        element: context
      }
    });
    this.addObserver(this.getValue("submitButtonId"), "onclick", "SubmitForm", function(context, caller) {
      return {
        form: this.getContextElement()
      }
    });
    
    this.addObserver(this.getCommand("SubmitForm"), "execute", "DisableBox", function(context, caller) {
      if(!this.getController().getValue("showDisableBox")) return; //No disable box if the dev specifies it in the controller paarams.
      return {
        show: true,
        target: context
      }
    });
    
    //Re-run ValidateRules when isSubmitted changes values. 
    this.addObserver(this.getConfig("params").isSubmitted, "onChange", "ValidateRules", function(context, caller) {
      if(!this.getController().getValue("isSubmitted")) return { rules: {}, formSet: this.getContextElement()};
      return {
        rules: formRules,
        formSet: this.getContextElement(),
        targetElement: targetElement
      }
    });
    
    this.addObserver(this.getValue("cancelButtonId"), "onclick", "ClearErrors", function(context, caller) { 
      return { 
        className: ".mojoValidationError", 
        target: this.getContextElement()
      }
    });
  },
  addCommands: function() {
    this.addCommand("EnterKey",     "stdlib.behavior.EnterKeyBehavior");
    this.addCommand("UpdateControllerParam",  "stdlib.command.UpdateControllerParamCommand");
    this.addCommand("ClearErrors",      "stdlib.behavior.RemoveElementsBehavior");
    this.addCommand("ValidateRules",    "stdlib.command.ValidateRulesCommand");
    this.addCommand("SubmitForm",     "stdlib.behavior.SubmitFormBehavior");
    this.addCommand("DisableBox",       "stdlib.behavior.DisableBoxBehavior");
  },
  addIntercepts: function() {
    this.addIntercept("around", "SubmitForm", "ValidateRules", { 
      rules: this.getValue("formRules"),
      formSet: this.getContextElement(),
      targetElement: (this.getValue("errorsContainerId") != "") ? mojo.queryFirst(this.getValue("errorsContainerId")) : null
    });
  }
});

dojo.provide("stdlib.controller.TabController");
dojo.require("mojo.controller.Controller");

dojo.declare("stdlib.controller.TabController", mojo.controller.Controller, 
{
  params: {
    selectedIndex: {
      required: false,
      defaultValue: 0,
      type: Number
    },
    activeOn: {
      required: false,
      defaultValue: "onclick"
    }
  },
  addObservers: function() {    
    this.addObserver("> .tabs-nav > .tab", this.getValue("activeOn"), "UpdateClass", function(context, caller) { 
      var tabs = mojo.query("> .tabs-nav > .tab", context);
      var index = 0;
      for (var i = 0; i < tabs.length; i++) {
        if (tabs[i] == caller) {
          index = i;
          break;
        }
      }
      this.getController().setValue("selectedIndex", index);
    });
    this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateClass", function(context, caller) { return {
      element: mojo.query("> .tabs-nav > .selected", context),
      action: "remove",
      cssClass: "selected"
    }});
    this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateClass", function(context, caller) { return {
      element: mojo.query("> .tabs-content > .selected", context),
      action: "remove",
      cssClass: "selected"
    }});
    this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateClass", function(context, caller) { return {
      element: mojo.query("> .tabs-nav > .tab", context)[caller.getValue()],
      action: "add",
      cssClass: "selected"
    }});
    this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateClass", function(context, caller) { return {
      element: mojo.query("> .tabs-content > .tab-content", context)[caller.getValue()],
      action: "add",
      cssClass: "selected"
    }});
    this.addObserver("> .add", "onclick", "UpdateClass", function(context, caller) {
      mojo.Model.add("testData", {name: "new", description: (new Date()).getTime()});
      this.getController().setValue("selectedIndex", 0);
      this.getController().getConfig("params").selectedIndex.onChange();
    });
  },
  addCommands: function() {
    this.addCommand("UpdateClass", "stdlib.behavior.UpdateCssClassBehavior");
  },
  addIntercepts: function() {

  }
});

/*
    Class: stdlib.behavior.FilterDropdownBehavior
    Author: Loyal Chow

    Filters the options of an HTML Select list by class name
*/
dojo.provide("stdlib.behavior.FilterDropdownBehavior");
dojo.require("mojo.command.Behavior");

dojo.declare("stdlib.behavior.FilterDropdownBehavior", mojo.command.Behavior,
{
    _optionsStorage: {},
    execute: function(requestObj) {
        // Params:
        var params = requestObj.getParams();
        var dropdown = params.selectObj;
        var filterClass = params.filterClass;
        var minoption = params.minoption;

  if(params.minoption =="undefined"){
    minoption =0;
  }
  else minoption =-1;
  
        // Get Name/ID
  if (!dropdown) { return; }
        var dropdownName = (dropdown.name || dropdown.id);

        // Store Options
        if (typeof(this._optionsStorage[dropdownName]) == "undefined") {
            this._optionsStorage[dropdownName] = [];
            for (var i = 0; i < dropdown.options.length; i++) {
                this._optionsStorage[dropdownName][i] = dropdown.options[i];
            }
        }
        
       
        // Blow Away Existing Options
        for (var i = dropdown.options.length - 1; i > minoption ; i--) {
            dropdown.removeChild(dropdown.options[i]);
        }
        
       
        // Add Filtered Options from Storage
        for (var i = 0; i < this._optionsStorage[dropdownName].length; i++) {
            var option = this._optionsStorage[dropdownName][i];

            if (option.className.indexOf(filterClass) >= 0) {
  
                dropdown.appendChild(option);
            }
        }
        // Reset Selected Index
        if (dropdown.options.length > 0 && filterClass.length > 0) {
            dropdown.selectedIndex = 0;
        }
    
    
    
    
    }
});
dojo.provide("stdlib.controller.TemplateController");
dojo.require("mojo.controller.Controller");

dojo.declare("stdlib.controller.TemplateController", mojo.controller.Controller, 
{
  modelSource: "",
  _modelSourceHandle: null,
  templateObj: null,
  escapeQuotes: false,
  escapeHtml: false,
  onInit: function() {
    var context = this.getContextElement();
    var templateHTML = this._normalize(context.innerHTML);
    this.templateObj = TrimPath.parseTemplate(templateHTML);
    dojo.style(this.getContextElement(), 'display', 'none');
    this.setModelSource(context.getAttribute("modelsource"));
  },
  getModelSource: function() {
    if(!this.modelSource) {
      return "";
    }
    return this.modelSource;
  },
  setModelSource: function(modelSource) {
    if (this._modelSourceHandle) {
      mojo.Model.removeObserver(this._modelSourceHandle);
    }
    this.modelSource = modelSource;
    this._modelSourceHandle = mojo.Model.addObserver(this.modelSource, this, "onModelUpdate");
    this.onModelUpdate();
  },
  onModelUpdate: function() {
    this._bindToModel();
  },
  _bindToModel: function() {
    var modifiers = {
      escapeQuotes: function(str) {
        str = str.toString();
        str = str.replace(/\"/g, "&#34;");
        str = str.replace(/\'/g, "&#39;");
        return str;
      }
    };
    var sModel = this.getModelSource();
    if (sModel.length > 0 && mojo.Model.contains(sModel) && this.getContextElement()) {
      var modelData = mojo.Model.get(sModel);
      var result = new Array();
      if (!dojo.isArray(modelData)) {
        modelData = [modelData];
      }
      var modelDataLength = modelData.length;

      for (var i = 0, len = modelDataLength; i < len; i++) {
        if (modelData[i]) {
          if (typeof(modelData[i]) != "object") {
            var tmpModelData = modelData[i].toString();
            modelData[i] = new Object();
            modelData[i].data = tmpModelData;
          }
          modelData[i].currentIndex = i;
          modelData[i].totalLength = len;
          if(this.escapeQuotes) {
            modelData[i]._MODIFIERS = modifiers;
            modelData[i].content = modifiers.escapeQuotes(modelData[i].content);
          }
          result.push(this.templateObj.process(modelData[i]));
        }
      }
      var templateNode = this.getContextElement();
      var content = result.join("");

      templateNode.innerHTML = "";
      templateNode.innerHTML = content;
      dojo.style(this.getContextElement(), 'display', 'block');
    } else {
      dojo.style(this.getContextElement(), 'display', 'none');
    }
  },
  _normalize: function(templateStr) {
    var pattern = /[\!|\$]\{[^\}]*\}/g;
    var matchResult = templateStr.match(pattern);
    var splitResult = templateStr.split(pattern);
    var result = new Array();
    var resultLength = 0;
    if (matchResult) {
      resultLength = matchResult.length;
    }
    for (var i = 0; i < resultLength; i++) {
      result.push(splitResult[i]);
      var npattern = "$" + matchResult[i].substring(1);
      var modifiers = "";
      if (this.escapeHtml) {
        modifiers += "|escape";
      }
      if (this.escapeQuotes) {
        modifiers += "|escapeQuotes";
      }

      npattern = npattern.substring(0, npattern.length-1) + modifiers + "}";
      result.push(npattern);
    }

    result.push(splitResult[resultLength]);
    return result.join("");
  },
  addObservers: function() {    
  },
  addCommands: function() {
  },
  addIntercepts: function() {

  }
});
/* 
  Class: stdlib.controller.DialogController
  Author: Jaime Bueza
  
  The Mojo Dialog Controller can be accessed by publishing messages with a topic called "dialog".
  
  In order to use this, you can simply use:
  
  (start code)
  mojo.Messaging.publish("dialog", { enabled: true, href: "/my-url-to-a-file.jsp", width: 500, height: 250 });
  (end)
  
  If you pass "url" (String), the Dialog Controller will fetch the html content and inject it into
  <div class="dialog">, which is automatically generated if it is not in the DOM.
  
  If you pass "id" (String), the Dialog Controller will fetch the innerHTML of the specific DOM Element
  by ID and inject the innerHTML into <div class="dialog">.
  
  In its entirety, you can render Dialogs internally (already in the DOM), or externally (on the fly in
  a remote location).
  
  There are two main behaviours which dictate the functionality of the Dialog.
    - DialogBehavior
      This behavior is responsible for rendering the dialog and fetching the markup, whether
      the content is external (remotely fetched via XHR) or internal (fetched via already on the DOM).
      
    - PositionBehavior
      This behavior is responsible for recalculating the dimensions of the Dialog based on content,
      and repositioning the Dialog to the center of the screen based on the dimensions of its content.
      
  Assumptions:
    - There can only be 1 dialog open at a time.
    
  Notes:
    - Perhaps we can pass a parameter to the Position behaviour to allow transitions (fading in, sliding, etc)?

*/
dojo.provide("stdlib.controller.DialogController");
dojo.require("mojo.controller.Controller");
dojo.declare("stdlib.controller.DialogController", mojo.controller.Controller, 
{
  addObservers: function() {    
    //Trigger for initializing a Mojo Dialog. 
    this.addObserver(mojo.Messaging.getTopic("dialog"), "onPublish", "Dialog", function(context, caller) { 
      return caller.getMessage();
    });


    //Re-update observers once the Dialog has instantiated itself.
    
    this.addObserver(this.getCommand("Dialog"), "onComplete", "MapControllers");
    this.addObserver(this.getCommand("Dialog"), "onComplete", "UpdateObservers", function(context, caller) {
      return {
        controllerName: this.getController().declaredClass
      };
    });

    //Accessibility feature of allowing the user to keypress "ESC" on their keyboard to close the dialog.
    this.addObserver(this.getCommand("EscapeKey"), "onResponse", "Dialog", function(context, caller) {
      return {
        enabled: false
      };
    });
    
    //Basic functionality
    this.addObserver(".btn-dialog-close", "onclick", "Dialog", function(context, caller) {
      return {
        topic: "dialog",
        message: {
          enabled: false
        }
      };
    });
        
  },
  addCommands: function() { 
    this.addCommand("Messaging",        "stdlib.behavior.MessagingBehavior");
    this.addCommand("Dialog",           "stdlib.behavior.dialog.DialogBehavior");
    this.addCommand("Position",         "stdlib.behavior.dialog.PositionBehavior");
    this.addCommand("EscapeKey",        "stdlib.behavior.dialog.EscapeKeyBehavior");
    this.addCommand("MapControllers",       "stdlib.command.MapControllersCommand");
    this.addCommand("UpdateObservers",      "stdlib.command.UpdateObserversCommand");
    this.addCommand("UpdateCss", "stdlib.behavior.UpdateCssClassBehavior");
  },
  addIntercepts: function() {
    
  }
});
