/**
 * Generates dynamic price bar
 */
var PriceBarBlock = Class.create();
PriceBarBlock.prototype = {
    initialize : function(mainText, headerText, footerText, denomTextLeft, denomTextRight, url, tab) {
        //default constructor
        this.mainText       = mainText;
        this.footerText     = footerText;
        this.headerText     = headerText;
        this.denomTextLeft  = denomTextLeft;
        this.denomTextRight = denomTextRight;
        this.url            = url;
        this.tab            = tab;
    },
    
    mainText : '',
    footerText : '',
    headerText : '',
    denomTextLeft : '',
    denomTextRight : '',
    url : '',
    tab : ''
};
    
var PriceBar = Class.create();
PriceBar.prototype = {
    
    _aTabs   : [],//internal array of tab captions
    _aBlocks : [],//internal array of block objects
    
    _containerWidth : 340,
    
    _aNewTab : [],//saves which tabs should be higlighted as new
    
    initialize : function() {
        //default constructor
        this._aTabs       = [];
        this._aBlocks     = [];
        this._aNewTab     = [];
        this._aNewTabText = []
    },
    
    /**
     * Returns an array of blocks that all share a tab name
     *
     * @param string tabName
     * @returns array
     */
    getBlocksByTabName : function(tabName) {
        var aBlocks = [];
        
        this._aBlocks.each( function(curBlock) {
            if (curBlock.tab == tabName) {
                aBlocks.push(curBlock);
            }
        });
        
        return aBlocks;
    },
    
    /**
     * Adds a tab caption to the pricebar
     *
     * @param string tabCaption the caption of the tab to display
     */
    addTab : function(tabName) {
        if (!tabName || this._aTabs.indexOf(tabName) > -1) {
            return;
        }
        
        this._aTabs.push(tabName);
    },
    
    /**
     * Sets which tab(s) should be displayed with the orange word "new" beside it
     *
     * @param string newTabName 
     */
    setTabAsNew : function(newTabName, newText) {
        if (!newTabName || this._aNewTab.indexOf(newTabName) > -1) {
            return;
        }
        
        this._aNewTab.push(newTabName);
        this._aNewTabText.push(newText);
    },
    
    /**
     * Adds a block object to the internal array
     *
     * @param PriceBarBlock objBlock     
     * @todo add some validation here?
     */
    addBlock : function(objBlock) {
        this._aBlocks.push(objBlock);
        
        //add the tab if one exists
        if (objBlock.tab) {
            this.addTab(objBlock.tab);
        }
    },
    
    /**
     * Renders the price bar in all it's glory
     *
     * @param string divId the id of the div where the price bar is gonna appear
     */
    render : function(divId, padding) {
        if (!$(divId)) {
            //something went wrong, we can't find where to render the pricebar            
            return;
        }

      	padding = parseInt(padding);

        // find the width of the parent's element
        // we could use prototype's getWidth() function
        // but it does not return an accurate width for 
        // hidden elements....so
        var parentEle = $(divId).up();
        var display = parentEle.getStyle('display');
        if (display != 'none' && display != null) { // Safari bug 
                 this._containerWidth = parentEle.offsetWidth - padding;
        } else {
            // hidden elements have 0 width
            // unhide the element temporary to get the width
            var originalDisplay = parentEle.style.display;
                parentEle.style.display = 'block';
                this._containerWidth = parentEle.offsetWidth - padding;
                parentEle.style.display = originalDisplay;
    	}

        
        //if no tabs just render the pricebar without tabs
        if (!this._aTabs.length) {
            this._renderTab('', divId);
        } else {            
            //render first tab and then show tab navigation
            this._renderTab(this._aTabs[0], divId);
            
            this._renderTabNav(divId, this._aTabs[0]);
        }
    },
    
    /**
     * Renders the tab navigation
     *
     * @param string divId
     * @param string focusTab name of the tab that currently has focus
     */
    _renderTabNav : function(divId, focusTab) {
        var objTabNav = new Element('div');
        objTabNav.className = 'priceTabNav';
        objTabNav.setStyle({
            'width' : this._containerWidth + 'px'
        });
        
        //thease are setup in reverse order because they are right float, so they stack starting from the right
        for (i=this._aTabs.length-1;i>=0;i--) {
            var tabName = this._aTabs[i];
            var hasFocus = (tabName == focusTab);
            
            //borders are friggin impossible to attach to tabs we attach them beside here
            objTabNav.insert(this._buildTabBorderElement(false, hasFocus, i));                                
            
            objTabNav.insert(this._buildTabElement(tabName, i, hasFocus, divId));            
            
            objTabNav.insert(this._buildTabBorderElement(true, hasFocus, i));                        
            
        }
        
        $(divId).insert(objTabNav);
    },
    
    /**
     * Builds and returns the border elements to place around focused tabs
     *
     * @param boolean isLeftSide whether we are building the left side or not, true we are, false we are doing right
     * @param booelan hasFocus whether the current tab we are building has focus or not
     * @param integer tabPos
     * @returns Element
     */
    _buildTabBorderElement : function(isLeftSide, hasFocus, tabPos) {
        if (hasFocus) {
            return this._buildActiveTabBorderElement(isLeftSide, tabPos);
        } else {
            return this._buildUnactiveTabBorderElement();
        }        
    },
    
    /**
     * Builds and returns an unactive tab border element
     *
     * @returns Element
     */
    _buildUnactiveTabBorderElement : function() {
	    var objBorder = new Element('div');
	    objBorder.className = 'priceTabBdr';
	    return objBorder;
    },
    
    /**
     * Builds and returns an active tab border element
     *
     * @param boolean isLeftSide
     * @param integer tabPos
     * @returns Element
     */
    _buildActiveTabBorderElement : function(isLeftSide, tabPos) {
        var objBorder = new Element('img');
        
        var isLast = (tabPos == this._aTabs.length - 1) ? true : false;
        
        objBorder.src = ((isLeftSide) ? '/images/pricebar/midtab_left.gif' : '/images/pricebar/' + ((isLast) ? 'last' : 'mid') + 'tab_right.gif');
        objBorder.className = 'priceTabBdrActive';
        
        
        return objBorder;
    },
    
    /**
     * Builds and returns a tab navigation element object
     *
     * @param string tabName
     * @param integer tabPos position of tab relative to left, zero index
     * @param boolean hasFocus whether the tab has focus or not, draw differently
     * @param string divId used for internal function calls
     * @returns Element
     */
    _buildTabElement : function(tabName, tabPos, hasFocus, divId) {
        var objTab = new Element('div').update(tabName);        
	    objTab.id = "priceBarTab"+tabName;
	    objTab.className = (hasFocus ? 'priceTabActive' : 'priceTab');
        
        if (!hasFocus) {
            objTab.observe('mouseover', function(event) {
                    this._renderTab(tabName, divId);                
                    this._renderTabNav(divId, tabName);                
            }.bind(this));
        }
        
        //if this is a "new" tab add the new text
        var newTabIndex = this._aNewTab.indexOf(tabName);
        if (newTabIndex > -1) {
            var objNew = new Element('span');
            objNew.update('&nbsp;&nbsp;' + this._aNewTabText[newTabIndex]);                        
            
            objNew.className = 'priceTabNewCaption';
            
            objTab.insert(objNew);                                    
        }
        
       return objTab;
       
    },
      
    /**
     * Displays all the blocks associated with a tab
     *
     * @param string tabName name of the tab to render
     * @param string divId the id of the div where all the html is supposed to go.
     */
    _renderTab : function(tabName, divId) {
        
        var objContainer = new Element('div');
        
        objContainer.className = 'priceCntr';
        objContainer.setStyle({
            'width' : this._containerWidth + 'px'
        });
        
        //stupid each() function doesn't have proper access to "this" keyword - until i realized i could bind this
        var aBlocks = this.getBlocksByTabName(tabName);
        for (i=0;i<aBlocks.length;i++) {            
            var objTmp = aBlocks[i];
            objContainer.insert(this._buildBlockElement(objTmp, i, aBlocks.length));                        
        }
        
        $(divId).innerHTML = '';
        $(divId).insert(objContainer);
        
        //post object orientation/aligment
        var blockTrim = 0;//the height of the bar container is higher than the actual block size, so we need to trim it
        
        var naturalWidth = 0;        
        objContainer.childElements().each(function(objChild) {
            naturalWidth += objChild.getWidth();            
        });
        
        objContainer.childElements().each(function(objChild) {       
                             
            var dynamicWidth   = parseInt(((this._containerWidth - naturalWidth) / objContainer.childElements().length) + objChild.getWidth());
            var dynamicPadding = parseInt(((objContainer.getHeight()-blockTrim) - (objChild.getHeight())) / 2);
            var dynamicHeight  = ((objContainer.getHeight()-blockTrim)-dynamicPadding);
            
            //esure values are all over zero at least
            dynamicWidth   = (dynamicWidth > 0) ? dynamicWidth : 0;
            dynamicPadding = (dynamicPadding > 0) ? dynamicPadding : 0;
            dynamicHeight  = (dynamicHeight > 0) ? dynamicHeight : 0;
            
            objChild.setStyle({
                'width' : dynamicWidth + 'px',
                'paddingTop' : dynamicPadding + 'px',
                'height' :  dynamicHeight + 'px'
            });
            
        }.bind(this));
    },
    
    /**
     * Takes a PriceBarBlock object and constructs a prototype Element object which can be attached to the pricebar
     *
     * @param PriceBarBlock objBlock
     * @param integer blockPos position from left of current block being generated - zero index
     * @param integer totalBlocks number of total blocks being rendered - used to width construction
     * @returns Element
     */
    _buildBlockElement : function(objBlock, blockPos, totalBlocks) {
        var objContainer = new Element('div');
        var width = parseInt(this._containerWidth / totalBlocks);
        
        if (objBlock.headerText) {
            objContainer.insert(this._buildHeaderTextElement(objBlock.headerText));
        }
        
        objContainerMainText = new Element('div');//wrapper div for the number, and denom elements
        objContainerMainText.setStyle({
            'textAlign' : 'center',
            'verticalAlign' : 'text-top'
        });
        if (objBlock.denomTextLeft) {
            objContainerMainText.insert(this._buildDemonElement(objBlock.denomTextLeft, (objBlock.mainText) ? objBlock.mainText.length : 0, width, true));
        }
        
        if (objBlock.mainText) {
            objContainerMainText.insert(this._buildMainTextElement(objBlock.mainText))
        }
                        
        if (objBlock.denomTextRight) {
            objContainerMainText.insert(this._buildDemonElement(objBlock.denomTextRight, (objBlock.mainText) ? objBlock.mainText.length : 0, width, false));
        }
        
        //add wrapper div for main elements           
        objContainer.insert(objContainerMainText);                        
        
        
        if (objBlock.footerText) {
            objContainer.insert(this._buildFooterTextElement(objBlock.footerText));
        }
        
        objContainer.className = 'priceBlock';        
        
        if (objBlock.url) {
            objContainer.observe('click', function(event) {
                document.location = objBlock.url;
            });
        }
        
        return objContainer;
    },
    
    /**
     * Builds the main text element and set's the style
     *
     * @param string mainText
     * @returns Element
     */
    _buildMainTextElement : function(mainText) {
        var objMainText = new Element('div').update(mainText);
        objMainText.className = 'priceText';
        return objMainText;
    },
    
    /**
     * Builds and returns the denomination element
     *
     * @param string denomText
     * @param integer mainTextLen use to slightly position the denomination sign better
     * @param integer blockWidth width of the block this denomination text is being displayed in
     * @param boolean onLeftSide whether to display on left side or right side - default to left side
     * @returns Element
     */
    _buildDemonElement : function(denomText, mainTextLen, blockWidth, onLeftSide) {
        var objLabel = new Element('label');
        
         //if there are more than 1 char we assume 1st char is $ and the rest are text
        if (denomText.length > 1) { 
        	//objLabel.update(denomText.substring(0,1)+'&nbsp;<span style="font-size: 7pt;">'+denomText.substring(1)+'</span>');
        	objLabel.update('<span style="font-size: 7pt;vertical-align:top;">'+denomText+'</span>');
        }
        else {
        	objLabel.update(denomText);
        }
        var objDenom = new Element('div').insert(objLabel);
        
        objDenom.className = 'priceTextDenom';
        
        return objDenom;
    },
    
    /**
     * Builds the header text element for a block
     *
     * @param string headerText
     * @return Element
     */
    _buildHeaderTextElement : function(headerText) {
        var objHeaderText = new Element('div').update(headerText);
        objHeaderText.className = 'priceHdr';
        
        //need to adjust line-height for longer text (goes on two lines)               
        objHeaderText.setStyle({
            'lineHeight' : '10px'
        });
        
        return objHeaderText;
    },
    
    /**
     * Builds and returns a spacer element (blank header for proper spacing of elements below it)
     *
     * @return Element
     */
    _buildHeaderSpacerElement : function() {
        var objSpacer = new Element('div');
        objSpacer.className = 'priceSpacer';
        return objSpacer;
    },
    
    /**
     * Builds the footer text element for a block
     *
     * @param string footerText
     * @return Element
     */
    _buildFooterTextElement : function(footerText) {
        var objFooterText = new Element('div').update(footerText);
        objFooterText.className = 'priceFtr';
        
        return objFooterText;
    }
};

