/*
    YpCode Input components and functions
*/


Yp.input = {};


var YpTokenizer = Class.create({
/*
    Base class of input tokenizer widget.
    Replace a textfield element with custom ExtJS input.

    usage:
        use as prototype class

    config format:
        see below
*/

    initialize: function(textarea) {
        // config default options
        this.config = Object.extend({
            searchUrl: null,
                /*  if empty tokenizer will use local data
                    otherwise use this url for fetching FILTERED items */
            className:'yp-tokenizer',
            tokenClassName:'yp-token',
            tokenRemoverClassName:'yp-token-remover',
            tokenContentClassName:'yp-token-content',
                /* html class Names for elements */

            validateInput: null,
                /* if passed as function, will use it to validate input */

            autocomplete: true,
                /* whether use autocomplete */
            checkUnique:true,
                /* only unique values */

            minLength:2,
            maxLength:false,
                /* min, max token length */
            limitCount: false,
                /* limit tokens number */
            defaults: [],
                /*  default tokens to be added at startup */
            data: [],
                /*  data items, used with local data search */

            loadingText: "Loading...",
                /* loading text label */
            queryParam:'str',
                /*  query parameter for remote data fetch,
                    passes current input value */

            baseParams:{}
                /*  base params for query */

        }, arguments[2]||{});


        textarea = $(textarea);

        // crete a raw input[text]
        this.rawinput = new Element('input',{type:'text',id:textarea.getAttribute('id')});
        this.rawinput.tokenizer = this;
        this.name = this.rawinput.getAttribute('id');

        this.rawinput.addClassName(textarea.className);
        this.rawinput.setAttribute('title', textarea.getAttribute('title'));

        // create tokens list container, base YpTokenizer element and new input
        this.tokList = new Element('div');
        this.element = new Element('div',{className:this.config.className});
        this.element.insert(this.tokList);
        this.element.insert(this.rawinput);

        // replace original textarea with tokenizer
        Element.replace(textarea,this.element);

        // focus element on click
        this.element.observe('click', function() {
            this.input.el.focus();
        }.bind(this));

        var proxy_mode;

        /* create a data store
           with local or remote configuration */
        if(this.config.searchUrl) {
            proxy_mode = 'remote';
            this.store = new Ext.data.Store({
                baseParams: this.config.baseParams,
                remoteSort:true,
                proxy: new Ext.data.HttpProxy({
                    url: this.config.searchUrl
                }),
                reader: new Ext.data.XmlReader({
                    record: 'item'
                },[{name:'name',mapping:'tag'}])
            });
        } else {    // local store
            proxy_mode = 'local';
            this.store = new Ext.data.SimpleStore({
                fields: ['name', 'value'],
                data : this.config.data
            });
        }

        // create ExtJs ComboBox
        this.input = new Ext.form.ComboBox({
            queryParam: this.config.queryParam,
            store: this.store,
            displayField:'name',
            minChars:this.config.minLength,
            typeAhead: false,
            mode: proxy_mode, 

            loadingText: this.config.loadingText,
            width: '100%',
            triggerAction: (proxy_mode=='remote' ? 'query' : 'all'),
            triggerConfig: {tag:'div', cls:'x-trig-add'},
            selectOnFocus:true
        });

        this.input.on('select',this.addFromInput,this);

        // install extjs input for new input
        this.input.applyToMarkup($(this.rawinput));

        // append default tokens
        if(Object.isArray(this.config.defaults) && this.config.defaults.length>0) {
            $A(this.config.defaults).each(function(it){
                if(Object.isArray(it)) {
                    this.addToken(it[0],it[1])
                } else {
                    this.addToken(it);
                }
            }.bind(this));
        }

        window.tokenizer=this;

        // using self rather than bind, for opera compatibility
        var self = this;
        this.rawinput.observe('blur', function(ev) {
            if(!self.input.isExpanded()) {
                self.addFromInput(self.input);
            }
        });

        /* next opera hack (disable autosubmit on input keypress)
          decorate 'onsubmit' form property */
        this.canSubmit = true;
        var onsubmit = this.rawinput.form.onsubmit;
        this.rawinput.form.onsubmit = function() {
            if(self.canSubmit) {
                if(onsubmit!=null) return onsubmit.apply(self.rawinput.form,$A(arguments));
                return true;
            }
            return false;
        }

        // observe keys events
        Event.observe(this.rawinput, 'keydown', function(ev) {
            if(ev.keyCode==Event.KEY_RETURN) {
                self.canSubmit = false;
                Event.stop(ev);

                self.addFromInput(self.input);

                (function() {
                    self.canSubmit=true;
                }).delay(1);
                return false;
            }
        });
    },

    addFromInput: function(input) {
        /* adds token from input(Element) */
        var v = input.getValue();
        if(this.validateInput(v)) {
            input.setValue("");
            this.addToken(v);
        }
    },
    addToken: function(name,value) {
        /* adds token from name, value.
            does not validate! */
        if(Object.isString(name)) {
        	var tagz = name.split(","); 
        	if (tagz.length > 1) {
        		for (i=0;i<tagz.length;i=i+1) {
              this.createToken(tagz[i],value || tagz[i]);
            }     
        	}
          else {
          	this.createToken(name,value || name);
          }
        }
    },
    addTokens: function(tokens) {
        /* adds an array */
        $A(tokens).each(function(t){
            if(Object.isArray(t)) this.addToken(t[0],t[1]);
            else this.addToken(t);
        }.bind(this));
    },

    getTokens: function() {
        /* finds hidden input fields in tokenizer form */
        return $A(Form.Methods.getInputs(this.input.el.dom.form,'hidden',this.name+'[]')).map(function(it){ return it.value; });
    },

    getTokensCount:function() {
        /* counts added tokens */
        return $A(this.input.el.dom.form.getInputs('hidden',this.name+'[]')).length;
    },

    validateInput: function(value) {
        /* validates input value */
        var v=value.strip();
        if(v=="" || !v) return false;
        if(this.config.checkUnique) {
            if(this.getTokens().member(v)) return false;
        }
        if(this.config.limitCount>0 && this.getTokensCount()>= this.config.limitCount) return false;
        if(this.config.maxLength>0 && v.length>this.config.maxLength) return false;
        if(this.config.minLength>0 && v.length < this.config.minLength) return false;


        // validate by user function if passed in config
        if(this.config.validateInput) {
            return this.config.validateInput(value)==true;
        }
        return true;
    },

    createToken: function(name, value) {
        /* creates token fields
            input[hidden] = value
            span[token] = name
        */

        var tok = new Element('span',{className:this.config.tokenClassName});

        tok.appendChild(new Element('input',{type:'hidden',name:this.name+'[]',value:value}));
        tok.appendChild(new Element('span',{className:this.config.tokenContentClassName}).update(name));
        // and token remover
        var r = new Element('span',{className:this.config.tokenRemoverClassName});
        r.update('x');

        r.observe('click', function() {
            tok.remove(); // remove token
        }.bindAsEventListener(this));

        tok.appendChild(r);
        this.tokList.insert(tok);
    }
});


