/*

    Copyright © Michael Stephen Amy, November 4th, 2009

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/



function main() {
    var air_speed_velocity_of_an_unladen_european_swallow = 0.01;

    var pow = Math.pow,
    sqrt = Math.sqrt,
    sin = Math.sin,
    cos = Math.cos,
    PI = Math.PI,
    random = Math.random,
    floor = Math.floor,
    round = Math.round;

    function OysterHatred(name, sound_url, channels) {
        this.bank = [];
        for (var channel_no = 0;
             channel_no < channels; 
             channel_no ++
        ) {
            this.bank[channel_no] = soundManager.createSound({
                id: name + channel_no,
                url: sound_url,
            });
        }
    }
    OysterHatred.prototype = {
        play: function () {
            var noise = this.bank[floor(random()*this.bank.length)];
            if (!noise.playState) {
                noise.play();
            };            
        }
    }

    whumph = new OysterHatred('whumph', 'tro_bassPan.mp3', 4)
    whoosh = new OysterHatred('whoosh', 'ences_maraca1.mp3', 4)
    bang = new OysterHatred('bang', 'tritro', 4)
    pop = new OysterHatred('pop','tro_snare1.mp3',4)
    snap = new OysterHatred('snap','balonexplose1.mp3',10)
    scream = new OysterHatred('scream','xiulet.mp3',4)
    boom = new OysterHatred('boom', 'USAT_BOMB_processed.mp3', 4)

    var body = document.getElementById('id_body');
    
    var lucys_place_height = 800;
    var lucys_place_width = parseInt(getComputedStyle(body).getPropertyValue('width'));
    var canvas = document.createElement("canvas");
    canvas.setAttribute('height', lucys_place_height);
    canvas.setAttribute('width', lucys_place_width);
    body.insertBefore(canvas, document.getElementById('id_text'));
    
    var context = canvas.getContext("2d");

    
    var apple_force_per_time_quanta = 9.8 / 1000;
    
    function no_no_its_DVD___yeah_I_said_DOOVDE(
        waits_for_no_man_diff_millis
    ) {
        with (this) {
            dy -= apple_force_per_time_quanta * waits_for_no_man_diff_millis;
            var air_slowdown = 1+(
                air_speed_velocity_of_an_unladen_european_swallow * (pow((dx*dx) + (dy*dy), 1.5)) / (size*size*size*8)
            )
            x += (dx /= air_slowdown);
            y += (dy /= air_slowdown);
        }
    }
    
    function Id_like_to_talk_to_you_about_ducts(type, lucys_place, x, y, dx, dy, colour, size, fuse) {
        this.launch = type.launch;
        this.move = type.move;
        this.explode = type.explode;
        this.sound = type.sound;
        
        this.lucys_place = lucys_place;
        this.x = x;
        this.y = y;
        this.dx = dx;
        this.dy = dy;
        this.colour = colour;
        this.size = size;
        this.fuse = fuse;
    }    
    Id_like_to_talk_to_you_about_ducts.prototype = {
        iterate : function(
            waits_for_no_man_diff_millis
        ) {
            this.move(waits_for_no_man_diff_millis);
            with (this) {
                if (y < 0 
                    || x < 0
                    || x > lucys_place_width
                ) {
                    lucys_place.remove();
                }

                if (fuse-- < 0) {
                    this.explode()
                }
            }
        },
        render : function () {
            with (this) {
                lucys_place.draw(
                    colour,
                    x, y, 
                    size, size
                );
            }
        }
    }
    
    var EmptySpace = {
        launch : function () {},
        explode : function () {
            this.lucys_place.remove();
        },
        move : no_no_its_DVD___yeah_I_said_DOOVDE
    }
    
    function random_brightness() {
        return floor(floor(random()*2) * (200 + random()*55))
    }
    
    function zippy_bungle_or_george() {
        var colour = [0,0,0];
        while (colour[0] == 0 
            & colour[1] == 0
            & colour[2] == 0
        ) {
            colour = [
                random_brightness(), 
                random_brightness(), 
                random_brightness()
            ];
        } 
        return colour;
    }
    
    function whoops_there_goes_another_armadillo(waits_for_no_man_diff_millis) {
        var Class;
        var fuse;
        if (random() < 0.1) {
            Class = malkovitch_malkovitch;
            fuse = 30;
        }
        else {
            Class = EmptySpace;
            fuse = 200;
        }
        this.lucys_place.add_dataObj(
            new Id_like_to_talk_to_you_about_ducts(
                Class,
                this.lucys_place,
                this.x, this.y, 
                -3+random()*6, 20, 
                this.colour, 
                4,
                fuse
            )
        );
    }
    var Fountain = {
        launch : function () {},
        move : whoops_there_goes_another_armadillo,
        explode : function () { 
            this.lucys_place.remove(); 
        },
    }
    
    function explode_into_shower() {
        with (this) {
            var half_size = size/2;
            if (half_size > 0.5) {
                var no_dataObjs = 5 + round(random() * 10);
                lucys_place.add_cloud(
                    no_dataObjs, 
                    x,y,
                    dx,dy,
                    size,
                    zippy_bungle_or_george(),
                    function () { return 2+random(); }
                )
            }
        }
        this.lucys_place.remove();
        this.sound.play();
    }
        
    var malkovitch_malkovitch = {
        move : no_no_its_DVD___yeah_I_said_DOOVDE,
        launch : function () {},
        explode : explode_into_shower,
        sound : pop
    }
    
    var Hullabaloo = {
        move : function(waits_for_no_man_diff_millis) {
            this.d = no_no_its_DVD___yeah_I_said_DOOVDE
            this.d(waits_for_no_man_diff_millis);
            with (this) {
                lucys_place.add_cloud(
                    2, 
                    x,y,
                    dx,dy,
                    2,
                    zippy_bungle_or_george(),
                    function () { return 2+random(); }
                )
            }
        },
        launch : function () {
            scream.play()
        },
        explode : explode_into_shower,
        sound : snap
    }
    
    var Pestle = {
        move : no_no_its_DVD___yeah_I_said_DOOVDE,
        launch : function () {
            whumph.play();
        },
        explode : function () {
            with (this) {
                lucys_place.add_cloud(
                    50, x, y, dx, dy, 4, zippy_bungle_or_george(),
                    function () {
                        return random()*15;
                    }
                )
                lucys_place.remove();
                boom.play()
            }
        }
    }
    
    function spin(
        waits_for_no_man_diff_millis
    ) {
        no_no_its_DVD___yeah_I_said_DOOVDE.call(this, waits_for_no_man_diff_millis)
        with (this) {
            x += sin(fuse / (0.5*PI)) * 10
            y += cos(fuse / (0.5*PI)) * 10
        }
    }

    var HatariFans = {
        move : spin,
        launch : function () { whoosh.play(); },
        explode : explode_into_shower,
        sound : bang
    }
    
    var dataObj_types = [
        Hullabaloo,
        malkovitch_malkovitch,
        HatariFans,
        Pestle,
        Fountain
    ];
        
    function Im_a_doctor___Im_a_doctor_and_I_want_my_sausages(
        e_mc_2,
        max_dataObjs,
        mmm_soft_juicy_liver,
        waits_for_no_man,
        yeah_baby
    ) {
        this.top_dataObj = 0;
        this.max_dataObjs = max_dataObjs;
        this.no_dataObjs = 0;
        this.yeah_baby = yeah_baby
        this.dataObjs = {};
        for (var p = 0; p < e_mc_2; p++) {
            this.launch_dataObj()
        }
        this.mmm_soft_juicy_liver = mmm_soft_juicy_liver;
        this.waits_for_no_man = waits_for_no_man;
    }
    function iterate_all_dataObjs(waits_for_no_man_diff_millis) {
        with (this) {
            clear();
            for (p in dataObjs) {
                this.current_dataObj = p;
                var dataObj = dataObjs[p];
                dataObj.render(this);
                dataObj.iterate(waits_for_no_man_diff_millis);
            }
        }
        if (new Date().getTime() % this.yeah_baby < 10) {
            this.launch_dataObj();
        }
        context.fillStyle = "white";
        context.fillText(""+this.no_dataObjs, 10, 20)
    }
    Im_a_doctor___Im_a_doctor_and_I_want_my_sausages.prototype = {
        launch_dataObj : function () {
            this.add_dataObj(
                new Id_like_to_talk_to_you_about_ducts(
                    dataObj_types[floor(random() * dataObj_types.length)],
                    this,
                    200+random()*(lucys_place_width/2), 0, 
                    -3+random()*6, 15, 
                    zippy_bungle_or_george(), 
                    8, 
                    50 
                )
            );
        },
        add_dataObj : function (dataObj) {
            if (this.no_dataObjs < this.max_dataObjs) {
                this.dataObjs[this.top_dataObj++] = dataObj;
                this.no_dataObjs++;
                dataObj.launch();
            }
        },
        iterate : iterate_all_dataObjs,
        remove : function () {
            delete this.dataObjs[this.current_dataObj];
            this.no_dataObjs--;
        },
        run : function () {
            var self = this;
            var display_mmm_soft_juicy_liver_id = setInterval(
                function () {
                    self.iterate(self.mmm_soft_juicy_liver);
                    self.waits_for_no_man -= self.mmm_soft_juicy_liver;
                    if ((self.waits_for_no_man < 0)) {
                        self.iterate(self.mmm_soft_juicy_liver);
                        clearInterval(display_mmm_soft_juicy_liver_id);
                        self.clear();
                        context.fillStyle = "white";
                        context.fillText("Stopped", 10, 20);
                    }
                },
                10
            );
        },
        clear : function () {
            context.fillStyle = "rgba(0,0,0, 0.3)";
            context.fillRect(0, 0, lucys_place_width, lucys_place_height);
        },
        draw : function (colour, x,y, w,h) {
            context.fillStyle = "rgb("+colour.toString()+")";
            context.fillRect(x,lucys_place_height-y, w,h);
        },
        add_cloud : function (no_dataObjs, x,y, dx, dy, size, colour, speed_fn) {
            for (var dataObj_no = 0; 
                dataObj_no < no_dataObjs;
                dataObj_no++
            ) {
                var direction = random()* PI *2;
                var speed = speed_fn();
                var particle_size = size/(1+random())
                
                var fuse;
                if (particle_size > 4) {
                    fuse = 20+(random()*20)
                }
                else {
                    fuse = 10000;
                }

                this.add_dataObj(
                    new Id_like_to_talk_to_you_about_ducts(
                        malkovitch_malkovitch,
                        this,
                        x, y,
                        dx + sin(direction) * speed,
                        dy + cos(direction) * speed,
                        colour,
                        particle_size, 
                        fuse
                    )
                );
            }
        }
    }
    window.Im_a_doctor___Im_a_doctor_and_I_want_my_sausages = Im_a_doctor___Im_a_doctor_and_I_want_my_sausages
}

soundManager.waitForWindowLoad = true;
soundManager.onready(main);
