/** @namespace Root namespace for Clearpix Website JavaScript */
var clearpix = {};

var HoverSwap = new Class(/** @lends HoverSwap.prototype */ {
    Implements : [Options, Events],
    /**
     * Instance options
     * 
     * <ul>
     *   <li>handle_out_class: {String} The name of a CSS class to apply to
     *   inactive handles.</li>
     *   <li>handle_over_class:{String} The name of a CSS class to apply to
     *   active handles. </li>
     *   <li>element_out_class: {String} The name of a CSS class to apply to
     *   inactive elements.</li>
     *   <li>element_over_class: {String} The name of a CSS class to apply to
     *   inactive elements.</li>
     * </ul>
     * */
    options : {
        'handle_out_class' : 'swap-out-handle',
        'handle_over_class' : 'swap-over-handle',
        'element_out_class' : 'swap-out',
        'element_over_class' : 'swap-over'
    },
    /**
     * "Swaps" elements when specific handles are activated.
     * 
     * This class accepts two lists of Elements: handles and the elements those
     * handles will swap. Each element in the list of handles will be
     * associated with the corresponding element in the list of swappable
     * elements. When the mouse pointer enters a handle element, the
     * corresponding swap element will be "activated." Active elements and
     * handles have the "swap-over" CSS class, while inactive elements and
     * handles have the "swap-out" CSS class. These classes can be configured
     * as Options.
     * 
     * @constructs
     * @requires MooTools v1.2+
     * @param {Element[]} handles Iterable list of Element objects to use as
     * the swap handles
     * @param {Element[]} elements Iterable list of Element objects to use as
     * the swap target
     * @param {Object} [options]
     * */
    initialize : function(handles, elements, options) {
        this.setOptions(options);
        this.elements = {};
        Array.each(handles, function(handle, idx) {
            this.elements[handle.id] = elements[idx];
            handle.addClass(this.options.handle_out_class);
            elements[idx].addClass(this.options.element_out_class);
            handle.addEvent('mouseover', function(e) {
                this.activate(e.target);
            }.bind(this));
        }, this);
    },
    /**
     * Activates an element given a handle. Fires a 'swap' even when complete
     * @param {String|Element} handle The handle to use to activate an element
     */
    activate : function(handle) {
        for(handle_id in this.elements) {
            this.swap_out($(handle_id));
        }
        this.swap_in(handle);
        this.fireEvent('swap', [$(handle)]);
    },
    /** 
     * Sets the appropriate CSS classes on a handle and its corresponding
     * element to mark them as active
     * @param {String|Element} handle Handle to activate
     * @private
     * */
    swap_in : function(handle) {
        handle = $(handle);
        var elm = this.elements[handle.id];
        handle.removeClass(this.options.handle_out_class);
        handle.addClass(this.options.handle_over_class);
        elm.removeClass(this.options.element_out_class);
        elm.addClass(this.options.element_over_class);
    },
    /** 
     * Sets the appropriate CSS classes on a handle and its corresponding
     * element to mark them as inactive
     * @param {String|Element} handle Handle to deactivate
     * @private
     * */
    swap_out : function(handle) {
        handle = $(handle);
        var elm = this.elements[handle.id];
        handle.removeClass(this.options.handle_over_class);
        handle.addClass(this.options.handle_out_class);
        elm.removeClass(this.options.element_over_class);
        elm.addClass(this.options.element_out_class);
    }
});

