(function($){

    var demo_h, demo_w, block_id, block_active, layer_inc;
    
    var block = new Array();
    var liquid = new Object();
    var limit = new Object();
    
    var defaults = new Object();
    defaults.block = new Object();
    defaults.block.height = '20.0';
    defaults.block.density = '2.7';
    defaults.block.limit = new Object();
    defaults.block.limit.max_num = '10.0';
    defaults.block.limit.min_density = '0.0';
    defaults.block.limit.max_density = '10.0';
    defaults.block.limit.min_height = '5.0';
    defaults.block.limit.max_height = '50.0';
    defaults.liquid = new Object();
    defaults.liquid.density = '3.3';
    defaults.liquid.viscosity = 2000;
    defaults.height_inc = '0.5';
    defaults.density_inc = '0.1';
    
    var prefab = new Object();
    prefab.branding = '<h1>Bouyancy Demo</h1>';
    prefab.controls = '<form class="controls"><div class="liquid"><h2>Liquid</h2><fieldset class="density"><label>Density</label><span class="display"></span><button class="add">+</button><button class="subtract">-</button></fieldset></div></form>';
    prefab.waterline = '<div class="water-line"></div>';
    prefab.workbench = '<div class="workbench"><div class="columns"></div><button class="add"></button></div>';
    prefab.equation = '<div class="equation"><h2>Bouyancy Equation</h2><dl class="density"><dt title="Active Block Density"></dt><dd title="Liquid Density"></dd></dl><dl class="height"><dt title="Active Block Root"></dt><dd title="Active Block Height"></dd></dl></div>';
    prefab.block_height = '<div class="label block-height"><div class="lines"></div><h2>Block Height</h2><span>99.9</span></div>';
    prefab.block_root = '<div class="label block-root"></div>';
    
    
    $.fn.bouyancy = function(method) { 

        if ( methods[method] ) {
            return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
        }
        else if ( typeof method === 'object' || ! method ) {
            return methods.init.apply( this, arguments );
        }
        else {
            $.error( 'Method ' +  method + ' does not exist on jQuery.bouyancy' );
        }
        
    };

    var methods = {
    
        init: function (options) {
            
            // Add Stuff
            $(this).addClass('dd-bouyancy-demo');
            $(this).append(prefab.branding);
            $(this).append(prefab.equation);
            $(this).append(prefab.controls);
            $(this).append(prefab.waterline);
            $(this).append(prefab.workbench);
            //$(this).append(prefab.block_height);
            //$(this).append(prefab.block_root);

            liquid.density = defaults.liquid.density;
        
            block_id = 0;
            block_active = 0;
        
            layer_inc = 10;

            demo_h = $(this).height() / 10;
            demo_w = $(this).width() / 10;
            
            $('.dd-bouyancy-demo .water-line').css({'top': (demo_h / 2) + 'em', 'height': (demo_h / 2) + 'em'});
            $('.dd-bouyancy-demo .controls .liquid span.display').html('&rho; '+liquid.density);
            $('.dd-bouyancy-demo .workbench button.add').css({'top': (demo_h / 2.5) + 'em'});
            
            editBlock('add');
            moveBlock(block_active);
            
            $('.dd-bouyancy-demo .workbench')
                .draggable({ axis: 'x' });
                //.click(deactivateBlocks);
            
            $('.dd-bouyancy-demo .controls .block .ctrls button.reset')
                .click(
                    function() {
                        this.destroy();
                        return false;
                    }
                );
        
            $('.dd-bouyancy-demo .controls .liquid .density button')
                .click(
                    function() {
                        inc = defaults.density_inc;
                        inc = ($(this).hasClass('add')) ? inc : '-'+inc;
                        new_val = parseFloat(liquid.density, 10) + parseFloat(inc, 10);
                        if (new_val >= defaults.block.limit.min_density) liquid.density = parseFloat(liquid.density, 10) + parseFloat(inc, 10);
                        this_input = $(this).prevAll('span.display');
                        this_input.html('&rho; '+roundNumber(parseFloat(liquid.density, 10), 1));
                        $('.dd-bouyancy-demo .workbench .block')
                            .each(
                                function(i) {
                                    moveBlock($(this).attr('data-id'));
                                }
                            );
                        return false;
                    }
                );            
            
            $('.dd-bouyancy-demo .controls .zoom button')
                .click(
                    function() {
                        
                        var prop = $(this).attr('class');
                        
                        if (prop == 'in') {
                            $('.dd-bouyancy-demo .workbench').css('fontSize', '0.5em');
                            demo_h = demo_h * 2;
                            demo_w = demo_w * 2;
                        }
                        else {
                            $('.dd-bouyancy-demo .workbench').css('fontSize', '1.5em');
                        }
                        
                        adjustWorkbench();
                        
                        return false;
                        
                    }
                );
            
            $('.dd-bouyancy-demo .workbench .columns')
                .sortable(
                    {
                        containment: 'parent',
                        handle: '.block'
                    }
                );
            
            $('.dd-bouyancy-demo .workbench > button.add')
                .click(
                    function() {
                        editBlock('add');
                        moveBlock(block_active);
                        return false;
                    }
                );
            
            return this;
            
            },
            
            
        destroy : function( ) { return this.each(function(){ $(window).unbind('.bouyancy'); }) },
    
    };
        

    function blockObj(num) {
        this.height = defaults.block.height;
        this.density = defaults.block.density;
        //this.html = '<div class="column"><div class="find hide"><button class="reset">!</button></div><div class="block" data-id="'+num+'"><button class="remove">X</button><span class="display id"></span><fieldset class="density props"><span class="display"></span><button class="add">+</button><button class="subtract">-</button></fieldset><fieldset class="height props"><span class="display"></span><button class="add">+</button><button class="subtract">-</button></fieldset><span class="handle top"></span><span class="handle bottom"></span></div></div>';
        this.html = '<div class="column"><div class="find hide"><button class="reset">!</button></div><div class="block" data-id="'+num+'"><span class="handle-top"></span><span class="handle-bottom"></span><div class="inner"><button class="remove"></button><span class="display id"></span><fieldset class="density props"><span class="display"></span><button class="add">+</button><button class="subtract">-</button></fieldset><fieldset class="height props"><span class="display"></span><button class="add">+</button><button class="subtract">-</button></fieldset></div></div></div>';
        this.id = num;
    } // end blockObj()
    
                
    function editBlock(op, block_num) {
        
        if (block_num == 'UNDEFINED') { block_num = block_active; }
        
        if (op != 'UNDEFINED') {
            
            wb_h = demo_h;
        
            switch (op) {
            
                case 'add':
                
                    var new_block_num = $('.dd-bouyancy-demo .workbench .block').length + 1;
                    
                    if (new_block_num <= defaults.block.limit.max_num) {
                        block[++block_id] = new blockObj(block_id);
                        $('.dd-bouyancy-demo .columns').append(block[block_id].html);
                        $('.dd-bouyancy-demo .block[data-id="'+block_id+'"] span.display.id').html(block_id);
                        $('.dd-bouyancy-demo .block[data-id="'+block_id+'"] .height .display').html(block[block_id].height);
                        $('.dd-bouyancy-demo .block[data-id="'+block_id+'"] .density .display').html('&rho; '+block[block_id].density);
                        initBlock(block_id);
                    }
                    break;
                
                case 'remove':
                
                    if (!$('.dd-bouyancy-demo .block[data-id="'+block_num+'"]').length) {
                        // No block selected
                        alert("Can't remove block since none are selected.");
                        break;
                    }
                    else if ($('.dd-bouyancy-demo .workbench .block').length == 1) {
                        // There has to be at least one block
                        alert("There is only one column left. Wouldn't be much of a demo without any columns, now would it?");
                        break;
                    }
                    
                    var this_column = $('.dd-bouyancy-demo .block[data-id="'+block_num+'"]').closest('.column');
                    
                    if (this_column.prev('.column').length) {
                        var next_block = this_column.prev('.column').find('.block').attr('data-id');
                    }
                    else if (this_column.next('.column').length) {
                        var next_block = this_column.next('.column').find('.block').attr('data-id');
                    }
                    else {
                        var next_block = false;
                    }
                    
                    if (next_block) {
                        activateBlock(next_block);
                        $('.dd-bouyancy-demo .block[data-id="'+block_num+'"]').closest('.column').remove();
                        adjustWorkbench(block_num);
                    }
                    
                    break;
                    
                default:
                    break;
            
            }
            
        }
    
    } // end editBlock()


    function initBlock(block_num) {
        
		if (block_num == null) block_num = block_active;
		
        $('.dd-bouyancy-demo .workbench .block[data-id="'+block_num+'"]')
            .unbind()
            .click(
                function(e) {
                    // Highlight
                    deactivateBlocks();
                    activateBlock($(this).attr('data-id'));
                    adjustWorkbench();
                    showValues(block_active);
                }
            )
            .hover(
                function() {
                    $(this).addClass('hover');
                    /*
                    $(this).addClass('hover');
                    //nudge = parseFloat($(this).css('margin-top')) / 10.0;
                    nudge = parseFloat($(this).css('top')) / 10.0;
                    nudge -= ((demo_h/10.0) * 0.1);
                    //$(this).stop().css('margin-top', nudge+'em');
                    $(this).stop().css('top', nudge+'em');
                    */
                },
                function() {
                    $(this).removeClass('hover');
                    /*
                    $(this).removeClass('hover');
                    moveBlock($(this).attr('data-id'));
                    */
                }
            )
            .resizable(
                {
                    handles: 'n,s',
                    minHeight: defaults.block.limit.min_height * 10,
                    maxHeight: defaults.block.limit.max_height * 10,
                    grid: 5,
                    resize: function(e,ui) {
                    
                        var new_val = parseFloat((ui.size.height/10), 10);
                        block[$(this).attr('data-id')].height = new_val;
                        
                        this_input = $(this).find('.height span.display');
                        this_input.html(roundNumber(parseFloat(block[$(this).attr('data-id')].height, 10), 1));
                    },
                    stop: function(e,ui) {
                        
                        moveBlock($(this).attr('data-id'));
                    }
                }
            );
        
        $('.dd-bouyancy-demo .workbench .block[data-id="'+block_num+'"] button.remove')
            .unbind()
            .click(
                function() {
                    block_num = $(this).closest('.block').attr('data-id');
                    deactivateBlocks();
                    activateBlock(block_num);
                    editBlock('remove', block_num);
                    moveBlock(block_active);
                    stopPropagation();
                }
            );
        
        $('.dd-bouyancy-demo .workbench .block[data-id="'+block_num+'"] .props button')
            .unbind()
            .click(
                function() {
                
                    block_num = $(this).closest('.block').attr('data-id');
                    var prop = ($(this).closest('fieldset').hasClass('density')) ? 'density' : 'height';
                    
                    // Determine Limits
                    limit.lower = (prop == 'density') ? defaults.block.limit.min_density : defaults.block.limit.min_height; 
                    limit.upper = (prop == 'density') ? defaults.block.limit.max_density : defaults.block.limit.max_height;
                
                    // Determine Increment
                    var inc = (prop == 'density') ? defaults.density_inc : defaults.height_inc;
                    inc = ($(this).hasClass('add')) ? inc : '-'+inc;
                    
                    // Set New Value
                    var new_val = parseFloat(block[block_num][prop], 10) + parseFloat(inc, 10);
                    if (new_val >= limit.lower && new_val <= limit.upper) block[block_num][prop] = new_val;
                    
                    // Display New Value
                    this_input = $(this).prevAll('span.display');
                    this_input.html(roundNumber(parseFloat(block[block_num][prop], 10), 1));
                    if (prop == 'density') this_input.prepend('&rho; ');
                    
                    // Update Block Position
                    moveBlock(block_num);
                    
                    return false;
                }
            );
        
        $('.dd-bouyancy-demo .workbench .column .find button.reset')
            .unbind()
            .click(
                function() {
                    $(this).closest('.find').addClass('hide');
                    block_num = $(this).closest('.column').find('.block').attr('data-id');
                    block[block_num]['density'] = liquid.density;
                    $('.dd-bouyancy-demo .block[data-id="'+block_num+'"] .density .display').html('&rho; '+roundNumber(parseFloat(block[block_num]['density'], 10), 1));
                    moveBlock(block_num);
                    
                }
            );
        
        $('.dd-bouyancy-demo .block[data-id="'+block_num+'"]').click();
        
    } // end initBlock()
    
    
    function updateEquation(id) {
    
        if (id == null) { id = block_active; }
        
        $('.dd-bouyancy-demo .equation dl.density dt').html('&rho; '+roundNumber(parseFloat(block[id].density, 10), 1));
        $('.dd-bouyancy-demo .equation dl.density dd').html('&rho; '+roundNumber(parseFloat(liquid.density, 10), 1));
        
        $('.dd-bouyancy-demo .equation dl.height dt').html(roundNumber(parseFloat(block[id].root, 10), 1));
        $('.dd-bouyancy-demo .equation dl.height dd').html(roundNumber(parseFloat(block[id].height, 10), 1));
    
    } // end updateEquation()
    
    
    function updateLabels() {
    
        
    
    } // end updateLabels()


    function moveBlock(id) {
    
        if (id != 'UNDEFINED' && id != 0) {
        
            wb_h = demo_h;
            
            var bh = $('.dd-bouyancy-demo .block[data-id="'+id+'"]').height() / 10;
            var bd = roundNumber(block[id].density, 1);
            var ld = roundNumber(liquid.density, 1);
            var br = roundNumber((bd/ld) * bh, 0);
            
            block[id].root = br;
            
            var wb_mp = wb_h / 2;
            var bt = bh - br;
            
            var block_top = (bd <= ld) ? wb_mp - bt : demo_h + 5;
            
            $('.dd-bouyancy-demo .block[data-id="'+id+'"]')
                .stop()
                .animate(
                    {
                        'height': block[id].height + 'em',
                        'top': block_top + 'em'
                    },
                    defaults.liquid.viscosity,
                    "easeOutElastic"
                );
            
            $('.dd-bouyancy-demo .label.block-root').css('height', block[id].root+'em');
            
            if (block_top > demo_h) {
                $('.dd-bouyancy-demo .block[data-id="'+id+'"]').closest('.column').find('.find').removeClass('hide');
            }
            else {
                $('.dd-bouyancy-demo .block[data-id="'+id+'"]').closest('.column').find('.find').addClass('hide');
            }
            
            updateEquation();
        
        }
        
    } // end moveBlock()
    
    
    function deactivateBlocks() {
        $('.dd-bouyancy-demo .block').removeClass('active');
    } // end deactivateBlocks()


    function activateBlock(id) {
    
        if (id != 'UNDEFINED') {
        
            $('.dd-bouyancy-demo .workbench .block[data-id="'+id+'"]')
                .addClass('active')
                .prepend($('.dd-bouyancy-demo .label.block-height').detach())
                .prepend($('.dd-bouyancy-demo .label.block-root').detach());
            
            $('.dd-bouyancy-demo .label.block-root').css('height', block[id].root+'em');
            
            block_active = id;
            
            updateEquation(id)
        
        }
    
    } // end activateBlock()


    function adjustWorkbench(block_num) {
        
        if (block_num == null) { block_num = block_active; }
        
        // Set Width of Column Wrapper
        wb_w = $('.dd-bouyancy-demo .workbench .columns .column').length * $('.dd-bouyancy-demo .workbench .columns .column:first').outerWidth(true) / 10;
        $('.dd-bouyancy-demo .workbench .columns').css('width', wb_w + 'em');
        
        // Set Width of Workbench
        wb_w += ($('.dd-bouyancy-demo .workbench button.add').outerWidth(true) / 10) + 1;
        $('.dd-bouyancy-demo .workbench').css('width', wb_w + 'em');
        
        // Set Horizontal Position
        wb_vc = parseInt(demo_w / 2);
        block_width = $('.dd-bouyancy-demo .workbench .column:first').outerWidth(true) / 10;
        position_wb = $('.dd-bouyancy-demo .workbench .column').has('.block[data-id="'+block_num+'"]').position();
        new_pos = wb_vc - ((position_wb.left / 10) + (block_width/2));
        $('.dd-bouyancy-demo .workbench').stop(false, false).animate({'left': new_pos + 'em'}, 500, 'easeInOutSine');
        
    } // end adjustWorkbench()


    function showValues(id) {
        $('.dd-bouyancy-demo .controls .block h2 span.display').html(id);
        $('.dd-bouyancy-demo .controls .block .density span.display').html(roundNumber(block[id].density, 1));
        $('.dd-bouyancy-demo .controls .block .height span.display').html(roundNumber(block[id].height, 1));
    } // end showValues()


    function roundNumber(num, dec) {
        var result = Math.round(num*Math.pow(10,dec))/Math.pow(10,dec);
        return result;
    } // end roundNumber()
    
})(jQuery);

