/*
This file is part of Ext JS 3.4

Copyright (c) 2011-2013 Sencha Inc

Contact:  http://www.sencha.com/contact

GNU General Public License Usage
This file may be used under the terms of the GNU General Public License version 3.0 as
published by the Free Software Foundation and appearing in the file LICENSE included in the
packaging of this file.

Please review the following information to ensure the GNU General Public License version 3.0
requirements will be met: http://www.gnu.org/copyleft/gpl.html.

If you are unsure which license is appropriate for your use, please contact the sales department
at http://www.sencha.com/contact.

Build date: 2013-04-03 15:07:25
*/
Ext.ns('Ext.ux');

Ext.ux.Rating = Ext.extend(Ext.util.Observable, {
	// Configuration options
    starWidth: 16,
    split: 1,
    resetValue: '',
	defaultSelected: -1,	
    selected: -1,
    showTitles: true,    
    
	// Our class constructor
    constructor : function(element, config) {
        Ext.apply(this, config);
        Ext.ux.Rating.superclass.constructor.call(this);
        
        this.addEvents(
            'change',
            'reset'
        );
        
        this.el = Ext.get(element);
        this.init();
    },
    
    init : function() {
        var me = this;
        
		// Some arrays we are going to store data in
        this.values = [];
        this.titles = [];
        this.stars = [];
		
		// We create a container to put all our stars into      
        this.container = this.el.createChild({
            cls: 'ux-rating-container ux-rating-clearfix'
        });
				
        if(this.canReset) {
            this.resetEl = this.container.createChild({
                cls: 'ux-rating-reset',
                cn: [{
                    tag: 'a',
                    title: this.showTitles ? (this.resetTitle || 'Reset your vote') : '',
                    html: 'Reset'
                }]
            });
            this.resetEl.visibilityMode = Ext.Element.DISPLAY;
            
            this.resetEl.hover(function() {
                Ext.fly(this).addClass('ux-rating-reset-hover');
            }, function() {
                Ext.fly(this).removeClass('ux-rating-reset-hover');
            });
            
            this.resetEl.on('click', this.reset, this);
        }

		// We use DomQuery to select the radio buttons
		this.radioBoxes = this.el.select('input[type=radio]');
		// Then we can loop over the CompositeElement using each
        this.radioBoxes.each(this.initStar, this);
        
		// We use DomHelper to create our hidden input
		this.input = this.container.createChild({
			tag: 'input',
			type: 'hidden',
			name: this.name,
			value: this.values[this.defaultSelected] || this.resetValue
		});
		
		// Lets remove all the radio buttons from the DOM
		this.radioBoxes.remove();
		
        this.select(this.defaultSelected === undefined ? false : this.defaultSelected)

        if(this.disabled) {
            this.disable();
        } else {
			// Enable will set up our event listeners
            this.enable();
        }
    },

    initStar : function(item, all, i) {
        var sw = Math.floor(this.starWidth / this.split);
        
		// We use the name and disabled attributes of the first radio button 
		if(i == 0) {
	        this.name = item.dom.name;
	        this.disabled = item.dom.disabled;		
		}
		
		// Saving the value and title for this star
        this.values[i] = item.dom.value;
        this.titles[i] = item.dom.title;

        if(item.dom.checked) {
            this.defaultSelected = i;
        }
        
		// Now actually create the star!
        var star = this.container.createChild({
            cls: 'ux-rating-star'
        });
        
        var starLink = star.createChild({
            tag: 'a',
            html: this.values[i],
            title: this.showTitles ? this.titles[i] : ''
        });
        
        // Prepare division settings
        if(this.split) {
          var odd = (i % this.split);              
          star.setWidth(sw);
          starLink.setStyle('margin-left', '-' + (odd * sw) + 'px');
        }

		// Save the reference to this star so we can easily access it later
        this.stars.push(star.dom);
    },
    
    onStarClick : function(ev, t) {
        if(!this.disabled) {
            this.select(this.stars.indexOf(t));
        }
    },

    onStarOver : function(ev, t) {
        if(!this.disabled) {
            this.fillTo(this.stars.indexOf(t), true);
        }        
    },
    
    onStarOut : function(ev, t) {
        if(!this.disabled) {
            this.fillTo(this.selected, false);            
        }
    },
    
    reset : function(ev, t) {
        this.select(-1);
    },
    
    select : function(index) {
        if(index === false || index === -1) {
            // remove current selection in el
            this.value = this.resetValue;
            this.title = "";
			this.input.dom.value = '';    
            
            if(this.canReset) {
                this.resetEl.setOpacity(0.5);
            }
            
            this.fillNone();
            
            if(this.selected !== -1) {
                this.fireEvent('change', this, this.values[index], this.stars[index]);              
            }
            this.selected = -1;            
        }
        else if(index !== this.selected) {
			// Update some properties         
            this.selected = index;
            this.value = this.values[index];
            this.title = this.titles[index];
			
			// Set the value of our hidden input so the rating can be submitted			
			this.input.dom.value = this.value;
			
            if(this.canReset) {
                this.resetEl.setOpacity(0.99);
            }
            
			// the fillTo() method will fill the stars up until the selected one        
            this.fillTo(index, false);
            
			// Lets also not forget to fire our custom event!
            this.fireEvent('change', this, this.values[index], this.stars[index]);            
        }     
    },
    
    fillTo : function(index, hover) {
        if (index != -1) {
            var addClass = hover ? 'ux-rating-star-hover' : 'ux-rating-star-on';
            var removeClass = hover ? 'ux-rating-star-on' : 'ux-rating-star-hover';
             
			// We add a css class to each star up until the selected one   
            Ext.each(this.stars.slice(0, index+1), function() {
                Ext.fly(this).removeClass(removeClass).addClass(addClass);
            });

			// And then remove the same class from all the stars after this one
            Ext.each(this.stars.slice(index+1), function() {
                Ext.fly(this).removeClass([removeClass, addClass]);
            });
        }
        else {
            this.fillNone();
        }        
    },
    
    fillNone : function() {
        this.container.select('.ux-rating-star').removeClass(['ux-rating-star-hover', 'ux-rating-star-on']);
    },

    enable : function() {		
        if(this.canReset) {
            this.resetEl.show();
        }
        
        this.input.dom.disabled = null;
        this.disabled = false;
        
        this.container.removeClass('ux-rating-disabled');
 
		// We will be using the technique of event delegation by listening
    	// for bubbled up events on the container       
        this.container.on({
            click: this.onStarClick, 
            mouseover: this.onStarOver,
            mouseout: this.onStarOut,
            scope: this,
            delegate: 'div.ux-rating-star'
        });        
    },
	    
    disable : function() {
        if(this.canReset) {
            this.resetEl.hide();
        }
        
        this.input.dom.disabled = true;
        this.disabled = true;
        
        this.container.addClass('ux-rating-disabled');

        this.container.un({
            click: this.onStarClick, 
            mouseover: this.onStarOver,
            mouseout: this.onStarOut,
            scope: this,
            delegate: 'div.ux-rating-star'
        });        
    },
    
    getValue : function() {
        return this.values[this.selected] || this.resetValue;
    },
	
	destroy : function() {
		this.disable();
		this.container.remove();
		this.radioBoxes.appendTo(this.el);
		if(this.selected !== -1) {
			this.radioBoxes.elements[this.selected].checked = true;
		}
	}
});
