// vim: ts=4:sw=4:nu:fdc=4:nospell
/**
 * Ext.ux.plugins
 *
 * @author    Ing. Jozef Sakáloš <jsakalos@aariadne.com>
 * @copyright (c) 2007, by Ing. Jozef Sakáloš
 * @date      24. November 2007
 * @version   $Id: Ext.ux.Plugins.js 55 2008-10-27 10:30:36Z mike $
 */


Ext.namespace('Ext.ux');
Ext.namespace('Ext.ux.Plugin');
Ext.namespace('Ext.ux.plugins');

/**
 * Remote Validator
 * Makes remote (server) field validation easier
 *
 * To be used by form fields like TextField, NubmerField, TextArea, ...
 */
Ext.ux.plugins.RemoteValidator = {
	init:function(field) {
		// save original functions
		var isValid = field.isValid;
		var validate = field.validate;

		// apply remote validation to field
		Ext.apply(field, {
			 remoteValid:false

			// private
			,isValid:function(preventMark) {
				return isValid.call(this, preventMark) && this.remoteValid;
			}

			// private
			,validate:function() {
				var clientValid = validate.call(this);
				if(!this.disabled && !clientValid) {
					return false;
				}
				if(this.disabled || (clientValid && this.remoteValid)) {
					this.clearInvalid();
					return true;
				}
				if(!this.remoteValid) {
					this.markInvalid(this.reason);
					return false;
				}
				return false;
			}

			// private - remote validation request
			,validateRemote:function() {
				this.rvOptions.params = this.rvOptions.params || {};
				this.rvOptions.params.field = this.name;
				this.rvOptions.params.value = this.getValue();
				Ext.Ajax.request(this.rvOptions);
			}

			// private - remote validation request success handler
			,rvSuccess:function(response, options) {
				var o;
				try {
					o = Ext.decode(response.responseText);
				}
				catch(e) {
					throw this.cannotDecodeText;
				}
				if('object' !== typeof o) {
					throw this.notObjectText;
				}
				if(true !== o.success) {
					throw this.serverErrorText + ': ' + o.error;
				}
				var names = this.rvOptions.paramNames;
				this.remoteValid = true === o[names.valid];
				this.reason = o[names.reason];
				this.validate();
			}

			// private - remote validation request failure handler
			,rvFailure:function(response, options) {
				throw this.requestFailText
			}

			// private - runs from keyup event handler
			,filterRemoteValidation:function(e) {
				if(!e.isNavKeyPress()) {
					this.remoteValidationTask.delay(this.remoteValidationDelay);
				}
			}
		});

		// remote validation defaults
		Ext.applyIf(field, {
			 remoteValidationDelay:500
			,reason:'Server has not yet validated the value'
			,cannotDecodeText:'Cannot decode json object'
			,notObjectText:'Server response is not an object'
			,serverErrorText:'Server error'
			,requestFailText:'Server request failed'
		});

		// install event handlers on field render
		field.on({
			render:{single:true, scope:field, fn:function() {
				this.remoteValidationTask = new Ext.util.DelayedTask(this.validateRemote, this);
				this.el.on('keyup', this.filterRemoteValidation, this);
			}}
		});

		// setup remote validation request options
		field.rvOptions = field.rvOptions || {};
		Ext.applyIf(field.rvOptions, {
			 method:'post'
			,scope:field
			,success:field.rvSuccess
			,failure:field.rvFailure
			,paramNames: {
				 valid:'valid'
				,reason:'reason'
			}
		});
	}
};


// Add the additional 'advanced' VTypes
  Ext.apply(Ext.form.VTypes, {
    daterange: function(val, field) {
    var date = field.parseDate(val);
    
    // We need to force the picker to update values to recaluate the disabled dates display
    var dispUpd = function(picker) {
      var ad = picker.activeDate;
      picker.activeDate = null;
      picker.update(ad);
    };
    
    if (field.startDateField) {
      var sd = Ext.getCmp(field.startDateField);
      sd.maxValue = date;
      if (sd.menu && sd.menu.picker) {
        sd.menu.picker.maxDate = date;
        dispUpd(sd.menu.picker);
      }
    } else if (field.endDateField) {
      var ed = Ext.getCmp(field.endDateField);
      ed.minValue = date;
      if (ed.menu && ed.menu.picker) {
        ed.menu.picker.minDate = date;
        dispUpd(ed.menu.picker);
      }
    }
    /* Always return true since we're only using this vtype
     * to set the min/max allowed values (these are tested
     * for after the vtype test)
     */
    return true;
  },
  
  password: function(val, field) {
    if (field.initialPassField) {
      var pwd = Ext.getCmp(field.initialPassField);
      return (val == pwd.getValue());
    }
    return true;
  },
  
  passwordText: 'Passwörter stimmen nicht überein'
});

