/*
    Common Grid 2.0.4
    
    Copyright (c) 2010 - 2011 STRAIGHTLINE<http://www.straightline.jp/> All rights reserved.
*/

/* 
---------------------------------------------------------------------------------------------------
    Adjust Grid 2.0.4
---------------------------------------------------------------------------------------------------
*/
var AdjustGrid = new Class({
	Implements: [Options,Events],
    resizeTimer: null,
    isFirst: true,
    isLoadFirst: false,
    isAdjusting: false,
    animationType: {
        fade: 0,
        move: 1,
        fadeContainer: 2
    },
    options: {
        containerId: null,
        containerMinWidth: 0,
        containerMaxWidth: 'auto',
        gridItemDelay: 50,
        onComplete: function(){},             // after first
        onLoadComplete: function(){},         // after window.load
        onAnimationComplete: function(){},    // after animation
        loadAnimation: true,
        loadAnimationType: 0,
        resizeAnimation: true,
        resizeAnimationType: 1,
        fadeDuration: 500,
        fadeTransition: 'sine:in:out',
        moveDuration: 500,
        moveTransition: 'expo:in:out',
        isQueueJumping: false,
        rightToLeft: false
    },
    
    initialize: function(options) {
        this.setOptions(options);
    },
    
    run: function() {
        this.isFirst = true;
        
        if (document.readyState == 'complete') {
                this.isLoadFirst = true;
        } else {
            window.addEvent('load', function() {
                this.isLoadFirst = true;
                this.adjust.apply(this, [
                    this.options.loadAnimation, 
                    this.options.loadAnimationType
                ]);
            }.bind(this));
        }
        
        if ($(this.options.containerId) == null) {
            $$('.grid').each(function(grid) {
                grid.setStyle('opacity', 0);
            });
        }
        
        window.addEvent('resize', function() {
            clearTimeout(this.resizeTimer);
            this.resizeTimer = (function() {
                if (this.isAdjusting == false) {
                    this.adjust.apply(this, [
                        this.options.resizeAnimation,
                        this.options.resizeAnimationType
                    ]);
                }
            }.bind(this)).delay(200);
        }.bind(this));
        
        this._adjust.apply(this, [this.options.loadAnimation, this.options.loadAnimationType]);
    },
    
    adjust: function(isAnimation, animationType) {
        var timer = (function() {
            if (this.isFirst == false) {
                clearTimeout(timer);
                this._adjust.apply(this, [isAnimation, animationType]);
            }
        }.bind(this)).periodical(50);
    },
    
    _adjust: function(isAnimation, animationType) {
        this.isAdjusting = true;
        
        var container = $(this.options.containerId);
        if (container) {
            var containerMinWidth = this.options.containerMinWidth;
            container.setStyle('position', 'relative');
            var windowWidth = window.getWidth();
            var curContainerWidth = container.getSize().x;
            
            if (container.retrieve('curWindowWidth') != windowWidth) {
                container.store('curWindowWidth', windowWidth);
                if (windowWidth > this.options.containerMaxWidth) {
                    container.setStyle('width', this.options.containerMaxWidth);
                } else if (windowWidth < this.options.containerMinWidth) {
                    container.setStyle('width', this.options.containerMinWidth);
                } else {
                    container.setStyle('width', 'auto');
                }
            }
        }

        var grids = $$('.grid');
        if (grids.length == 0) {
            this.fireEvent('animationComplete');
            this.isFirst = false;
            
            if (this.isLoadFirst) {
                this.fireEvent('loadComplete');
                this.isLoadFirst = false;
            }
            return;
        }
        var isLoopBack = false;
        for (var gridIndex = 0; gridIndex < grids.length; gridIndex++) {
            var grid = grids[gridIndex];
            
            if (grid.retrieve('fixed')) {
                continue;
            }
            var isContinue = false;
            var childGrids = grid.getElements('.grid');
            childGrids.each(function(childGrid) {
                if (childGrid.retrieve('fixed') == null) {
                    isContinue = true;
                }
            });
            if (isContinue) {
                continue;
            }
            var parentGrid = grid.getParent('.grid');
            if (parentGrid && parentGrid.retrieve('fixed') == null) {
                isLoopBack = true;
            }
            grid.setStyle('position', 'relative');
            
            var gridItems = grid.getElements('.grid-item');
            var gridWidth = grid.getSize().x;
            var sheet = new Array();
            var row = 0;
            var col = 0;
            var curUpperCol = 0;
            var gridMaxHeight = 0;
            var rightToLeftOffsetLeft = gridWidth;
            for (var gridItemIndex = 0; gridItemIndex < gridItems.length; gridItemIndex++) {
                //console.log("Num: " + gridItemIndex + ", Row: " + row + ", Col:" + col);
                var gridItem = gridItems[gridItemIndex];
                if (grid != gridItem.getParent('.grid')) {
                    continue;
                }
                
                var gridItemWidth = gridItem.getComputedSize().totalWidth;
                gridItem.removeClass('grid-item-first');
                gridItem.removeClass('grid-item-last');
                gridItem.removeClass('col-first');
                gridItem.removeClass('col-last');
                gridItem.removeClass('row-last');
                gridItem.eliminate('fixed', false);
                gridItem.setStyle('position', 'absolute');
                if (this.options.rightToLeft) {
                    gridItem.store('positionRight', col > 0 ? sheet[row][col - 1].retrieve('positionLeft') : gridWidth);
                    gridItem.store('positionLeft', col > 0 ? gridItem.retrieve('positionRight') - gridItemWidth : gridWidth - gridItemWidth);
                } else {
                    gridItem.store('positionLeft', col > 0 ? sheet[row][col - 1].retrieve('positionRight') : 0);
                    gridItem.store('positionRight', col > 0 ? gridItem.retrieve('positionLeft') + gridItemWidth : gridItemWidth);
                }
                
                if (gridItemIndex + 1 == gridItems.length) {
                    gridItem.addClass('grid-item-last');
                    gridItem.addClass('col-last');
                }
                if (row == 0 && col == 0) {
                    gridItem.addClass('grid-item-first');
                    gridItem.addClass('col-first');
                } else if (col == 0) {
                    gridItem.addClass('col-first');
                } else if (
                    (this.options.rightToLeft && gridItem.retrieve('positionLeft') < 0) ||
                    (this.options.rightToLeft == false && gridItem.retrieve('positionRight') > gridWidth)
                ) {
                    sheet[row][col - 1].addClass('col-last');
                    col = 0;
                    row++;
                    curUpperCol = 0;
                    gridItemIndex--;
                    continue;
                }

                if (this.options.rightToLeft) {
                    rightToLeftOffsetLeft = Math.min(gridItem.retrieve('positionLeft'), rightToLeftOffsetLeft);
                }
                                
                var gridItemHeight = gridItem.getComputedSize().totalHeight;
                if (row == 0) {
                    if (col == 0) {
                        gridItem.store('positionTop', 0);
                        gridItem.store('positionBottom', gridItemHeight);
                    } else {
                        gridItem.store('positionTop', sheet[row][col - 1].retrieve('positionTop'));
                        gridItem.store('positionBottom', gridItem.retrieve('positionTop') + gridItemHeight);
                    }
                } else {
                    var left = gridItem.retrieve('positionLeft');
                    var right = gridItem.retrieve('positionRight');
                    var height = gridItemHeight;
                    
                    var upperGridItem = null;
                    var isSkip = false;
                    for (var upperCol = curUpperCol; upperCol < sheet[row - 1].length; upperCol++) {
                        var curUpperGridItem = sheet[row - 1][upperCol];
                        var upperLeft = curUpperGridItem.retrieve('positionLeft');
                        var upperRight = curUpperGridItem.retrieve('positionRight');
                        
                        if (this.options.isQueueJumping && !upperGridItem) {
                            var curUpperGridItemBottom = curUpperGridItem.retrieve('positionBottom');
                            var heightRange = 0;
                            if (upperCol + 1 != sheet[row - 1].length) {
                                heightRange = curUpperGridItemBottom - sheet[row - 1][upperCol + 1].retrieve('positionBottom');
                            } else if (sheet[row - 1].length > 1) {
                                heightRange = curUpperGridItemBottom - sheet[row - 1][upperCol - 1].retrieve('positionBottom');
                            }
                            
                            if (
                                heightRange > 0 && 
                                height / 2 <= heightRange
                            ) {
                                var isException = false;
                                if (
                                    col > 0 &&
                                    curUpperGridItemBottom + height <= sheet[row][col - 1].retrieve('positionBottom') + sheet[row][col - 1].getComputedSize().totalHeight / 2
                                ) {
                                    isException = true;
                                }
                                if (isException == false) {
                                    gridItem = curUpperGridItem;
                                    gridItemIndex--;
                                    isSkip = true;
                                    curUpperCol = upperCol + 1;
                                    break;
                                }
                            }
                        }
                        
                        // 完全一致
                        if (upperLeft == left && right == upperRight) {
                            upperGridItem = curUpperGridItem;
                            curUpperCol = upperCol + 1;
                            break;
                        } else if (
                            // 完全内包
                            (upperLeft <= left && right <= upperRight) ||
                            (upperLeft >= left && right >= upperRight) ||
                            // 部分内包
                            (upperLeft < left && left < upperRight) ||
                            (upperLeft < right && right < upperRight)
                        ) {
                            if (
                                !upperGridItem ||
                                curUpperGridItem.retrieve('positionBottom') > upperGridItem.retrieve('positionBottom')
                            ) {
                                upperGridItem = curUpperGridItem;
                                if (right >= upperRight) {
                                    curUpperCol = upperCol + 1;
                                }
                            }
                        }
                    }

                    if (isSkip == false) {
                        gridItem.store('positionTop', upperGridItem ? upperGridItem.retrieve('positionBottom') : sheet[row][col - 1].retrieve('positionTop'));
                        gridItem.store('positionBottom', upperGridItem ? upperGridItem.retrieve('positionBottom') + height : sheet[row][col - 1].retrieve('positionTop') + height);
                    }
                }
                
                gridMaxHeight = Math.max(gridItem.retrieve('positionBottom'), gridMaxHeight);
                if (container) {
                    if (this.options.rightToLeft) {
                        containerMinWidth = Math.max(gridWidth - gridItem.retrieve('positionLeft'), containerMinWidth);
                    } else {
                        containerMinWidth = Math.max(gridItem.retrieve('positionRight'), containerMinWidth);
                    }
                }
                if (!sheet[row]) {
                    sheet[row] = new Array();
                }
                if (!sheet[row][col]) {
                    sheet[row][col] = new Array();
                }
                sheet[row][col] = gridItem;
                col++;
                
                gridItem.store('fixed', true);
            }
            
            if (sheet[row]) {
                var lastRowPositionRight = 0;
                sheet[row].each(function(lastRowGridItem, lastIndex) {
                    lastRowGridItem.addClass('row-last');
                    if (sheet[row].length == lastIndex + 1) {
                        lastRowPositionRight = lastRowGridItem.retrieve('positionRight');
                    }
                });
                if (row > 0) {
                    sheet[row - 1].each(function(lastRowGridItem, lastIndex) {
                        if (lastRowGridItem.retrieve('positionLeft') >= lastRowPositionRight) {
                            lastRowGridItem.addClass('row-last');
                        }
                    });
                }
            }
            
            if (this.isFirst) {
                grid.setStyle('height', gridMaxHeight);
            } else {
                grid.set('tween', {
                    property: 'height',
                    duration: 'normal',
                    transition: 'expo:out',
                    link: 'cancel'
                }).get('tween').start(gridMaxHeight);
            }
            grid.store('fixed', true);
            if (isLoopBack) {
                gridIndex = -1;
            }

            if (this.options.rightToLeft && rightToLeftOffsetLeft > 0) {
                for (var gridItemIndex = 0; gridItemIndex < gridItems.length; gridItemIndex++) {
                    var gridItem = gridItems[gridItemIndex];
                    if (grid != gridItem.getParent('.grid')) {
                        continue;
                    }
                    gridItem.store('positionLeft', gridItem.retrieve('positionLeft') - rightToLeftOffsetLeft);
                    gridItem.store('positionRight', gridItem.retrieve('positionRight') - rightToLeftOffsetLeft);
                }
            }
        }
        
        grids.each(function(grid) {
            grid.eliminate('fixed');
        });
        if (container) {
            container.setStyle('width', curContainerWidth);
        }
        
        var index = 0;
        var gridItems = $$('.grid-item');
        var chain = new Chain();
        var duration;
        var transition;
        chain.chain(
            function() {
                if (container == null) {
                    $$('.grid').each(function(grid) {
                        grid.setStyle('opacity', 1);
                    });
                }
                if (container) {
                    new Fx.Tween(container, {
                        property: 'width',
                        duration: 'normal',
                        transition: 'expo:out',
                        link: 'cancel'
                    }).start(Math.min(containerMinWidth, (this.options.containerMaxWidth == 'auto' ? containerMinWidth : this.options.containerMaxWidth)));
                    if (isAnimation && animationType != this.animationType.fadeContainer) {
                        container.setStyle('opacity', 1);
                    }
                }
            }.bind(this)
        );
        
        if (isAnimation) {
            if (
                animationType == null || 
                animationType == this.animationType.fade ||
                animationType == this.animationType.fadeContainer
            ) {
                duration = this.options.fadeDuration;
                transition = this.options.fadeTransition;
            } else if (animationType == this.animationType.move) {
                duration = this.options.moveDuration;
                transition = this.options.moveTransition;
            }
        }

        gridItems.each(function(gridItem, index) {
            if (isAnimation && animationType != this.animationType.fadeContainer) {
                if (
                    this.isFirst ||
                    gridItem.getStyle('top').toInt() != gridItem.retrieve('positionTop') ||
                    gridItem.getStyle('left').toInt() != gridItem.retrieve('positionLeft')
                ) {
                    var properties;
                    if (
                        animationType == null || 
                        animationType == this.animationType.fade
                    ) {
                        gridItem.setStyles({
                            top: gridItem.retrieve('positionTop'),
                            left: gridItem.retrieve('positionLeft'),
                            opacity: 0
                        });
                        properties = {
                            opacity: 1
                        };
                    } else if (animationType == this.animationType.move) {
                        properties = {
                            top: gridItem.retrieve('positionTop'),
                            left: gridItem.retrieve('positionLeft')
                        };
                    }
                    if (index + 1 == gridItems.length) {
                        chain.chain(
                            function() {
                                if (gridItem.retrieve('morphSetting') == null) {
                                    gridItem.set('morph', {
                                        duration: duration,
                                        transition: transition,
                                        link: 'chain',
                                        onComplete: function() {
                                            this.fireEvent('animationComplete');
                                            this.isFirst = false;
                                            if (this.isLoadFirst) {
                                                this.fireEvent('loadComplete');
                                                this.isLoadFirst = false;
                                            }
                                        }.bind(this)
                                    }).get('morph').start(properties);
                                    gridItem.store('morphSetting', true)
                                } else {
                                    gridItem.set('morph', {
                                        transition: transition
                                    }).get('morph').start(properties);
                                }
                            }.bind(this)
                        );
                    } else {
                        chain.chain(
                            function() { 
                                if (gridItem.retrieve('morphSetting') == null) {
                                    gridItem.set('morph', {
                                        duration: duration,
                                        transition: transition,
                                        link: 'chain'
                                    }).get('morph').start(properties);
                                    gridItem.store('morphSetting', true)
                                } else {
                                    gridItem.set('morph', {
                                        transition: transition
                                    }).get('morph').start(properties);
                                }
                            }.bind(this)
                        );
                    }
                }
            } else {
                gridItem.setStyles({
                    top: gridItem.retrieve('positionTop'),
                    left: gridItem.retrieve('positionLeft')
                });
            }
            
        }.bind(this));
        
        if (isAnimation && animationType == this.animationType.fadeContainer) {
            chain.chain(
                function() {
                    if (container) {
                        new Fx.Tween(container, {
                            property: 'opacity',
                            duration: duration,
                            transition: transition,
                            link: 'chain',
                            onComplete: function() {
                                this.fireEvent('animationComplete');
                                this.isFirst = false;
                                if (this.isLoadFirst) {
                                    this.fireEvent('loadComplete');
                                    this.isLoadFirst = false;
                                }
                            }.bind(this)
                        }).start(1);
                    }
                }.bind(this)
            );
        }

        if (this.isFirst) {
            this.fireEvent('complete');
        }

        var runChain = function() {
    		if (chain.callChain() == false) {
                runChain = clearTimeout(timer);

                this.isAdjusting = false;
                
                if (isAnimation == false) {
                    if (container) {
                        container.setStyle('opacity', 1);
                    }
                    this.fireEvent('animationComplete');
                    this.isFirst = false;
                    
                    if (this.isLoadFirst) {
                        this.fireEvent('loadComplete');
                        this.isLoadFirst = false;
                    }
                }
                
            } 
    	}.bind(this);
    	var timer = runChain.periodical(this.options.gridItemDelay);
    }
    
});