var TabBox = new Class(/** @lends TabBox.prototype */{
    Implements : [ Options, Events ],
    
    /**
     * Instance Options
     * 
     * <ul>
     *   <li>active_class: CSS class to add to active tabs and
     *   panels</li>
     * </ul>
     */
    options : {
        active_class : 'active'
    },
    
    /**
     * Display a tabbed user interface box.
     * 
     * Given a list of tabs and panels, this class will construct a
     * dynamic tabbed user interface. Each tab element will be
     * associated with a tab panel element based on their respective
     * list indices (i.e. clicking the first tab element will activate
     * the first tab panel element, etc.). 
     * 
     * Adapted from the TabBox MooTools class by
     * Dustin C. Hatch <admiralnemo@gmail.com>
     * @constructs
     * @param {Element[]} tabs An iterable list of tab elements
     * @param {Element[]} panels An iterable list of tab panels
     * @param {Object} [options]
     */
    initialize : function(tabs, panels, options) {
        this.setOptions(options);
        this.tabs = tabs;
        this.panels = panels;
        this.tabs.each(function(elem, idx) {
            elem.addEvent('click', function() {
                this.flipTo(idx);
            }.bind(this));
        }.bind(this));
        
        var tabFlipped = false;
        if (window.location.hash && window.location.hash['substring']) {
            //If a tab ID is given in the URL as a document-fragment
            //identifier, switch to that tab immediately.
            var selectedTab = window.location.hash.substring(1);
            if (selectedTab) {
                this.panels.each(function(elem, idx) {
                    if (elem.id == selectedTab) {
                        this.flipTo(idx);
                        tabFlipped = true;
                    }
                }.bind(this));
            }
        }
        if (!tabFlipped) {
            this.flipTo(0);
        }
    },
    
    /**
     * Activate a tab panel given a tab index
     * 
     * This method will "deactivate" all tabs and tab panels except
     * those identified by the given index by removing the "active"
     * CSS class (which can be defined as an instance option) and
     * "activate" the selected tab/panel by adding the "active" CSS
     * class.
     * 
     * Fires {@link TabBox#event:flip}
     *  
     * @param {int} tab_idx The tab index to activate
     */
    flipTo : function(tab_idx) {
        var activePanel;
        var previousTab;
        var previousPanel;
        this.tabs.each(function(elem, idx) {
            if(elem.hasClass(this.options.active_class)) {
                previousTab = idx;
            }
            if (idx == tab_idx) {
                elem.addClass(this.options.active_class);
            } else {
                elem.removeClass(this.options.active_class);
            }
        }.bind(this));
        this.panels.each(function(elem, idx) {
            if(elem.hasClass(this.options.active_class)) {
                previousPanel = elem;
            }
            if (idx == tab_idx) {
                elem.addClass(this.options.active_class);
                elem.setStyle('display', '');
                activePanel = elem;
            } else {
                elem.removeClass(this.options.active_class);
                elem.setStyle('display', 'none');
            }
        }.bind(this));
        this.fireEvent('flip', [activePanel, previousPanel,
                                tab_idx, previousTab]);
    /**
     * @name TabBox#flip
     * @event
     * @param {Element} activePanel The newly activated tab panel
     * @param {Element} previousPanel The previously active tab panel
     * @param {int} tab_idx Index of the newly activated tab
     * @param {int} previousTab Index of the previously active tab
     */
    }
});

var PhotoGallery = new Class({/** @lends PhotoGallery.prototype */
    Implements : Options,
    options : {
        images_baseurl : '',
        projection_height : '360px',
        projection_width : '480px',
        slide_active_class : 'active',
        slide_class : 'slide',
        slide_height : null,
        slide_width : null,
        thumbs_baseurl : ''
    },
    /**
     * A simple photo gallery
     * 
     * The gallery consists of a "projection" where images are displayed, and
     * a "film strip" which consists of "slides" or image thumbnails. Clicking
     * on a slide causes the corresponding image to be projected. 
     * 
     * @param {Element} projection The element where images are "projected"
     * @param {Element} filmstrip The element containing the "film strip"
     * @param {object} options Options
     * @constructs
     */
    initialize : function(projection, filmstrip, options) {
        this.projection = $(projection);
        this.filmstrip = $(filmstrip);
        this.setOptions(options);
        this.slides = [];
    },
    
    /**
     * Add images to the film strip
     * @param {array} images A of paths of images to add
     */
    add_images : function(images) {
        images.each(function(item) {
            this._preload_projection(item);
            var slide = new Element('span', {
                'class' : this.options.slide_class
            });
            slide.grab(new Element('img', {
                'src' : [this.options.thumbs_baseurl, item].join('/'),
                'events' : {
                    'click' : function(e) {
                        this.slides.each(function(i) {
                            i.removeClass(this.options.slide_active_class);
                        }.bind(this));
                        e.target.getParent().addClass(
                            this.options.slide_active_class);
                        this.project_image(item);
                    }.bind(this)
                }
            }));
            this.filmstrip.grab(slide);
            this.slides.push(slide);
        }.bind(this));
    },
    
    /**
     * Project an image from the film strip
     * @param {string} image The relative path to the image to project
     */
    project_image : function(image) {
        var fx_out = new Fx.Tween(this.projection, {
            'onComplete' : function() {
                var fx_in = new Fx.Tween(this.projection);
                this.projection.empty();
                this.projection.setStyles({
                    'background-image' : 'url("{base}/{name}")'.substitute({
                        'base' : this._get_projection_baseurl(),
                        'name' : image
                    })
                 });
                fx_in.start('opacity', 1);
                this.projection.grab(new Element('a', {
                    'href' : [this.options.images_baseurl, image].join('/')
                }));
            }.bind(this)
        });
        fx_out.start('opacity', 0);
    },
    
    _get_projection_baseurl : function() {
        if (this.options.projection_height && this.options.projection_width) {
            return '{base}/{w}x{h}'.substitute({
                'base' : this.options.thumbs_baseurl,
                'w' : parseInt(this.options.projection_width),
                'h' : parseInt(this.options.projection_height)
            });
        } else {
            return this.options.thumbs_baseurl;
        }
    },
    
    _preload_projection : function(image) {
        var img = new Image();
        img.src = [this._get_projection_baseurl(),
                   image].join('/');
    }
});