// checkcolum
Ext.grid.CheckColumn = function(config){
    Ext.apply(this, config);
    if(!this.id){
      this.id = Ext.id();
    }
    this.renderer = this.renderer.createDelegate(this);
};

Ext.grid.CheckColumn.prototype ={
    init : function(grid){
      this.grid = grid;
      this.grid.on('render', function(){
        var view = this.grid.getView();
        view.mainBody.on('mousedown', this.onMouseDown, this);
      }, this);
    },

    onMouseDown : function(e, t){
      if(t.className && t.className.indexOf('x-grid3-cc-'+this.id) != -1){
        e.stopEvent();
        var index = this.grid.getView().findRowIndex(t);
        var record = this.grid.store.getAt(index);
        record.set(this.dataIndex, !record.data[this.dataIndex]);
        if(this.switchOff) {
          record.set(this.switchOff, false);
        }
        if(this.afterEdit) {
          this.grid.fireEvent('afterEdit', record);
        }
      }
    },

    renderer : function(v, p, record){
      p.css += ' x-grid3-check-col-td'; 
      return '<div class="x-grid3-check-col'+(v?'-on':'')+' x-grid3-cc-'+this.id+'">&#160;</div>';
    }
};



// paging toolbar
  Ext.ux.Plugin.PagingToolbar = Ext.extend(Ext.Toolbar, {
    
    initComponent: function(cfg) {
      Ext.apply(this, cfg);
      Ext.ux.Plugin.PagingToolbar.superclass.initComponent.call(this);
      if(!this.current) {
        this.current = 1;
      }
      if(this.pages) {
	      this.on('render', function () {
	        this.createButtons();
	        this.createPaging();
	      }, this);
      }
    },
    
    createButtons: function() {
      var tb = this;
      for(var button in this.btns) {
        this.add(this.btns[button]);
      }
    },
    
    createPaging: function() {
      var e = (this.pages > 6) ? 6 : this.pages;
      for(var i=1; i<=e; i++) {
        this.addPager(this, i);
      }
    },
    
    addPager: function(tb, i) {
      this.add({
        text: i,
        cls: (i==this.current) ? 'x-btn-pressed' : '',
        enableToggle: true,
        handler: function(b){
          tb.current = parseInt(b.text);
          tb.update();
          this.load(b.text);
        },
        scope: this.scope
      });
    },
    
    update: function() {
      for(var i=0; i<=this.items.items.length; i++) {
        var b = this.items.items[i];
        if(b && b.text) {
          if(b.text == this.current) {
            b.addClass('x-btn-pressed');
          } else {
            b.removeClass('x-btn-pressed');
          }
        }
      }
    }
    
  });
  
  
  Ext.ux.Plugin.LiteRemoteComponent = function (config){
  var defaultType = config.xtype || 'panel';
    var callback = function(res){ 
    this.container.add(Ext.ComponentMgr.create(Ext.decode(res.responseText), defaultType)).show();
    this.container.doLayout() ;
  };
    return{
    init : function (container){
      this.container = container;
      Ext.Ajax.request(Ext.apply(config, {success: callback, scope: this}));
      }
  }
};

/**
 * @author Timo Michna / matikom
 * @class Ext.ux.Plugin.RemoteComponent
 * @extends Ext.util.Observable
 * @constructor
 * @param {Object} config
 * @version 0.2.1
 * Plugin for Ext.Container/Ext.Toolbar Elements to dynamically 
 * add Components from a remote source to the Element�s body.  
 * Loads configuration as JSON-String from a remote source. 
 * Creates the Components from configuration.
 * Adds the Components to the Container body.
 * Additionally to its own config options the class accepts all the 
 * configuration options required to configure its internal Ext.Ajax.request().
 */
