/**
  * @module Command
  */
var com = com||{};
com.rikkertkoppes = com.rikkertkoppes||{};
com.rikkertkoppes.util = com.rikkertkoppes.util||{};


com.rikkertkoppes.util.Command = function() {
  var Event = com.rikkertkoppes.Event;

  var version = '2009.09.08';

/** 
  * @namespace Command
  * @param name <string> optional
  * @param scope <object> optional
  *
  * the command function can be used in several ways
  * as a namespace for e.g. register, enable and disable method
  * e.g Command.register('foo',function(){},[scope]);
  * to return a function that executes the command (which can be assigned to event handlers)
  * var func = Command('foo',[scope]);
  
  * Commands can be executed in three ways, by commandstring, direct evaluation or method call, i.e.:
  * Command.doCommand('foo arg1 arg2 arg3 agr4')
  * Command('foo')(arg1,arg2,arg3,arg4)
  * Command().foo(arg1,arg2,arg3,arg4)
  *
  * furthermore, commands can have maps to use them in for instance event listeners while maintaining a clean arguments signature
  * - add a maps object literal to the function you register
  * - add function references for mapping, they should return arrays that will be parsed to commands
  * - use the maps as event listeners
  *
  * function foo(){};
  * foo.maps = {
  *   event: function(e) {return [arg1,arg2]}
  * }
  *
  * Command.register('foo',foo);
  * addEventListener('click',Command.map('foo').event);
  */

  function Command(name,scope) {
    if (!(name || scope)) return commandsByName;
    return function() {
      return _execute(name,arguments,scope);
    };
  };
  var commands = {};
  var commandsByName = {};
  var enabledCommands = {};

  /**
    * @method register
    * @static
    * @param name <string> name the command is registered and callable by
    * @param funcRef <function> the actual command function to register
    * @param scope <object> optional execution scope for the command, defaults to window
    * registers a command under a certain name. with an optional execution scope
    */
  Command.register = function(name,funcRef,scope) {
    if (!funcRef) throw('Command: function reference for '+name+' not defined');
    commands[name] = {
      f: funcRef,
      s: scope,
      m: _createMaps(name,funcRef,scope)
    };
    commandsByName[name] = function() {
      return _execute(name,arguments,scope);
    };
    Command.enable(name);
  };

  /**
    * @method _execute
    * @static
    * @private
    * @param name <string> name of the (registered) command to execute
    * @param args <array> optional arguments to pass to the command function
    * @param scope <object> optional execution scope for the command, overrides previously defined scope at registering, defaults to window
    * executes a command by name, optionally passing arguments and an execution scope
    */
  function _execute(name,args,scope) {
    if (!commands[name] || !enabledCommands[name]) return;
    var f = commands[name].f;
    if (!f) return;
    if (Command.onCommandExecute(name)===false) return;
    var s = scope||commands[name].s||window;
    return f.apply(s,args);
  };

  /**
    * @method _createMaps
    * @static
    * @private
    * @param name
    * @param funcRef
    * @param scope
    */
  function _createMaps(name,funcRef,scope) {
    var m,maps = {};
    if (!funcRef.maps) return maps;
    for (m in funcRef.maps) {
      maps[m] = function(m) {
        return function() {
          var mappedArgs = funcRef.maps[m].apply(scope,arguments);
          return _execute(name,mappedArgs,scope);
        }
      }(m);
    }
    return maps;
  };

  /**
    * @method map
    * @static
    * @param name
    */
  Command.map = function(name) {
    return commands[name].m;
  };

  /**
    * @method doCommand
    * @static
    * @param commandString <string>
    */
  Command.doCommand = function(commandString) {
    var args = commandString.split(' ');
    var name = args[0];
    var pars = [];
    for (var i=1; i<args.length; i++) {
      pars[i-1]=args[i];
    }
    args[0] = pars.join(' ');
    return _execute(name,pars);
  };

  /**
    * @method do
    * @static
    * @param commandString <string>
    * alias for doCommand()
    */
  Command['do'] = Command.doCommand;

  /**
    * @method enable
    * @static
    * @param name
    */
  Command.enable = function(name) {
    if (Command.onCommandEnable(name)===false) return;
    enabledCommands[name] = true;
  };

  /**
    * @method disable
    * @static
    * @param name
    */  
  Command.disable = function(name) {
    if (Command.onCommandDisable(name)===false) return;
    delete enabledCommands[name];
  };
    
  Command.onCommandExecute = function(name) {};
  Command.onCommandEnable = function(name) {};
  Command.onCommandDisable = function(name) {};

  /**
    * @property __version__
    * version of the current build
    */
  Command.__version__ = version;
  return Command;
}();