// nikatlas -- Solar System
(function() {
    var MAX_CAM = 300;
    PouchDB.debug.disable('*');
    var ZEROVECTOR = new THREE.Vector2(0,0);
    var X_AXIS = new THREE.Vector3(1,0,0);
    var Y_AXIS = new THREE.Vector3(0,1,0);
    var Z_AXIS = new THREE.Vector3(0,0,1);

    var ZERO_ROT_QUAT = new THREE.Quaternion(0,0,0,1);

    var controls;
    var manager;
    var loader;
    var _textures = {};

    var Game = window.GameInstance =  new window.Game();
    var GameBox = new window.GameBox(5,14,5);
 
    var moveVector = new THREE.Vector2(0,0);
    var lookVector = new THREE.Vector3(0,0,1);
    var paused = false;
    var db = new PouchDB('tetris3d');
    window.remoteDB = new PouchDB('http://tetrisuser:tetrispass@couchdb.onarbooks.com:80/tetris3d');
    function init() {

        Game.init();
        

        addLights(Game.scene);
        
        window.scene = Game.scene; // DEBUG

        manager = new THREE.LoadingManager();
        loader = new THREE.TextureLoader(manager);
        
        createScene(Game.scene);

        // controls
        controls = new THREE.OrbitControls(Game.camera, Game.renderer.domElement);
        controls.minPolarAngle = Math.PI * 0.28;
        controls.maxPolarAngle = Math.PI * 0.48;
        controls.minDistance = 30;
        controls.maxDistance = MAX_CAM;
        controls.target.copy(new THREE.Vector3(0,5.5,0));
        Game.camera.lookAt(new THREE.Vector3(0,5.5,0));

        GameBox.init(Game.scene);
        GameBox.drop(new window.Shapes.Box(0x00ff20));
        

        Game.animate();
        var lasttime = 0,movelasttime=0;
        var oldLookVector = new THREE.Vector3(0,0,1);
        Game.addLoopFn(function(time){
            if(time - lasttime > GameBox.getSpeed()  && !paused ){ ////////////////////////////////////////////////      TIME     .....
                GameBox.progress();
                lasttime = time;
            }
            if(time - movelasttime > 0.05){
                if(!moveVector.equals(ZEROVECTOR) || !lookVector.equals(oldLookVector)){
                    var move = rotateToCamera(moveVector);
                    var look = rotateToCamera(lookVector);
                    look = vectorToLook(look);
                    GameBox.move(move.x,move.z, look.axis, look.degrees);
                    oldLookVector.copy(lookVector);
                    movelasttime = time;
                }
            }
            restoreUI();
        });
        function fixData(){
            db.allDocs({
                  include_docs: true,
                  descending : true,
                  limit : 5
                }).then(function(res){
                    var data = res.rows;
                    var s = "";
                    for(var i=0;i< data.length;i++){
                        s += ' \
                        <div class="row">\
                            <div class="col-xs-6">'+data[i].doc.name+'</div>\
                            <div class="col-xs-6">'+data[i].doc.score+'</div>\
                        </div>';
                    }
                    var scores = getit("scores");
                    scores.innerHTML = s;
                });
        }
        window.getFromDB = function(){
            db.changes().on('change', function() {
                fixData();
            });
            remoteDB.login('nikatlas', 'Nikos0349').then(function (user) {
                db.info();
            })
            .then(function (info) {
                  console.log(info);
                  db.sync(remoteDB);
            });

        };
        getFromDB();
        window.saveToDB = function(){
            var name = getit("name").value;
            if(!name)return;
            var mid = pad(GameBox.score,100) + name;
            db.put({
                _id : mid,
                name : name,
                score : GameBox.score
            }).then(function (result) {
              console.log(result);
              fixData();
            }).catch(function (err) {
              console.log(err);
            });;
        };
    }
    function pad(num, size) {var s = num+"";while (s.length < size) s = "0" + s;return s;}
    function getit(id){return document.getElementById(id);};
    function restoreUI(){
        var score = getit("highscore");
        score.innerHTML = GameBox.score || 0;

        if(GameBox.finished){
            var lost = getit("lost");
            lost.style.display = "block";
            var mscore = getit("myscore");
            mscore.innerHTML = GameBox.score || 0;
        }
    };

    window.restartGame = function(){
        if(GameBox.finished){
            var lost = getit("lost");
            lost.style.display = "none";
            GameBox.restart();
        }  
    }

    function rotateToCamera(v){
        var mat4 = new THREE.Matrix4();
        mat4.makeRotationFromQuaternion(Game.camera);
        var rot;
        if(v.z == undefined){
            rot = new THREE.Vector3(v.x,0,v.y);
        }
        else{
            rot = new THREE.Vector3(v.x,v.y,v.z);
        }

        rot.applyQuaternion(Game.camera.getWorldQuaternion());
        var x = rot.x;
        var y = rot.y;
        var z = rot.z;
        var ax = Math.abs(x) > Math.abs(z) && Math.abs(x) > Math.abs(y);
        var ay = Math.abs(y) > Math.abs(x) && Math.abs(y) > Math.abs(z);
        var az = Math.abs(z) > Math.abs(x) && Math.abs(z) > Math.abs(y);
        var sx = x > 0 ? 1 : -1;
        var sy = y > 0 ? 1 : -1;
        var sz = z > 0 ? 1 : -1;
        rot.set(sx * ax, sy * ay,sz * az); 
        return rot;
    }
    function getRotationOf(u, v)
    {
      if( u.equals(v) )return ZERO_ROT_QUAT;
      // It is important that the inputs are of equal length when
      // calculating the half-way vector.
      u = u.clone().normalize();
      v = v.clone().normalize();

      var k_cos_theta = u.clone().dot(v);
      var k = Math.sqrt(u.length() * v.length());
      // Unfortunately, we have to check for when u == -v, as u + v
      // in this case will be (0, 0, 0), which cannot be normalized.
      // if (u.equals(v.clone().multiplyScalar(-1)))
      if (k_cos_theta / k == -1)
      {
        // 180 degree rotation around any orthogonal vector
        var orthv = Y_AXIS;
        orthv.normalize();
        return new THREE.Quaternion(orthv.x , orthv.y , orthv.z , 0);
      }
      var cross = u.cross(v);
      return new THREE.Quaternion(cross.x ,  cross.y , cross.z , k_cos_theta + k ).normalize();
    }

    function vectorToLook(v){
        var q = getRotationOf(Z_AXIS, v);
        var qw = q.w;
        var angle = 2 * Math.acos(qw)
        var x = q.x /  Math.sqrt(1-qw*qw)
        var y = q.y /  Math.sqrt(1-qw*qw)
        var z = q.z /  Math.sqrt(1-qw*qw)


        var look = {
            axis : new THREE.Vector3(x,y,z),
            degrees : angle
        };
        return look;
    }

    // Create Scene
    function createScene(scene){
        box = createBox(5,5,5,0x11ff20);
        box.receiveShadow = true;
        box.castShadow = true;
        box.position.copy(new THREE.Vector3( -4 , 7 , 4 ));
        //console.log(box.position);
        //scene.add(box);
        box = createBox(4,1,4,0x00ff20);
        box.receiveShadow = true;
        box.castShadow = true;
        box.position.copy(new THREE.Vector3( 1 , 4 , 0 ));
        //console.log(box.position);
        //scene.add(box);

        plane = createTerrain(2025,2025,0x7f8f6f);
        plane.rotation.x = Math.PI / 2;
        plane.receiveShadow  = true;
        scene.add(plane);

        target = scene;
        createSkybox(scene);
    }



    // Lights
    function createDLight(color, intensity) {
        var l = new THREE.DirectionalLight( color, intensity );
        l.castShadow = true;
        l.shadowCameraRight     =  30;
        l.shadowCameraLeft     = -30;
        l.shadowCameraTop      =  30;
        l.shadowCameraBottom   = -30;
        l.shadow.mapSize.width = 1024;
        l.shadow.mapSize.height = 1024;
        l.shadow.map = null;
        return l;
    }
    function addLights(scene) {
        scene.add(new THREE.AmbientLight(0x111111)); // Ambient light

        // White directional light at half intensity shining from the top.
        var directionalLight = createDLight( 0xffffff, 0.55 );
        directionalLight.position.copy(new THREE.Vector3( 0 , 50, 0));
        directionalLight.castShadow = true;
        // var directionalLight2 = createDLight( 0xffffff, 0.15 );
        // directionalLight2.position.copy(new THREE.Vector3( -100 , 100, -45 ));
        // directionalLight2.castShadow = true;
        // var directionalLight3 = createDLight( 0xffffff, 0.15 );
        // directionalLight3.position.copy(new THREE.Vector3( 0 , 100 , 65 ));
        // directionalLight3.castShadow = true;

        //scene.add( directionalLight );
        // scene.add( directionalLight2 );
        // scene.add( directionalLight3 );
    }

    function load(k,path) {
        _textures[k] = loader.load(path, THREE.SphericalRefractionMapping);
    }
    function loadTextures() {
        manager.onProgress = function () {
            console.log("Progress");
        }
        manager.onLoad = function(){
            console.log("[-] Textures Loaded!")
            computeGraph();
        }
        //load('sun','textures/planets/sun.jpg');
    }
    

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    var earth,moon,sun,europa;
    function computeGraph() {
        return true;
    }
    // Input Handling
    var axis = X_AXIS;
    var degrees = 0;
    window.onkeydown = function (e) {
        if(e.keyCode == 65){ // a
            moveVector.x = -1;
        }
        else if(e.keyCode == 87){ // w
            moveVector.y = -1;
        }
        else if(e.keyCode == 68){ // d
            moveVector.x = 1;
        }
        else if(e.keyCode == 83){ // s
            moveVector.y = 1;
        }


        if(e.keyCode == 73){
            lookVector.z = -1;
            lookVector.x = 0;
            lookVector.y = 0;
        }
        else if(e.keyCode == 75){
            lookVector.z = 1;
            lookVector.x = 0;
            lookVector.y = 0;
        }

        if(e.keyCode == 74){
            lookVector.x = -1;
            lookVector.y = 0;
            lookVector.z = 0;
        }
        else if(e.keyCode == 76){
            lookVector.x = 1;
            lookVector.y = 0;
            lookVector.z = 0;
        }
        
        if(e.keyCode == 79){ //o
            lookVector.y = 1;
            lookVector.z = 0;
            lookVector.x = 0;
        }
        else if(e.keyCode == 85){ //u
            lookVector.y = -1;
            lookVector.z = 0;
            lookVector.x = 0;
        }


        if(e.keyCode == 32){
            GameBox.progressToNext();
        }
        console.log(e.keyCode);
    };
    window.onkeyup = function (e) {
        if(e.keyCode == 65){ // a
            moveVector.x = 0;
        }
        else if(e.keyCode == 87){ // w
            moveVector.y = 0;
        }
        else if(e.keyCode == 68){ // d
            moveVector.x = 0;
        }
        else if(e.keyCode == 83){ // s
            moveVector.y = 0;
        }

        // if(e.keyCode == 73){
        //     lookVector.y = 0;
        // }
        // else if(e.keyCode == 75){
        //     lookVector.y = 0;
        // }

        // if(e.keyCode == 74){
        //     lookVector.x = 0;
        // }
        // else if(e.keyCode == 76){
        //     lookVector.x = 0;
        // }


        if(e.keyCode == 80){
            paused = !paused;
        }
    };


    var raycaster = new THREE.Raycaster();
    var dragging = false;
    window.onmousedown = function (event) {
        // var mx = ( event.clientX / window.innerWidth ) * 2 - 1;
        // var my = - ( event.clientY / window.innerHeight ) * 2 + 1;
        // var mouse = new THREE.Vector2(mx,my);
        // // update the picking ray with the camera and mouse position
        // raycaster.setFromCamera( mouse, Game.camera );

        // // calculate objects intersecting the picking ray
        // var intersects = raycaster.intersectObjects( Game.scene.children, true );
        // if(intersects.length){
        //     dragging = intersects[0].object;
        // }
    };
    window.onmouseup = function (event) {
        dragging = false;
    };
    var lastmx=0,lastmy=0;
    window.onmousemove = function (event) {
        if(dragging){
            var mx = ( event.clientX / window.innerWidth ) * 2 - 1;
            var my = - ( event.clientY / window.innerHeight ) * 2 + 1;
            var dx = (mx - lastmx)*30;
            var dy = (my - lastmy)*30;
            lastmx = mx;
            lastmy = my;
            if(typeof dx != "number"  || typeof dy != "number" )return;
            switch(axis){
                case 1 :
                    dragging.position.x +=  dx;
                    break;
                case 2 : 
                    dragging.position.y +=  dy;
                    break;
                case 3 : 
                    dragging.position.z +=  dx;
                    break;
            }
        }

    };





















    ///////////////////////// HELPERS /////////////////////////////////

    function createSkybox(scene) {
        /////////////////////////////////////////////////////////////////////
        ///// SKYBOX
        var urlPrefix = "textures/skybox/Daylight Box_";
        var urls = [ "Left.bmp",  "Right.bmp",
            "Top.bmp",  "Bottom.bmp",
            "Back.bmp", "Front.bmp" ];
        scene.background = new THREE.CubeTextureLoader()
        .setPath( urlPrefix )
        .load(urls);
        return;
    
    }
    function createBox(x,y,z,color){
        //  This is where introtowebgl uses CubeGeometry
        var geometry = new THREE.BoxGeometry(x,y,z);

        //var material = new THREE.MeshBasicMaterial({ color: color, shading : THREE.SmoothShading });
        var material = new THREE.MeshPhongMaterial( { 
            color: color, 
            specular: 0x050505,
            shininess: 100
        } );
        var cube = new THREE.Mesh(geometry,material);
        return cube;
    }

    function generateHeight( width, height ) {
        var size = width * height, data = new Uint8Array( size ),
        perlin = new ImprovedNoise(), quality = 1, z = Math.random() * 100;
        for ( var j = 0; j < 4; j ++ ) {
            for ( var i = 0; i < size; i ++ ) {
                var x = i % width, y = ~~ ( i / width );
                data[ i ] += Math.abs( perlin.noise( x / quality, y / quality, z ) * quality * 1.75 );
            }
            quality *= 5;
        }
        return data;

    }

    function createTerrain(w,h,color){
        var geometry = new THREE.PlaneGeometry( w, h, w/8, h/8);
        var vertices = geometry.vertices;
        var NOISE = generateHeight(w/8+1,h/8+1);
        for ( var i = 0, l = vertices.length; i < l; i ++) {
            vertices[ i ].z = NOISE[ i ] + 10;
        }

        var texture = new THREE.TextureLoader().load( "textures/terrains/desertrock.jpg" );
        texture.wrapS = THREE.RepeatWrapping;
        texture.wrapT = THREE.RepeatWrapping;
        texture.repeat.set( w/64, w/64 );

        //var material = new THREE.MeshBasicMaterial( {color: color, side: THREE.DoubleSide} );
        var material = new THREE.MeshPhongMaterial({
            specular: 0x030303,
            map : texture,
            color : color,
            alphaTest: 0.8,
            shininess: 2,
            side: THREE.DoubleSide,
            shading : THREE.SmoothShading
        });
        var plane = new THREE.Mesh( geometry, material );
        return plane;
    }


    init();
})();