Ext.ux.Plugin.RemoteComponent = function (config){

   /**
    * @cfg {String} breakOn set to one of the plugins events, to stop any 
    * further processing of the plugin, when the event fires.
    */
   /**
    * @cfg {String} loadOn set to one of the Containers events, to stop any 
    * further processing of the plugin, when the event fires.
    */
   /**
  * @cfg {String} xtype Default xtype for loaded toplevel component.
  * Overwritten by config.xtype or xtype declaration 
  * Defaults to 'panel'
  * in loaded toplevel component.
  */
  var defaultType = config.xtype || 'panel';
   /**
  * @cfg {String} purgeListeners Set true to automatically purge
  * any listner for the plugin after the process chain (even when the
  * processing has been stopped by config option breakOn).
  * Defaults to true
  * Overwritten by config.xtype or xtype declaration 
  * in loaded toplevel component.
  */
    var purgeListeners = config.purgeListeners || true;
    this.addEvents({
      /**
       * @event beforeload
       * Fires before AJAX request. Return false to stop further processing.
       * @param {Object} config
       * @param {Ext.ux.Plugin.RemoteComponent} this
       */
        'beforeload' : true,
      /**
       * @event beforecreate
       * Fires before creation of new Components from AJAX response. 
     * Return false to stop further processing.
       * @param {Object} JSON-Object decoded from AJAX response
       * @param {Ext.ux.Plugin.RemoteComponent} this
       */
        'beforecreate' : true,
      /**
       * @event beforeadd
       * Fires before adding the new Components to the Container. 
     * Return false to stop further processing.
       * @param {Object} new Components created from AJAX response.
       * @param {Ext.ux.Plugin.RemoteComponent} this
       */
        'beforeadd' : true,
      /**
       * @event beforecomponshow
       * Fires before show() is called on the new Components. 
     * Return false to stop further processing.
       * @param {Object} new Components created from AJAX response.
       * @param {Ext.ux.Plugin.RemoteComponent} this
       */
        'beforecomponshow': true,
      /**
       * @event beforecontainshow
       * Fires before show() is called on the Container. 
     * Return false to stop further processing.
       * @param {Object} new Components created from AJAX response.
       * @param {Ext.ux.Plugin.RemoteComponent} this
       */
        'beforecontainshow': true,
      /**
       * @event success
       * Fires after full process chain. 
     * Return false to stop further processing.
       * @param {Object} new Components created from AJAX response.
       * @param {Ext.ux.Plugin.RemoteComponent} this
       */
        'success': true
    });
  // set breakpoint 
  if(config.breakOn){
    this.on(config.breakOn, function(){return false;});
  }
   /**
    * private
    * Callback method for successful Ajax request.
    * Creates Components from responseText and  
    * and populates Components in Container.
    * @param {Object} response object from successful AJAX request.
    */
    var callback = function(res){ 
        var JSON = Ext.decode(res.responseText);
    if(this.fireEvent('beforecreate', JSON, this)){
      var component = Ext.ComponentMgr.create(JSON, defaultType);
      if(this.fireEvent('beforeadd', component, this)){
        this.container.add(component);
        if(this.fireEvent('beforecomponshow', component, this)){
          component.show();
          if(this.fireEvent('beforecontainshow', component, this)){
            this.container.doLayout();
            this.fireEvent('success', component, this);
          }           
        }         
      }         
    }   
    this.purgeListeners();
    
  };
   /**
    * public
    * Processes the AJAX request.
    * Generally only called internal. Can be called external,
    * when processing has been stopped or defered by config
    * options breakOn or loadOn.
    */
  this.load = function(){
    if(this.fireEvent('beforeload', config, this)){
      Ext.Ajax.request(Ext.apply(config, {success: callback, scope: this}));        
    } 
  };
   /**
    * public
    * Initialization method called by the Container.
    */
    this.init = function (container){
    container.on('beforedestroy', function(){this.purgeListeners();}, this);
    this.container = container;
    if(config.loadOn){
      var defer = function (){
        this.load();
        container.un(config.loadOn, defer, this); 
      };
      container.on(config.loadOn, defer, this);
    }else{
      this.load();  
    }           
    };
};
Ext.extend(Ext.ux.Plugin.RemoteComponent, Ext.util.Observable);


// remote toolbar
Ext.ux.Plugin.RemoteToolbar = function (config){
  var callback = function(res){
    var tbar = config.tbar;
    var btns = Ext.decode(res.responseText);
    // hide
    tbar.hideMode = 'visibility';
    tbar.hide();
    // remove items
    tbar.items.each(function(item) {
      tbar.items.remove(item);
      item.destroy();
    }, tbar.items);
    // add new
    for(var i = 0; i < btns.length; i++){
      if(typeof(btns[i].handler) != 'undefined') {
        btns[i].handler = eval(btns[i].handler);
        btns[i].scope   = this;
        //btns[i].hidden  = true;
      }
      tbar.add(btns[i]);
      //btns[i].hidden = false;
    }
    // show
    tbar.show();
  };
  Ext.Ajax.request(Ext.apply(config, {success: callback}));
};

// end of file