var YpTagsTokenizer = Class.create(YpTokenizer,{
/*
    Custom input field for tags.
    Replace a textarea element with own input code.

    usage:
        new YpTagsTokenizer('some-textarea' [, config]);

    where config include:
        'data': tags data

*/
    initialize: function($super,textarea) {
        var cfg = Object.extend({
            searchUrl: '/tagsfa',
            // default tags ajax gateway

            tagsSeparator: '\n'
            // data separator
        },arguments[2] || {});


        var values = String($(textarea).value || "").split(cfg.tagsSeparator).map(function(v) {
            v= String(v).strip().escapeHTML();
            if(v) return v;
        });

        if(values) {
            // set defauls
            cfg.defaults = values;
        }
        $super(textarea,name,cfg);
    }
});





var YpUsersTokenizer = Class.create(YpTokenizer,{
/*
    Custom input field for selecting users.
    Replace a textarea element with own input code.

    usage:
        new YpUsersTokenizer('some-textarea' [, config]);

    where config include:
        'defaults' - array of default users (already added to tokenizer)
        'data' - array of available users

        + other options for YpTokenizer base class (see above)

    the 'user' item format:
        ['displayed name', user_id]

    example:
        new YpUsersTokenizer('recipient-users',{
            'users': [
                ['Jozin z Bazin', 1],
                ['Ivan Mladek', 2],
                ['Fat Bastard', 666]
            ]]
        });

*/
    initialize: function($super,textarea) {
        window.tokenizer=this;
        this.config = Object.extend({
            notFoundError: 'Contact not found',
            minLength: 1            // min key length
        },arguments[2] || {});

        $super(textarea,name,this.config);

        // override default onSelect action
        this.input.onSelect = function(record) {
            if( !this.getTokens().member(record.data.value) ) {
                this.addToken(record.data.name, record.data.value);
                this.input.collapse();
                this.input.setValue('');
            }
        }.bind(this);


        this.input.on('beforequery', function(e) {
            // Look for typed info anywhere in string, not just beginning
            var len= e.query.length;
            e.query = new RegExp(Ext.escapeRe(e.query), "i");
            e.query.length = len;
            return 1;
        });
    },
    addFromInput: function(input) { // override adding from input to do nothing
        var val = input.getValue();
        if(val!="") {
            var err = $('error_for_receivers');
            if(err) {
                if(err.innerHTML=="") {
                    err.hide();
                }
                err.addClassName('lineError');
                err.update('<span>'+ this.config.notFoundError + '</span>');
                new Effect.Appear(err);
            }
        }
    },
    
    createToken: function($super,name,val) {
        var err = $('error_for_receivers');
        if(err && err.visible()) {
            err.hide();
        }
        $super(name,val);
    }
});



