var MG_SIMPLE = 1;
var MG_COMBO = 2;

var DBG = null;
var MG_clickTargets = $A([]);
window.addEvent('domready', function () {
    document.getElement('body').addEvent('click', function (event) {
        MG_clickTargets.each(function (item, index) {
            var c = item.suggList.getCoordinates();
            if((event.page.x > c.left + c.width || event.page.x < c.left) || 
               (event.page.y > c.top + c.height || event.page.y < c.top)) {
                item.hideList();
            }
            
            if (item.mustHideDD) {
                DBG = [item.dropDown.id, event.target.parentNode.id, event];
                switch (true) {
                    case event.target && event.target.tagName.toLowerCase() == 'div' 
                         && event.target.id && event.target.id == item.dropDown.id:
                    case event.target && event.target.tagName.toLowerCase() == 'a'
                         && event.target.parentNode.id == item.dropDown.id:
                        break;
                        
                    default:
                        item.hideDropDown();
                        break;
                }
            }
        }.create({bind: event}));
    });
});

var _MOO_GESTERS = $H({});
function getGester(targetId) {
    if  (_MOO_GESTERS.has(targetId)) {
        return _MOO_GESTERS.get(targetId);
    }
    
    return null;
}

var mooGester = new Class({
    Implements: [Options, Events],
    
    options: {
        type: null,
        target: null,
        requestUrl: null,
        requestMethod: null,
        requestParamsRetrieval: null,
        preloadedData: null,
        useOnlyPreloadedData: null,
        defaultItem: null,
        disableDropDown: null,
        maintainDefaultFormAction: false,
        dropdownContainer: null,
        
        targetClassName: 'suggTarg',
        targetIdSuffix: '_id',
        
        suggContclass: 'suggCont',
        suggListclass: 'suggList',
        
        dropDownSuffix: '_dd',
        dropDownclass: 'suggDd',
        dropDownArrowSuffix: '_ddArr',
        dropDownArrowclass: 'suggDdArr',
        listItemIdPrefix: 'suggII_',
        
        maxItemsInList: 10
    },
    
    disabled: false,
    
    initialize: function (options) {
        if (options.events) {
            this.addEvents(options.events);
//            delete options.events;
        }
        this.setOptions(options);
        
        this.requestCount = 0;
        this.selectedItem = null;
        this.target = null;
        this.targetId = null;
        
        this.suggCont = null;
        this.suggList = null;
        
		this.ddCont = null;
        this.dropDown = null;
        this.dropDownArrow = null;
		this.ddScrolledTo = null;
		
		this.target =  $(this.options.target);
        
        if(! this.target) {
        	return;
        }
        
        this.bound = new $H({
            selectItem: this.selectItem.create({bind: this}),
            hoverItem: this.hoverItem.create({bind: this}),
            populateFromRequest: this.populateFromRequest.create({bind: this}),
            hideList: this.hideList.create({bind: this}),
            
            keyUp: this.keyUp.create({bind: this}),
            keyDown: this.keyDown.create({bind: this}),
            focus: this.focus.create({bind: this}),
			enableMustHideDD: this.enableMustHideDD.create({bind: this})
        });
        
        if (this.options.type == MG_COMBO) {
            this.bound.include('showDropDown', this.showDropDown.create({bind: this}));
            this.bound.include('hideDropDown', this.hideDropDown.create({bind: this}));
            this.bound.include('populateDropDown', this.populateDropDown.create({bind: this}));
        }
        
        this.transformTarget();
        if (this.options.defaultItem) {
            this.selectItem(null, new $H(this.options.defaultItem));
        }
        
        //defaul value from populate dropdown
        this.dopdd = null;
        
        MG_clickTargets.push(this);
        _MOO_GESTERS.set(this.target.id, this);
    },
    
    transformTarget: function () {
        if  (this.options.type != MG_SIMPLE && !this.options.dropdownContainer) {
            this.target.addClass(this.options.targetClassName);
        }
        this.target.setAttribute('autocomplete', 'off');
        this.target.addEvents({
            'keyup': this.bound.keyUp,
            'keydown': this.bound.keyDown,
            'blur': this.bound.hideList,
            'focus': this.bound.focus,
            'mousedown': this.bound.focus
        });
        
        if (! document.getElementById(this.target.id + this.options.targetIdSuffix)) {
            this.targetId = new Element('input', {
                id: this.options.target + this.options.targetIdSuffix,
                name: this.target.name + this.options.targetIdSuffix,
                type: 'hidden',
                name: this.target.name + this.options.targetIdSuffix,
                value: ''
            });
            $(this.target.parentNode).grab(this.targetId);
        } else {
            this.targetId = $(this.target.id + this.options.targetIdSuffix);
        }
        
        var toWrap = $A([this.target]);
        if (this.options.type == MG_COMBO) {
            this.prepareDropDown();
            
            if (! this.options.dropdownContainer) {
	            toWrap.push(this.dropDownArrow);
	            toWrap.push(this.ddCont);
            }
        }
        
        this.prepareSuggCont();
        toWrap.push(this.suggCont);
        
        var wrapper = new Element('div');
        toWrap.each(function (item, index) {
            wrapper.wraps(item);
        });
    },
    prepareSuggCont: function() {
    	this.suggCont = new Element('div', {
            'class': this.options.suggContclass
        });
        
        this.suggList = new Element('div', {
            'class': this.options.suggListclass
        });
        
        this.suggCont.grab(this.suggList);
        
        $(this.target.parentNode).grab(this.suggCont);
    },
    prepareDropDown: function() {
    	if (this.options.dropdownContainer) {
    		this.dropDown = this.ddCont = $(this.options.dropdownContainer);
    		
    		if (this.options.preloadedData) {
                this.populateDropDown();
            }
    		
    		return;
    	}
    	
		this.ddCont = new Element('div', {
            'class': this.options.suggContclass
        });
        
        this.dropDown = new Element('div', {
            'id': this.options.target + this.options.dropDownSuffix,
            'class': this.options.suggListclass, //this.options.dropDownclass,
			'styles': {
				'height': 200,
				'width': 238,
				'overflow-x': 'hidden',
				'overflow-y': 'auto'
			},
            'events': {
                'click': this.bound.selectItem,
                'blur': this.bound.hideDropDown
            }
        });
		
		this.ddCont.adopt(this.dropDown);
        
        this.dropDownArrow = new Element('img', {
            id:  this.options.target + this.options.dropDownArrowSuffix,
            'class': this.options.dropDownArrowclass,
            src: 'http://www.pomagalo.com/index3/img/pmd_arrow.gif',
            events: {
                'click': this.bound.showDropDown
            }
        });
        if (this.options.disableDropDown) {
            this.dropDownArrow.setStyle('width', '0px');
            this.dropDownArrow.setStyle('height', '0px');
        }
        
        if (this.options.preloadedData) {
            this.populateDropDown();
        }
        
        this.target.parentNode.adopt(this.dropDownArrow);
		this.target.parentNode.adopt(this.ddCont);
    },
    populateDropDown: function (data) {
        if (arguments.length > 1 && data == {}) {
            this.empty();
            return;
        }
        var items = data ? new $H(data) : new $H(this.options.preloadedData);
        
        this.dropDown.empty();
		items.each(function (item, index) {
            this.dropDown.grab(new Element('a', {
                'html': item,
                'id': this.options.listItemIdPrefix + index,
                'href': 'javascript: void(0);',
                'events': {
                    'mouseover': this.bound.hoverItem,
                    'mousedown': this.bound.selectItem
                }
            }));
        }, this);
        
//        this.dropDown.grab(new Element('div', {
//            'html': '',
//            'value': 0
//        }), 'top');
        this.dropDown.value = 0;
        
        if (this.dopdd) {
            var selected = this.dropDown.getElement('#' + this.options.listItemIdPrefix + this.dopdd);
			this.targetId.value = this.dopdd;
			this.target.value = selected.get('html');
            this.dopdd = null;
        }
    },
    setDefaultOnPopulateDropDown: function (id) {
        this.dopdd = id;
    },
    
    loadTempItemsInList: function() {
        this.suggList.empty();
        this.tempCount = 0;
        
        this.tempItems.each(function (item, index) {
            this.tempCount ++;
            this.suggList.grab(new Element('a', {
                'html': item[1].replace(this.tempPhraseRe, '<b class="match">$1</b>'),
                'id': this.options.listItemIdPrefix + item[0],
                'href': 'javascript: void(0);',
                'events': {
                    'mouseover': this.bound.hoverItem,
                    'mousedown': this.bound.selectItem
                },
                'styles': {
                	'border': this.options.maxItemsInList - 1 == index ? 'none' : ''
                },
                'class': (this.tempCount % 2 == 0) ? 'invert' : ''
            }));
        }, this);
        
        if ((! this.options.useOnlyPreloadedData) && this.options.type == MG_COMBO) {
            this.tempItems.each(function (item, index) {
                this.dropDown.grab(new Element('a', {
                    'html': item[1],
	                'id': this.options.listItemIdPrefix + item[0],
	                'href': 'javascript: void(0);',
	                'events': {
	                    'mouseover': this.bound.hoverItem,
	                    'mousedown': this.bound.selectItem
	                }
                }));
            }, this);
        }
        
        if (0 == this.tempCount) {
        	this.hideList();
        }
        
        this.tempItems.empty();
    },
    executeRequest: function () {
        this.requestCount ++;
        
        if (this.request) {
        	this.request.cancel();
        }
        
        this.request = new Request.JSON({
            url: this.options.requestUrl + this.options.requestParamsRetrieval(),
            method: this.options.requestMethod,
            onComplete: this.bound.populateFromRequest
        }).send();
    },
    populateFromRequest: function(respJSON, respText) {
        if (respJSON) {
            this.suggList.empty();
            
            $H(respJSON).each(function (value, key) {
                this.tempItems.push([key, value]);
            }, this);
            
            this.loadTempItemsInList();
        }
    },
    populateFromDropDown: function() {
        this.tempCount = 0;
        tmpH = $H({
            hash: $A([]), 
            ind: $A([]), 
            mi: 0, 
            phrase: this.tempPhrase.toLowerCase(), 
            re: this.tempPhraseRe, 
            out: $A([]),
            cnt: 0,
			listItemIdPrefix: this.options.listItemIdPrefix
		});
		
        this.dropDown.getElements('a').each(function (item, index) {
            if(this.re.test(item.get('html'))) {
                var mi = item.get('html').toLowerCase().indexOf(this.phrase);
                if(! this.hash[mi]) {
                    this.hash[mi] = $A([]);
                    this.ind.push(mi);
                }
                this.hash[mi][parseInt(item.id.toString().replace(this.listItemIdPrefix, ''))] =  item.get('html').trim();
            }
        }, tmpH);

        tmpH.ind.sort(function (a,b) { return a - b; });
        tmpH.ind.each(function (item, index) {
            if(this.cnt == 10) {
                return;
            }
            
            this.hash[item].each(function (i, ind) {
                if ($type(i) != 'string') {
                    return;
                }
                
                if (this.cnt < 10) {
                    this.cnt ++;
                    this.out.push([ind, i]);
                } else {
                    return;
                }
            }, this)
        }, tmpH);
        this.tempItems = tmpH.out;
        
        this.loadTempItemsInList();
    },
    populateList: function () {
        this.tempPhrase = latcyr(this.target.value);
        this.tempPhraseRe = RegExp('(' + this.tempPhrase + ')', 'i');
        this.tempItems = [];
        if (MG_SIMPLE == this.options.type) {
        	this.targetId.value = "";
        }
        
        if  (this.tempPhrase.trim() != "") {
        	this.showList();
            
        	switch (true) {
                case this.options.useOnlyPreloadedData:
                    this.populateFromDropDown();
                    break;
                    
                default :
                    this.executeRequest();
                    break;
            }
            
            ! this.tempCount && this.hideList();
        } else {
            this.hideList();
        }
    },
    
    hoverItem: function (event) {
        var target = $(event.target);
        
        target.getParent('div').getElements('a').each(function (item, index) {
            item.removeClass('selected');
        }, this);
        
        if (target.get('tag') == 'a') {
            this.selectedItem = target;
            this.selectedItem.addClass('selected');
        }
    },
    selectItem: function(event, hash) {
        if ((! event) && (! hash)) {
            return;
        }
        
        if (hash) {
            this.target.set('value', hash.get('value'));
            this.targetId.set('value', hash.get('key'));
            
            if (this.options.type == MG_COMBO) {
                this.dropDown.value = hash.get('key');
				this.hideDropDown();
            }
            
            return;
        }
        
        var target = $(event.target);
        
        this.suggList.getElements('a').each(function (item, index) {
            item.removeClass('selected');
        }, this);
        
        if (target.get('tag') == 'a') {
            this.selectedItem = target;
            this.selectedItem.addClass('selected');
            
            this.target.set('value', target.get('text').trim().replace(/(<([^>]+)>)/ig, ''));
            this.targetId.set('value', target.id.replace(this.options.listItemIdPrefix, ''));
            
            if ($type(event) == 'event') {
                this.hideList();
            }
            if (this.options.type == MG_COMBO) {
                this.dropDown.value = this.targetId.get('value');
				this.hideDropDown();
            }
            
            if (event.type && event.type == 'mousedown' && this.options.maintainDefaultFormAction) {
            	var frm = this.target.getParent('form');
            	if(frm) {
            		setTimeout(function () {frm.submit()}, 10);
            	}
            }
        } else if (target.get('tag') == 'select') {
            this.target.set('value', target.options[target.selectedIndex].text.trim());
            this.targetId.set('value', target.get('value'));
            
            this.selectedItem = this.suggList.getElement('#' + this.options.listItemIdPrefix + target.get('value'));
            if (this.selectedItem) {
                this.selectedItem.addClass('selected');
            }
            
            this.hideDropDown();
        }
        
        this.hideDropDown();
        
        if(event && $defined(event.change) && event.change === false) {
            return;
        }
        this.onChange();
    },
    onSelectItem: function() {
        this.fireEvent('onSelectItem');
    },
    onChange: function() {
        this.alreadyNulled = false;
        
        if (formValidators) {
			var parentForm = this.target.getParent('form');
			
			if (parentForm) {
				var validator = formValidators.get(parentForm.name + 'Validator');
				
				if (validator) {
					validator.validateField(this.target);
					validator.validateField(this.targetId);
				}
			}
		}
        
        var ot = this.target.retrieve('OverText');
        if (ot) {
        	ot.hide();
        }
        
        this.fireEvent('change', this);
    },
    focus: function() {
        this.fireEvent('focus');
    },
    
    moveListMarker: function(direction, target) {
		var list = target || this.suggList;
		
		var cdsi = null;
		if (list.id && list.id == this.dropDown.id && this.selectedItem) {
			cdsi = this.dropDown.getElement('#' + this.selectedItem.id);
			if (cdsi) {
				cdsi.removeClass('selected');
			}
		}
		
        if (list.childNodes.length > 0) {
            if (! this.selectedItem) {
                return this.selectItem({target: list.getFirst(), change: false});
            }
            
            switch (direction) {
                case 'up':
                    if (this.selectedItem.id == list.getFirst().id) {
                        return this.selectItem({target: list.getLast(), change: false});
                    } else {
                        return this.selectItem({target: this.selectedItem.getPrevious(), change: false});
                    }
                    break;
                    
                case 'down':
                    if (this.selectedItem.id == list.getLast().id) {
                        return this.selectItem({target: list.getFirst(), change: false});
                    } else {
                        return this.selectItem({target: this.selectedItem.getNext(), change: false});
                    }
                    break;
            }
        }
    },
    showList: function () {
        this.suggCont.setStyle('display', 'block');
    },
    hideList: function (event) {
        this.selectedItem = null;
        this.suggCont.setStyle('display', 'none');
        
        if (this.options.type == MG_COMBO && (event && event.target)) {
            var existsInCache = this.dropDown.getElements('a').some(function(item, index) {
                var status = item.get('html').trim() != "" && item.get('html').trim().toLowerCase() == this.target.value.trim().toLowerCase();
                if (status) {
                    this.targetId.value = item.id.toString().replace(this.options.listItemIdPrefix, '');
                }
                return status;
            }, this);
            
            if (! existsInCache && this.target.value.trim() != "" && !this.alreadyNulled) {
                this.targetId.value = "";
                this.onChange();
                this.alreadyNulled = true;
            } else {
				this.onChange();
			}
        }
		
		this.suggList.empty();
    },
    showDropDown: function (event) {
        if(this.dropDown.childNodes.length < 1 || 
           (this.dropDown.childNodes.length == 1 && (this.dropDown.getFirst().value == "" || this.dropDown.getFirst().value == "0"))) {
            return;
        }
		
        if (this.options.type != MG_COMBO || 
            (event && ! ((event.target && event.target.tagName.toLowerCase() == 'img')) && ! this.mustShowDD)) {
            this.mustShowDD = true;
            return;
        }
        
        if (event && event.target && event.target.tagName.toLowerCase() == 'img') {
            var iv = this.getIdValue();
            var tv = this.getTextValue();
            if ((iv == "" || iv == "0") && tv != "") {
                if(! (dtElements && dtElements[this.target.id] && dtElements[this.target.id].text == this.target.value)) {
                    var lo = this.dropDown.getLast();
                    if (lo.value != 0) {
                        this.dropDown.grab(new Element('option', {
                            'html': tv,
                            'value': ''
                        }));
                    } else {
                        lo.set('html', tv);
                    }
                    
                    this.dropDown.value = '';
                }
            }
        }
        
//        this.target.setStyle('display', 'none');
//        this.dropDownArrow.setStyle('display', 'none');
        this.ddCont.setStyle('display', 'block');
		var selected = this.dropDown.getElement('#' + this.options.listItemIdPrefix + this.targetId.value);
        if (selected) {
			if (null == this.ddScrolledTo) {
				new Fx.Scroll(this.dropDown).toElement(selected);
                this.ddScrolledTo = selected.id;
				selected.removeClass("selected");
				selected.addClass("selected");
			}
        }
		setTimeout(this.bound.enableMustHideDD, 100);
    },
	enableMustHideDD: function () {
		this.mustHideDD = true;
	},
    hideDropDown: function (event) {
        if (this.options.type != MG_COMBO) {
            return;
        }
        
        if (this.options.dropdownContainer) {
        	this.target.getParent('.custom_dropdown').removeClass('custom_dd_active');
        	return;
        }
        
        if (event && event.target.id != this.dropDown.id) {
            this.mustShowDD = false;
            return;
        }
        
        this.target.setStyle('display', 'inline');
        if (! this.options.dropdownContainer) {
        	this.dropDownArrow.setStyle('display', 'inline');
        }
        this.ddCont.setStyle('display', 'none');
        this.mustHideDD = false;
    },
    enable: function () {
//        this.target.disabled = false;
    	this.disabled = false;
        if (this.options.type == MG_COMBO) {
            this.dropDownArrow.setStyle('display', 'inline');
        }
    },
    disable: function () {
    	this.disabled = true;
        this.hideList();
        if (this.options.type == MG_COMBO) {
            this.hideDropDown();
            this.dropDownArrow.setStyle('display', 'none');
        }
        
//        this.target.disabled = true;
    },
    isDisabled: function () {
        return this.target.disabled;
    },
    isListEmpty: function () {
        return ! this.suggList.childNodes.length;
    },
    getIdValue: function () {
        return this.targetId.value;
    },
    getTextValue: function () {
        return this.target.value;
    },
    
    keyDown: function (event) {
    	if (this.disabled) {
    		return;
    	}
    	
        switch(event.key) {
            case 'tab':
                if (! this.selectedItem && this.suggList.childNodes.length > 0
                    && this.suggCont.getStyle('display') != 'none' ) {
                    this.selectItem({target: this.suggList.getFirst()});
                } else if(this.selectedItem) {
                    this.selectItem({target: this.selectedItem});
                }
                
                this.hideList();
                break;
                
            case 'enter':
            	var returnValue = false;
            	if (this.isListEmpty() && MG_SIMPLE == this.options.type) {
            		returnValue = true;
            	}
                if (! this.selectedItem && this.suggList.childNodes.length > 0 && ! this.options.maintainDefaultFormAction) {
                    this.selectItem({target: this.suggList.getFirst()});
                } else if(this.selectedItem) {
                    this.selectItem({target: this.selectedItem});
                }
                
                this.hideList();
                
                //overrides set return value
                if (this.options.maintainDefaultFormAction) {
                	return true;
                }
                
                return returnValue;
            break;
        }
        
        this.onKeyDown();
    },
    keyUp: function (event) {
    	if (this.disabled) {
    		return;
    	}
    	
        switch(event.key) {
            case 'up':
            case 'down':
        	   if(this.suggList.childNodes.length > 0) {
        	       this.moveListMarker(event.key);
        	   } else if (MG_COMBO = this.options.type) {
                   this.moveListMarker(event.key, this.dropDown);
			   }
               break;
               
            case 'esc':
                this.hideList();
                break;
                
            case 'enter':
                break;
                
            default:
                this.populateList();
            break;
        }
        
        this.onKeyUp();
    },
    onKeyUp: function () {
        this.fireEvent('keyup');
    },
    onKeyDown: function () {
        this.fireEvent('keydown');
    },
    
    clear: function () {
        if(dtElements && dtElements[this.target.id]) {
            this.target.value = "";
            this.target.fireEvent('blur');
        } else {
            this.target.value = "";
        }
        this.targetId.value = "";
        if (this.options.type == MG_COMBO) {
            this.dropDown.value = "";
        }
    },
    empty: function () {
        this.clear();
        
        this.suggList.empty();
        if (this.options.type == MG_COMBO) {
            this.dropDown.empty();
        }
        this.requestCount = 1;
    }
});
