/**
 * Warning: This happens when you let musician write any kind of code
 */
(function () {
    var Assets = Assets || function () {
        this.assets = {
            particle:  new THREE.ImageUtils.loadTexture('images/particle.png'),
            end0T:     new THREE.ImageUtils.loadTexture('images/end1.png'),
            end1T:     new THREE.ImageUtils.loadTexture('images/end2.png'),
            end2T:     new THREE.ImageUtils.loadTexture('images/end3.png'),
            start0T:   new THREE.ImageUtils.loadTexture('images/fist.png'),
            start1T:   new THREE.ImageUtils.loadTexture('images/start1.png'),
            start2T:   new THREE.ImageUtils.loadTexture('images/start2.png'),
            start3T:   new THREE.ImageUtils.loadTexture('images/start3.png'),
            start4T:   new THREE.ImageUtils.loadTexture('images/start4.png'),
            start5T:   new THREE.ImageUtils.loadTexture('images/start5.png'),
            credits0T: new THREE.ImageUtils.loadTexture('images/fist.png'),
            credits1T: new THREE.ImageUtils.loadTexture('images/credits1.png'),
            credits2T: new THREE.ImageUtils.loadTexture('images/credits2.png'),
            credits3T: new THREE.ImageUtils.loadTexture('images/credits3.png'),
            credits4T: new THREE.ImageUtils.loadTexture('images/credits4.png'),
            credits5T: new THREE.ImageUtils.loadTexture('images/credits5.png'),
            credits6T: new THREE.ImageUtils.loadTexture('images/credits6.png'),
            credits7T: new THREE.ImageUtils.loadTexture('images/credits7.png'),
            credits8T: new THREE.ImageUtils.loadTexture('images/credits8.png'),
            greet0T:   new THREE.ImageUtils.loadTexture('images/greet0.png'),
            greet1T:   new THREE.ImageUtils.loadTexture('images/greet1.png'),
            greet2T:   new THREE.ImageUtils.loadTexture('images/greet2.png'),
            greet3T:   new THREE.ImageUtils.loadTexture('images/greet3.png'),
            greet4T:   new THREE.ImageUtils.loadTexture('images/greet4.png'),
            greet5T:   new THREE.ImageUtils.loadTexture('images/greet5.png'),
            greet6T:   new THREE.ImageUtils.loadTexture('images/greet6.png'),
            greet7T:   new THREE.ImageUtils.loadTexture('images/greet7.png'),
            greet8T:   new THREE.ImageUtils.loadTexture('images/greet8.png'),
            greet9T:   new THREE.ImageUtils.loadTexture('images/greet9.png'),
            greet10T:  new THREE.ImageUtils.loadTexture('images/greet10.png'),
            greet11T:  new THREE.ImageUtils.loadTexture('images/greet11.png'),
            greet12T:  new THREE.ImageUtils.loadTexture('images/greet12.png'),
            greet13T:  new THREE.ImageUtils.loadTexture('images/greet13.png'),
            greet14T:  new THREE.ImageUtils.loadTexture('images/greet14.png'),
            audio:     new Audio('music/fts.mp3')
        };
    };
    Assets.prototype.getAsset = function (id) {
        return this.assets[id];
    };

    var Demo = Demo || function (s) {
    };

    Demo.prototype.init = function () {
        this.currentScenes = [];
    };

    Demo.prototype.start = function () {
        this.renderer = new THREE.WebGLRenderer({
            canvas: canvasEl,
            antialias: true
        });
        this.renderer.setSize(window.innerWidth, window.innerHeight);
        this.renderer.autoClear = false;
        this.starttime = new Date().getTime();

        // play
        a.getAsset('audio').play();
        this.animate();
    };

    Demo.prototype.startScene = function (scene, options) {
        console.log('start scene', scene.id);
        this.currentScenes.unshift(scene);
        scene.start.apply(scene, options);
    };

    Demo.prototype.endScene = function (scene) {
        console.log('end scene', scene.id);
        this.currentScenes = this.currentScenes.filter(function (s) {
            return s !== scene;
        });
    };

    Demo.prototype.animate = function () {
        var curTime = new Date().getTime() - this.starttime;
        // animate scene
        if (this.currentScenes.length > 0) {
            var s, i;

            this.renderer.clear(0x000000);
            for (i in this.currentScenes) {
                s = this.currentScenes[i];
                s.animate(curTime);
                this.renderer.render(s.getScene(), s.getCamera());
            }
        }

        var that = this;
        requestAnimationFrame(function () {
            that.animate();
        });

    };

    var Scene1 = function () {
        this.id = 'scene1';
    };
    Scene1.prototype.getScene = function () {
        return this.scene;
    };
    Scene1.prototype.getCamera = function () {
        return this.camera;
    };
    Scene1.prototype.init = function () {
        console.log('init ' + this.id);
        var i,
            j,
            spacing = 300,
            size = 300,
            mesh,
            geometry = new THREE.CubeGeometry(size, size, size),
            material = new THREE.MeshLambertMaterial({ color: 0x552222, shading: THREE.FlatShading });

        this.camera = new THREE.PerspectiveCamera(65, window.innerWidth / window.innerHeight, 1, 10000);
        this.camera.position.x = 500;
        this.camera.position.z = 2000;
        this.camera.position.y = 400;
        this.camera.lookAt(new THREE.Vector3(-500, 0, 0));
        this.camera.tween = TweenMax.to(this.camera.position, beatS * 8, {z: -1000, x: 1000, lookAtY: -100, ease: Linear.easeInOut, paused: true});
        this.scene = new THREE.Scene();

        this.group = new THREE.Object3D();
        for (i = -10; i < 10; i++) {
            for (j = -10; j < 10; j++) {
                mesh = new THREE.Mesh(geometry, material);
                mesh.position.x = i * spacing;
                mesh.position.z = j * spacing;
                mesh.tweens = {};
                this.group.add(mesh);
            }
        }
        this.scene.add(this.group);

        this.fog = new THREE.Fog(0x000000, 1000, 3000);
        this.scene.fog = this.fog;

        this.light = new THREE.PointLight(0xffffff, 1);
        this.light.position.set(0, 5000, 3000);
        this.scene.add(this.light);
    };
    Scene1.prototype.start = function () {
        var mesh, t1, t2, t3, t4, i, len;
        this.camera.position.z = 2000;
        this.camera.position.x = 0;
        this.camera.tween.restart();

        for (i = 0, len = this.group.children.length; i < len; i++) {
            mesh = this.group.children[i];
            mesh.position.y = 100;
            t1 = TweenMax.to(mesh.position, beatS * 2, {y: 100 * Math.sin(i) + Math.cos(i * 2), ease: Cubic.easeOut, overwrite: "none"});
            t2 = TweenMax.to(mesh.position, beatS * 2, {y: 100 * Math.cos(i) + Math.sin(i / 2), ease: Cubic.easeOut, delay: beatS * 2, overwrite: "none"});
            t3 = TweenMax.to(mesh.position, beatS * 2, {y: 100 * Math.sin((-i) / 2) + Math.cos(i * 2), ease: Cubic.easeOut, delay: beatS * 4, overwrite: "none"});
            t4 = TweenMax.to(mesh.position, beatS * 2, {y: 100 * Math.cos(-i) + Math.sin(i * 2), ease: Cubic.easeOut, delay: beatS * 6, overwrite: "none"});
        }
    };
    Scene1.prototype.stop = function () {

    };
    Scene1.prototype.animate = function (curTime) {
    };

    var Scene2 = function () {
        this.id = 'scene2';
    };
    Scene2.prototype.getScene = function () {
        return this.scene;
    };
    Scene2.prototype.getCamera = function () {
        return this.camera;
    };
    Scene2.prototype.init = function () {
        console.log('init ' + this.id);
        var geometry = new THREE.SphereGeometry(800, 13, 13);
        var material = new THREE.SpriteMaterial({
            map:      a.getAsset('particle'),
            color:    0x552222,
            fog:      true,
            size:     1000,
            blending: THREE.AdditiveBlending
        });
        this.camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000);
        this.camera.position.z = 1000;
        this.camera.tween = TweenMax.to(this.camera.position, beatS * 8, {paused: true, z: -1000, x: 1000, y: 4000, ease: Cubic.easeInOut, onUpdateParams: [this.camera], onUpdate: function (c) {
            c.lookAt(new THREE.Vector3(0, 0, 0))
        }});
        this.scene = new THREE.Scene();
        this.particles = new THREE.Object3D;
        var p;
        for (var i = 0; i < 750; i++) {
            p = new THREE.Sprite(material);
            p.scale.x = p.scale.y = 512;
            p.tween = TweenMax.to(p.scale, beatS, {paused: true, x: 16, y: 16, repeat: 8});

            this.particles.add(p);
        }
        this.scene.add(this.particles)

    };
    Scene2.prototype.start = function () {
        var particle,
            i,
            len;
        for (i = 0, len = this.particles.children.length; i < len; i++) {
            particle = this.particles.children[i];
            particle.scale.x = particle.scale.y = 512;
            particle.tween.restart().seek(0);
        }

        this.camera.position.set(0, 0, 2000);
        this.camera.tween.restart();
    };
    Scene2.prototype.stop = function () {
    };
    Scene2.prototype.animate = function (curTime) {
        var particle,
            modifier,
            i,
            len,
            deg = 360 / this.particles.children.length,
            cur = (curTime % 350) / 15000;
        for (i = 0, len = this.particles.children.length; i < len; i++) {
            particle = this.particles.children[i];
            modifier = (i * deg) + cur;

            particle.position.set(
                (Math.sin(modifier) + Math.cos(modifier / 2) + Math.sin(modifier * 7)) * 2000,
                (Math.cos(modifier) + Math.cos(modifier * 2) + Math.cos(modifier * 5)) * 2000,
                ((Math.sin(modifier) * Math.cos(modifier * 2) * Math.sin(modifier * 9)) * 2000)
            );
        }
    };


    var Scene3 = function () {
        this.id = 'scene3';
    };
    Scene3.prototype.getScene = function () {
        return this.scene;
    };
    Scene3.prototype.getCamera = function () {
        return this.camera;
    };
    Scene3.prototype.init = function () {
        console.log('init ' + this.id);
        this.camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000);
        this.camera.position.z = 0;
        this.scene = new THREE.Scene();
        this.group = new THREE.Object3D();
        var i, j, mesh,
            geometry = new THREE.CubeGeometry(330, 50, 100),
            material = new THREE.MeshLambertMaterial({ color: 0x552222, shading: THREE.FlatShading });
        for (i = 0; i < 50; i++) {
            for (j = 0; j < 4; j++) {
                mesh = new THREE.Mesh(geometry, material);
                if (j % 2 == 0) {
                    mesh.rotation.z = Math.PI / 2;
                }
                mesh.delay = beatS * ((i + 1) / 10);
                switch (j) {
                    case 0:
                        mesh.origPosition = new THREE.Vector3(-200, 0, -i * 100);
                        mesh.position.set(mesh.origPosition.x, mesh.origPosition.y, mesh.origPosition.z);
                        mesh.tween = TweenMax.to(mesh.position, beatS, {x: -300, paused: true, repeat: -1, yoyo: true, delay: mesh.delay});
                        break;
                    case 1:
                        mesh.origPosition = new THREE.Vector3(0, 200, -i * 100);
                        mesh.position.set(mesh.origPosition.x, mesh.origPosition.y, mesh.origPosition.z);
                        mesh.tween = TweenMax.to(mesh.position, beatS, {y: 300, paused: true, repeat: -1, yoyo: true, delay: mesh.delay});
                        break;
                    case 2:
                        mesh.origPosition = new THREE.Vector3(200, 0, -i * 100);
                        mesh.position.set(mesh.origPosition.x, mesh.origPosition.y, mesh.origPosition.z);
                        mesh.tween = TweenMax.to(mesh.position, beatS, {x: 300, paused: true, repeat: -1, yoyo: true, delay: mesh.delay});
                        break;
                    case 3:
                        mesh.origPosition = new THREE.Vector3(0, -200, -i * 100);
                        mesh.position.set(mesh.origPosition.x, mesh.origPosition.y, mesh.origPosition.z);
                        mesh.tween = TweenMax.to(mesh.position, beatS, {y: -300, paused: true, repeat: -1, yoyo: true, delay: mesh.delay});
                        break;
                }
                this.group.add(mesh);
            }
        }

        this.scene.add(this.group);
        this.fog = new THREE.Fog(0x000000, 1000, 4000);
        this.scene.fog = this.fog;
        this.light = new THREE.PointLight(0xffffff, 1);
        this.light.position.set(this.camera.position.x, this.camera.position.y, this.camera.position.z);
        this.scene.add(this.light);

    };
    Scene3.prototype.start = function () {
        console.log('start 3');
        var mesh,
            i,
            len;
        this.group.position.z = 0;
        this.group.rotation.z = 0;
        TweenMax.to(this.group.rotation, beatS * 8, {z: Math.PI * 2, ease: Cubic.easeInOut});
        for (i = 0, len = this.group.children.length; i < len; i++) {
            mesh = this.group.children[i];
            mesh.position.set(mesh.origPosition.x, mesh.origPosition.y, mesh.origPosition.z);
            mesh.tween.resume();
        }
    };
    Scene3.prototype.stop = function () {
        var mesh,
            i,
            len;
        for (i = 0, len = this.group.children.length; i < len; i++) {
            mesh = this.group.children[i];
            mesh.tween.kill();
        }
    };
    Scene3.prototype.animate = function (curTime) {
    };

    var Overlays = function () {
        this.id = 'overlays';
    };
    Overlays.prototype.getScene = function () {
        return this.scene;
    };
    Overlays.prototype.getCamera = function () {
        return this.camera;
    };
    Overlays.prototype.start = function () {
        var that = this,
            i = 0,
            offset = beat * 0,
            creditsF,
            greetsF,
            startF

        startF = function (i, e) {
            if (typeof(e) === 'undefined') e = 15;
            var mat = i % 6;
            that.plane.material.map = a.getAsset('start' + mat + 'T');
            if (i == 0)that.scene.add(that.plane);
            if (i == e)that.scene.remove(that.plane);
        };
        creditsF = function (i, e) {
            if (typeof(e) === 'undefined') e = 15;
            var mat = i % 9;
            that.plane.material.map = a.getAsset('credits' + mat + 'T');
            if (i == 0)that.scene.add(that.plane);
            if (i == e)that.scene.remove(that.plane);
        };
        greetsF = function (i, e) {
            if (typeof(e) === 'undefined') e = 15;
            var mat = i % 15;
            that.plane.material.map = a.getAsset('greet' + mat + 'T');
            if (i == 0)that.scene.add(that.plane);
            if (i == e)that.scene.remove(that.plane);
        };

        for (i = 0; i < 16; i++) {
            setTimeout(startF, beat * i + offset, i);
        }
        for (i = 0; i < 14; i++) {
            setTimeout(creditsF, beat * 8 * 2 + beat * i + offset, i, 13);
        }
        for (i = 0; i < 16; i++) {
            setTimeout(startF, beat * 8 * 4 + beat * i + offset, i);
        }
        for (i = 0; i < 16; i++) {
            setTimeout(creditsF, beat * 8 * 6 + beat * i + offset, i);
        }
        for (i = 0; i < 16; i++) {
            setTimeout(greetsF, beat * 8 * 8 + beat * i + offset, i);
        }
        for (i = 0; i < 36; i++) {
            setTimeout(startF, beat * 8 * 10 + beat * i + offset, i, 35);
        }
        setTimeout(function () {
            that.plane.material.map = a.getAsset('end0T');
            that.scene.add(that.plane);
        }, 53500);
        setTimeout(function () {
            that.plane.material.map = a.getAsset('end1T');
        }, 53900);
        setTimeout(function () {
            that.plane.material.map = a.getAsset('end2T');
        }, 54300);
        setTimeout(function () {
            that.plane.material.map = a.getAsset('start0T');
        }, 58070);

    };
    Overlays.prototype.stop = function () {

    };
    Overlays.prototype.init = function () {
        console.log('init ' + this.id);
        this.material = new THREE.MeshBasicMaterial({
            map:         Assets.start3T,
            shading:     THREE.FlatShading,
            fog:         false,
            transparent: true
        });
        this.scene = new THREE.Scene();
        this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
        this.camera.position.z = 2010;
        this.camera.lookAt(new THREE.Vector3(0, 0, 0));
        this.plane = new THREE.Mesh(new THREE.PlaneGeometry(10, 10), this.material);
        this.plane.position.z = 2000;

    };
    Overlays.prototype.animate = function (curTime) {
    };


    function enterFullScreen() {
        if (fullscreen === true) return false;
        fullscreen = true;

        setTimeout(function () {
            o.init();
            s1.init();
            s2.init();
            s3.init();
            d.init();

            d.start();
            d.startScene(o);
            d.startScene(s1);

            // pretty....
            setTimeout(function () {
                d.startScene.apply(d, [s2]);
                d.endScene.apply(d, [s1]);
            }, 8 * beat + offset);
            setTimeout(function () {
                d.startScene.apply(d, [s3]);
                d.endScene.apply(d, [s2]);
            }, 2 * 8 * beat + offset);
            setTimeout(function () {
                d.startScene.apply(d, [s1]);
                d.endScene.apply(d, [s3]);
            }, 3 * 8 * beat + offset);
            setTimeout(function () {
                d.startScene.apply(d, [s2]);
                d.endScene.apply(d, [s1]);
            }, 4 * 8 * beat + offset);
            setTimeout(function () {
                d.startScene.apply(d, [s3]);
                d.endScene.apply(d, [s2]);
            }, 5 * 8 * beat + offset);
            setTimeout(function () {
                d.startScene.apply(d, [s1]);
                d.endScene.apply(d, [s3]);
            }, 6 * 8 * beat + offset);
            setTimeout(function () {
                d.startScene.apply(d, [s2]);
                d.endScene.apply(d, [s1]);
            }, 7 * 8 * beat);
            setTimeout(function () {
                d.startScene.apply(d, [s3]);
                d.endScene.apply(d, [s2]);
            }, 8 * 8 * beat);
            setTimeout(function () {
                d.startScene.apply(d, [s1]);
                d.endScene.apply(d, [s3]);
            }, 9 * 8 * beat + offset);
            setTimeout(function () {
                d.startScene.apply(d, [s2]);
                d.endScene.apply(d, [s1]);
            }, 10 * 8 * beat + offset);
            setTimeout(function () {
                d.startScene.apply(d, [s3]);
                d.endScene.apply(d, [s2]);
            }, 11 * 8 * beat + offset);
            setTimeout(function () {
                d.startScene.apply(d, [s1]);
                d.endScene.apply(d, [s3]);
            }, 12 * 8 * beat + offset);
            setTimeout(function () {
                d.startScene.apply(d, [s2]);
                d.endScene.apply(d, [s1]);
            }, 13 * 8 * beat + offset);
            setTimeout(function () {
                d.startScene.apply(d, [s3]);
                d.endScene.apply(d, [s2]);
            }, 14 * 8 * beat + offset);
            setTimeout(function () {
                d.endScene.apply(d, [s3]);
            }, 53000);
        }, 250);
    }

    var fullscreen = false;
    var tempo = 130;
    var beatS = (60 / tempo);
    var beat = beatS * 1000;

    var offset = 0;
    var a = new Assets();
    var d = new Demo();

    // demo
    var s1 = new Scene1();
    var s2 = new Scene2();
    var s3 = new Scene3();
    var o = new Overlays();

    var loadingText = document.getElementById('loading');
    var startBtn = document.getElementById('start');
    var canvasEl = document.getElementById('canvas');

    a.getAsset('audio').addEventListener('canplaythrough', function () {
        loadingText.style.display = "none";
        startBtn.style.display = "inline";
    });

    // start screen stuff
    startBtn.addEventListener('click', function (e) {
        var container = document.getElementById('container');
        container.parentNode.removeChild(container);
        if (canvasEl.requestFullscreen) {
            canvasEl.requestFullscreen();
        } else if (canvasEl.msRequestFullscreen) {
            canvasEl.msRequestFullscreen();
        } else if (canvasEl.mozRequestFullScreen) {
            canvasEl.mozRequestFullScreen();
        } else if (canvasEl.webkitRequestFullscreen) {
            canvasEl.webkitRequestFullscreen();
        } else {
            enterFullScreen();
        }
        document.addEventListener('mozfullscreenchange', enterFullScreen);
        document.addEventListener('webkitfullscreenchange', enterFullScreen);
        document.addEventListener('MSFullscreenChange', enterFullScreen);
        document.addEventListener('fullscreenchange', enterFullScreen);

    });

})();