window.addEvent('domready', function() {
   $$('li.nav-root').each(function(elm) {
      var dropdown = elm.getElement('ul.nav-sub');
      if(dropdown) {
          elm.addEvent('mouseenter', function(e) {
              this.reveal();
          }.bind(dropdown));
          elm.addEvent('mouseleave', function(e) {
              this.dissolve();
          }.bind(dropdown));
      }
   });
});

if(Browser.ie6) {
    $$('img').each(function(img) {
        if(!img.hasClass('ignore_png') &&
                img.src.toLowerCase().indexOf('.png') != -1) {
            var filter = img.getParent().currentStyle.filter;
            if(filter.indexOf("AlphaImageLoader") == -1) {
                var img_dims = img.getSize();
                new Element('div', {
                    'id' : img.id,
                    'styles' : {
                        'filter' : "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + img.src + "')",
                        'width' : img_dims.x,
                        'height' : img_dims.y
                    }
                }).replaces(img);
            }
        }
    });
}

clearpix.HomePage = new Class(/** @lends HomePage.prototype */{
    /**
     * Singleton wrapper class for the ClearPix Website home page 
     * @constructs
     * @memberOf clearpix
     * @requires HoverSwap {@link HoverSwap}
     * */
    initialize : function() {
        window.addEvent('domready', function() {
            var re = new RegExp("(swap-)(\\D+)(\\d)");
            var swapper = new HoverSwap($$('.home-rollovers li'),
                                        $$('.rollover-quip'), {
                'onSwap' : function(handle) {
                    //When a swap is complete, replace the images on the page
                    //with the newly activated product class
                    var cls = handle.id.replace('-handle', '');
                    $$('img.swappable').each(function(elm) {
                        var new_src = elm.src.replace(re, '$1' + cls + '$3');
                        elm.src = new_src;
                    });
                }
            });
            swapper.activate('cameras-handle');
            //Preload images for each of the three swap states
            ['cameras', 'servers', 'software'].each(function(cls) {
                $$('img.swappable').each(function(elm) {
                    var tmp_img = new Image();
                    tmp_img.src = elm.src.replace(re, '$1' + cls + '$3');
                });
            });
        });
    }
});

clearpix.ProductCategoryPage = new Class(/** @lends ProductCategoryPage.prototype */{
   /**
    * Singleton wrapper class for product category pages
    * @constructs
    * @memberOf clearpix
    */
    initialize : function() {
        var tabbox = new TabBox($$('.tabbox.products li.tab'),
                $$('.tabbox.products .tab-panel'));
    }
});

