var fxISC = new Class( {
    
    Implements: [ Options ],
    
    options : {

        // FxMorph
        imgContainer : "wrap",
        
        // FxMorph
        highlightClass : "highlightBox",
        
        highlightClassBorders : [ "#000", "#fff" ],
        
                
        blockPreviewWidth       : 430,
        blockLargeWidth         : 300,
        blockWidthFactor        : 1.5,
        
        blocksContainerId       : "blocksContainer",
        blockClass              : "block",
        blockTeaserClass        : "blockTeaser",
        blockTeaserTextClass    : "blockTeaserText",
        blockPreviewClass       : "blockPreview",
        blockPreviewCloserClass : "blockPreviewCloser",

        blockTeaserFxTop        : 150,
        blockTeaserFxHeight     : 200,
        
        blockPreviewHeight      : 'auto'
        
        
    },
    
    initialize: function( Options ) {

        this.setOptions( Options );

        // custom effect
        this.fxStart = function() { return arguments[0].start( arguments[1] ) };

        if ( $(this.options.blocksContainerId) ) this.setupFxBlocks();

        // fire that fx on resize of body
        this.fxBodyWidth = new Fx.Tween( this.options.imgContainer, { 
            transition  : Fx.Transitions.Quad.easeIn, 
            duration    : 500, 
            ignore      : 1 
        } );

        // custom effect
        this.fxStart = function() { return arguments[0].start( arguments[1] ) };
        
        this.addFxBodyWidth();
        
        this.addHighlightMorphing();
    },    

    fxBodyWidth_: function( el ) {
        
        /*
            AN - changed 100122 for improved ie6 support due to lacking max-width support
        */
        
        el = $( el );

        var dim        = $$("body")[0].getCoordinates();
        var elWidth    = el.getStyle( "width"     ).toInt();
        var elMaxWidth = Browser.Engine.trident && Browser.Engine.version < 5 ? 1280 : el.getStyle( "max-width" ).toInt();
        var elMinWidth = Browser.Engine.trident && Browser.Engine.version < 5 ? 990  : el.getStyle( "min-width" ).toInt();
        
        if ( Browser.Engine.trident && Browser.Engine.version < 5 ) { 

            this.fxBodyWidth.start( "width", Math.min( dim.width, 1280 ) );
            
        } else {
            
            if ( elWidth < elMinWidth || elWidth > elMaxWidth ) return false;
            this.fxBodyWidth.start( "width", dim.width );
        }
        

        return true;
    },
    
    addFxBodyWidth : function() {
        
        window.addEvent( "resize", this.fxBodyWidth_.create( {
            
            arguments : [ this.options.imgContainer ],
            delay     : 500,
            bind      : this

        } ) );
        
        return this.fxBodyWidth_( this.options.imgContainer );
    },

    highlightBox: function( fx_, obj, cancel ) {
        
        if ( this.highFX && cancel ) this.highFX.cancel();
        
        this.highFX = this.fxStart( fx_, obj );
        
        return true;
    },

    addHighlightMorphing: function() {
        
        var els = $$( "." + this.options.highlightClass );
        
        if ( !els.length ) return false;
        
        var borders = this.options.highlightClassBorders;

        els.each( function( el ) {        

            el.addEvent( "mouseenter", this.highlightBox.bind( this, [
                    
                    new Fx.Morph( el, { 
                        transition: Fx.Transitions.Quad.easeIn, 
                        duration: 250, 
                        "link" : "cancel",
                        "onCancel" : el.removeProperty( "style" )
                         } ), 
                    {
                        "background-color" : borders,
                        "color"            : $A(borders).reverse()
                    } ]
            
            ) );
        
            el.addEvent( "mouseleave", this.highlightBox.bind( this, [
        
                    new Fx.Morph( el, { transition: Fx.Transitions.Quad.easeOut, duration: 250, "link" : "cancel","onCancel" : el.removeProperty( "style" ) } ), 
                    { 
                        "background-color" : $A(borders).reverse(),
                        "color"            : borders
                    },1 ]
            ) );        
        
        }.bind ( this ) );

        return true;
    },
    
    setupFxBlocks: function() {
        
        this.fxBlocks       = {};
        this.fxTeasers      = {};
        this.fxTeasersText  = {};
        this.fxPreviews     = {};
        
        this.fxBlocks.els       = $$( "." + this.options.blockClass );
        this.fxBlocks.count     = this.fxBlocks.els.length;
        this.fxBlocks.current   = -1;
        this.fxBlocks.selected  = -1;
        this.fxBlocks.width     = this.fxBlocks.els[0].getStyle( "width" ).toInt();
        this.fxBlocks.fullWidth = this.fxBlocks.width * this.fxBlocks.count;
        this.fxBlocks.widths    = this.calculateBlockWidths();
        
        this.fxTeasers.els      = $$( "." + this.options.blockTeaserClass );
        this.fxTeasersText.els  = $$( "." + this.options.blockTeaserTextClass );
        this.fxPreviews.els     = $$( "." + this.options.blockPreviewClass );
        
        // cancelable effects
        this.FXs = [];
        this.PreviewFXs = "";
        
        this.addBlockEvents();
        this.addPreviewCloserEvent();
    },
    
    calculateBlockWidths: function() {
        
        var fxBlocks = this.fxBlocks;
        
        // calculates the 3 widths a block may take: small, normal, large
        
        // withoutPreview
        var large  = this.options.blockLargeWidth || fxBlocks.width * this.blockWidthFactor;
        var normal = fxBlocks.width
        var small  = ( fxBlocks.fullWidth - large ) / ( fxBlocks.count - 1 );
        
        //withPreview
        var normal_ = ( fxBlocks.fullWidth - this.options.blockPreviewWidth ) / ( fxBlocks.count - 1 );
        var large_  = normal_ * 1.5;
        var small_  = ( fxBlocks.fullWidth - this.options.blockPreviewWidth - large_ ) / ( fxBlocks.count - 2 );
        
        return {

            "withPreview"    : [ Math.round(small_), Math.round(normal_), Math.round(large_) ],
            "withoutPreview" : [ Math.round(small),  Math.round(normal),  Math.round(large)  ]
        };
    },

    calculateResizeBlockWidths: function( i ) {
        
        var widths = {};
        var where  = this.fxBlocks.selected > -1
            ? "withPreview"
            : "withoutPreview";
        
        var w = i > -1 && i !== this.fxBlocks.selected
            ? 0
            : 1;
        
        var sum = 0;
        
        for( var j = 0; j < this.fxBlocks.count; j++ ) {
            
            widths[j] = {
                
                "width" : [ 
                    
                    this.fxBlocks.selected === j
                        ? this.options.blockPreviewWidth
                        : i === j
                            ? this.fxBlocks.widths[ where ][ 2 ]
                            : this.fxBlocks.widths[ where ][ w ]
                ]
            };
            
            sum += widths[j][ "width" ][0];
        }

        // correct some round problems
        widths[ ( this.fxBlocks.selected + 1 ) % 4 ][ "width" ][0] += this.fxBlocks.fullWidth - sum;
        
        return widths;
    },

    logWidths: function( w ) {
        
        //return console.log( w[0]["width"][0], w[1]["width"][0], w[2]["width"][0], w[3]["width"][0] );
    },

    log : function( mixed, nl ) {
        
        if ( nl ) new Element( "br" ).inject( $( "console" ), "top" );
        
        new Element( "span", { "text" : ( 
            
            $type( mixed ) === "array" 
                ? mixed.join( ",", mixed ) 
                : ( $type( mixed ) === "object" 
                    ? mixed.toQueryString()
                    : mixed ) + " " )
            
            } ).inject( $( "console" ), "top" );
        
    },
        
    cancelFXs: function() {
        
        this.FXs.each( function( fx ) {
            
            //console.log( 
                fx.cancel()
            //, "cancel" );
        
        }.bind( this ) );
        
        this.FXs.empty();
    },


    addBlockEvents: function() {
        
        $each( this.fxBlocks.els, function( block, i ) {
            
            block.addEvent( "mouseenter", this.eventMouseEnter.bind( this, i ) );
            block.addEvent( "mouseleave", this.eventMouseLeave.bind( this, i ) );
            block.addEvent( "click",      this.eventMouseClick.bind( this, i ) );

        }.bind( this ) );           
        
        return true;        
    },
    
    eventMouseLeave: function( i ) {
        
        this.fxBlocks.disableClick = 0
         
        this.fxBlocks.current = -1;
        
        this.mouseLeaveDelayId = this.manageBlocks.delay( 100, this, -1 );
        
        //this.resetBlockTeaser.delay( 100, this );
        
        return true;
    },

    eventMouseEnter: function( i ) {
        
        this.cancelFXs();
        
        // cancel mouseleave event
        if ( this.mouseLeaveDelayId ) {
            
            $clear( this.mouseLeaveDelayId );
            this.mouseLeaveDelayId = null;
        }
        
        this.fxBlocks.current = i;
        
        return this.manageBlocks( i );
    },
    
    eventMouseClick: function( i ) {
        
        if ( this.fxBlocks.selected === i || this.fxBlocks.disableClick ) return false;

        this.resetPreviews(i);
        
        return this.manageBlocks( i, 1 );
    },
    
    manageBlocks: function( i, fromClick ) {
        
        var resizeWidths = this.calculateResizeBlockWidths( i );
        this.cancelFXs();

        i = $defined( i ) ? i : -1;

        //console.log( "manageBlocks", i, fromClick );

        this.resetBlockTeaser( i );

        var fx1 = new Fx.Elements( this.fxBlocks.els, { 
            
            "link"          : "cancel",
            "onComplete"    : function() {
                
                this.TeaserFX( i );
            
            }.bind( this )
        } );

        var fx2 = new Fx.Elements( this.fxBlocks.els, { 
            
            "link"          : "cancel",
            "onComplete"    : function() {
                
                this.PreviewFX( i );
            
            }.bind( this )
        } );

        if ( fromClick ) return fx2.start( resizeWidths );

        return this.FXs.include( fx1.start( resizeWidths ) );
    },

    TeaserFX: function( i ) {
        
        if ( i < 0  ) return false;
        if ( this.fxBlocks.selected > -1 ) return false;
        
        this.cancelFXs();
        
        var teaser     = this.fxTeasers.els[ i ];
        var teaserText = this.fxTeasersText.els[ i ]; 


        // 2. change height of teaser
        var fx2 = new Fx.Tween( teaser, { 
            
            "link"          : "cancel",
            "duration"      : 250,
            "onComplete"    : function() {
                
                teaserText.show();
                teaserText.tween( "color", "#fff" );
            
            }.bind( this ),
            
            "onCancel"      : function() {
                
                teaserText.hide();
                teaserText.removeProperty( "style" );
                
            }.bind( this )
            
        } );

        // 1. change top of teaser
        var fx1 = new Fx.Tween( teaser, { 
            
            "link"          : "cancel",
            "onComplete"    : function() {
                
                this.FXs.include( fx2.start( "height", this.options.blockTeaserFxHeight ) );
            
            }.bind( this ),
            
            "onCancel"      : function() {
                
                teaser.removeProperty( "style" );
                
            }.bind( this )
            
        } );

        return this.FXs.include( fx1.start( "top", this.options.blockTeaserFxTop ) );
    },
    
    PreviewFX: function( i ) {

        // cancel active preview FX
        if ( this.PreviewFXs ) this.PreviewFXs.cancel();
        
        // either now or onComplete, not sure
        this.fxBlocks.selected = i;
        
        
        var block        = this.fxBlocks.els[ i ];
        var blockTeaser  = this.fxTeasers.els[i].hide();
        // probably better to set height directly in css
        var blockPreview = this.fxPreviews.els[ i ].show().setStyle( "height", this.options.blockPreviewHeight );
        
        var fx = new Fx.Tween( blockPreview, { 
        
            "link"          : "cancel",
            "onCancel"    : function() {
                
                blockPreview.removeProperty( "style" );
            }
        } );
        
        this.PreviewFXs = new Fx.Morph( this.options.blocksContainerId, { 
        
            "link"          : "cancel",
            "onComplete"    : function() {
                
                this.PreviewFXs = fx.start( "opacity", 0, 1 );
            
            }.bind( this ),
            
            "onCancel"      : function() {
                
                blockPreview.hide().removeProperty( "style" );
                blockTeaser.show();
            
            }.bind( this )
        
        } );
        
        this.fxTeasers.els.each( function( teaser ) {
            
            teaser.setStyle( "top", this.options.blockTeaserFxTop);
            
        }.bind( this ) );
        
        return this.PreviewFXs.start( {
            
            "background-position" : "-4px -265px",
            "height"              : 265
        } );
    },

    resetPreviews: function( i ) {

        this.fxBlocks.selected = i;
        
        this.fxBlocks.disableClick = 1;

        var blockPreviewIndices = this.fxPreviews.els.map( function( preview, j ) { 
            
            return preview.isDisplayed() ? j : null
        
        } ).clean();

        blockPreviewIndices.each( function( k ) {
            
            this.fxPreviews.els[ k ].setStyle( "opacity", 0 ).hide();
            this.fxTeasers.els[ k ].show();
            
        }.bind( this ) );

        if ( i > -1 ) {
            
            this.fxTeasers.els[i].hide();
            this.resetBlockTeaser( i );
            return true;
        
        } else {
            
            this.fxBlocks.els.removeClass( "smaller" );
            this.fxTeasers.els.removeProperty( "style" );
            this.fxTeasersText.els.removeProperty( "style" );
            this.manageBlocks(-1);
        }
        
        new Fx.Morph( this.options.blocksContainerId, { 
            
            "link"          : "cancel"
        
        } ).start( {
            
            "background-position" : "-4px 0",
            "height"              : 530
        
        } );        

        return true;
    }, 

    resetBlockTeaser: function( i ) {
        
        if ( !$defined(i) ) i = -1;

        // depends on either existing selected or not
        var hasSelected = this.fxBlocks.selected > -1;

        hasSelected
            ? this.fxBlocks.els.addClass( "smaller" )
            : this.fxBlocks.els.removeClass( "smaller" );

        // remove Property bugs here with webkit
        //this.fxTeasersText.els.setProperty( "style", "" );
        this.fxTeasersText.els.removeProperty( "style" );

        // remove styles and hide text
        $each( this.fxTeasers.els, function( teaser, j ) {

            // selected teaser is always out of affecting
            if ( j === this.fxBlocks.selected ) return false;

            this.fxTeasersText.els[j].removeProperty( "style" );

            hasSelected 
                ? teaser.setStyle( "height", 50 )
                //: teaser.setProperty( "style", "" );
                : teaser.removeProperty( "style" );

            return i < 0
                ? teaser.show()
                : hasSelected
                    ? j !== i && i !== this.fxBlocks.selected ? teaser.hide() : teaser.show()
                    : teaser.show();
        
        }.bind( this ) );

        return true;
    },

    addPreviewCloserEvent: function() {
        
        $$( "." + this.options.blockPreviewCloserClass ).each( function( closer ) {
            
            closer.addEvent( "click", this.resetPreviews.bind( this, -1 ) );
            
        }.bind( this ) );
        
        return true;
    }
            
} );