/*
    Custom field delayed validator.
    runs a defined function (as second parameter)
*/
function ypDelayedInput(input,func) {
    var sec = $A(arguments)[2] || 2;    // 2 seconds default timeout

    if(input.checker) {
        window.clearTimeout(input.checker);
    }
    input.checker = (function(inp,val,f){if(inp.value==val) f()}).delay(sec,input,input.value,func);
}




/*
    Custom Map Edit controls 
*/
Yp.input.CountryCitiesControls = Class.create({
    initialize: function(country_input, city_input, cities_getter, editable, custom_text, city_id) {
        this.city_input = $(city_input);
        this.country_input = $(country_input);
        
        this.country = new Ext.form.ComboBox({
            transform: this.country_input,
            triggerAction: 'all',
            selectOnFocus:true,
            triggerConfig: {tag:'div', cls:'x-trig'},
            id: this.country_input.getAttribute('id')
        });
        
        window.cci = this;
        var self = this;
        this.country.on('change', function() {
            var val = self.country.getValue();
            self.city.setValue('');
            self.city.store.baseParams = {'cc': val};
            self.city.store.load({params:{'cc':val}});
        });
        

        
        this.store = new Ext.data.Store({
            baseParams: {},
            remoteSort:true,
            proxy: new Ext.data.HttpProxy({
                 url: cities_getter
             }),
             reader: new Ext.data.XmlReader({
                  record: 'item',
                  id:'id'
            },[{name:'tag'}, {name:'id'} ])
        });
        
        var cfg =  {
            queryParam: 'str',
            store: this.store,
            displayField: 'tag',

            minChars: 2,
            typeAhead: false,
            transform: this.city_input,
            
            mode: 'remote',
            //id: this.city_input.getAttribute('id'),
            selectOnFocus:true,
            emptyText: (custom_text || ' '),
 
            value: this.city_input.value,
            triggerAction: 'all',
            triggerConfig: {tag:'div', cls:'x-trig'}
        };
        
        if(!editable) {
            cfg.valueField = 'id';
            cfg.editable = false;
            cfg.value = this.city_input.value ||'';
        } else {
            cfg.valueField = 'id';
            cfg.editable = true;
            cfg.value = this.city_input.value ||'';
            cfg.forceSelection = true;
        }

        var setCityFormValue = function(val) {
            $(self.city_input.id).value = val;
        };
        
        this.city = new Ext.form.ComboBox(cfg);
        this.city.store.baseParams = {'cc': this.country.getValue()};

        if(editable) {
            this.city.on('specialkey',function() {
                setCityFormValue(this.getValue());
            });
            this.city.on('blur',function() {
                setCityFormValue(this.getValue());
            });
            setCityFormValue(city_id);            
        } else {
            setCityFormValue(city_id);
        }

    }
    
});

/*
            queryParam: this.config.queryParam,
            store: this.store,
            displayField:'name',
            minChars:this.config.minLength,
            typeAhead: false,
            mode: proxy_mode,

            loadingText: this.config.loadingText,
            width: '100%',
            hideTrigger:true,
            triggerAction: (proxy_mode=='remote' ? 'query' : 'all'),
            selectOnFocus:true
            
*/