clearpix.ContactUsPage = new Class(/** @lends ContactUsPage.prototype */ {
    /**
     * Singleton wrapper class for the contact us page
     * @constructs
     * @memberof clearpix
     */
    initialize : function() {
        var tabbox = new TabBox($$('.tabbox.contact li.tab'),
                $$('.tabbox.contact .tab-panel'));
    }
});

clearpix.CamerasPage = new Class(/** @lends CamerasPage.prototype */ {
    /**
     * Singleton wrapper class for the contact us page
     * @constructs
     * @memberof clearpix
     */
    initialize : function() {
        var tabbox = new TabBox($$('.tabbox.cameras li.tab'),
                $$('.tabbox.cameras .tab-panel'));
    }
});

clearpix.NewsPage = new Class(/** @lends CamerasPage.prototype */ {
    /**
     * Singleton wrapper class for the contact us page
     * @constructs
     * @memberof clearpix
     */
    initialize : function() {
        var tabbox = new TabBox($$('.tabbox.news li.tab'),
                $$('.tabbox.news .tab-panel'));
    }
});

clearpix.ProductPage = new Class(/** @lends ProductPage.prototype */ {
    /**
     * Singleton wrapper class for the individual product pages
     * @constructs
     * @memberof clearpix
     */
    initialize: function() {
        var fade_speed = 100;
        var re = new RegExp('/thumbs/[0-9]+x[0-9]+/');
        
        var replace_full = function(e) {
            var fx = new Fx.Tween(this, {
                'property' : 'opacity',
                'duration' : fade_speed,
                'onComplete' : function() {
                    this.getParent().getElement('.vspacer').hide();
                    this.full_src = this.src;
                    this.src = this.src.replace(re, '/images/');
                    this.removeEvents('click');
                    this.addEvent('click', replace_thumb.bind(this));
                    this.set('tween', {'duration' : fade_speed}).fade('in');
                }.bind(this)
            });
            fx.start('1', '0');
        };
        
        var replace_thumb = function(e) {
            var fx = new Fx.Tween(this, {
                'property' : 'opacity',
                'duration' : fade_speed,
                'onComplete' : function() {
                    this.getParent().getElement('.vspacer').show();
                    this.src = this.full_src;
                    this.removeEvents('click');
                    this.addEvent('click', replace_full.bind(this));
                    this.set('tween', {'duration' : fade_speed}).fade('in');
                }.bind(this)
            });
            fx.start('1', '0');
        };
        
        $$('.product-pane .image img').each(function(elem) {
            elem.setStyle('cursor', 'pointer');
            elem.addEvent('click', replace_full.bind(elem));
            new Image().src = elem.src.replace(re, '/images/');
        });
    }
});

clearpix.DownloadsPage = new Class(/** @lends DownloadsPage.prototype */ {
    /**
     * Singleton wrapper class for the downloads page
     * @constructs
     * @memberof clearpix
     */
    initialize : function() {
        var tabbox = new TabBox($$('.tabbox.downloads li.tab'),
                $$('.tabbox.downloads .tab-panel'));
    }
});

clearpix.SupportPage = new Class(/** @lends SupportPage.prototype */ {
    /**
     * Singleton wrapper class for the support page
     * @constructs
     * @memberof clearpix
     */
    initialize : function() {
        var tabbox = new TabBox($$('.tabbox.support li.tab'),
                $$('.tabbox.support .tab-panel'));
    }
});

clearpix.GalleryPage = new Class(/** @lends GalleryPage.prototype */ {
    /**
     * Singleton wrapper class for gallery pages
     * @constructs
     * @memberof clearpix
     */
    initialize : function(base_url) {
        this.base_url = base_url;
        window.addEvent('domready', this.render_gallery.bind(this));
    },
    
    render_gallery : function() {
        var req = new Request.JSON({
            'url' : '',
            'onSuccess' : function(responseJSON) {
                this.gallery = new PhotoGallery('projection',
                        $$('.filmstrip')[0], {
                    'thumbs_baseurl' : this.base_url + 
                        responseJSON.thumbs_baseurl,
                    'images_baseurl' : this.base_url + 
                        responseJSON.images_baseurl
                });
                this.gallery.add_images(responseJSON.images);
            }.bind(this)
        });
        req.get();
    }
});

