package activities;

import java.io.IOException;
import java.util.ArrayList;



import javax.microedition.khronos.opengles.GL10;

import org.anddev.andengine.audio.music.Music;
import org.anddev.andengine.audio.music.MusicFactory;
import org.anddev.andengine.audio.sound.Sound;
import org.anddev.andengine.audio.sound.SoundFactory;
import org.anddev.andengine.engine.Engine;

import org.anddev.andengine.engine.camera.SmoothCamera;

import org.anddev.andengine.engine.handler.IUpdateHandler;
import org.anddev.andengine.engine.handler.timer.ITimerCallback;
import org.anddev.andengine.engine.handler.timer.TimerHandler;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLayer;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLoader;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXObject;

import org.anddev.andengine.entity.layer.tiled.tmx.TMXProperties;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTile;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTileProperty;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTiledMap;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLoader.ITMXTilePropertiesListener;
import org.anddev.andengine.entity.layer.tiled.tmx.util.exception.TMXLoadException;
import org.anddev.andengine.entity.primitive.Rectangle;
import org.anddev.andengine.entity.scene.Scene;


import org.anddev.andengine.entity.scene.Scene.IOnSceneTouchListener;
import org.anddev.andengine.entity.scene.menu.MenuScene;
import org.anddev.andengine.entity.scene.menu.MenuScene.IOnMenuItemClickListener;
import org.anddev.andengine.entity.scene.menu.item.decorator.ColorMenuItemDecorator;
import org.anddev.andengine.entity.scene.menu.item.TextMenuItem;
import org.anddev.andengine.entity.scene.menu.item.IMenuItem;
import org.anddev.andengine.entity.shape.Shape;


import org.anddev.andengine.entity.util.FPSLogger;

import org.anddev.andengine.extension.physics.box2d.PhysicsConnector;
import org.anddev.andengine.extension.physics.box2d.PhysicsFactory;
import org.anddev.andengine.extension.physics.box2d.PhysicsWorld;
import org.anddev.andengine.input.touch.TouchEvent;

import org.anddev.andengine.opengl.font.Font;
import org.anddev.andengine.opengl.font.FontFactory;
import org.anddev.andengine.opengl.texture.Texture;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.opengl.texture.region.TextureRegionFactory;

import org.anddev.andengine.sensor.SensorDelay;
import org.anddev.andengine.sensor.accelerometer.AccelerometerData;
import org.anddev.andengine.sensor.accelerometer.AccelerometerSensorOptions;
import org.anddev.andengine.sensor.accelerometer.IAccelerometerListener;
import org.anddev.andengine.ui.activity.BaseGameActivity;
import org.anddev.andengine.util.Debug;


import tools.ShapeCreator;



import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.Contact;

import com.badlogic.gdx.physics.box2d.ContactListener;

import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.heyzap.sdk.HeyzapLib;

import entities.Collectible;
import entities.Player;
import entities.ScoreHUD;

import android.content.Context;
import android.graphics.Color;
import android.hardware.SensorManager;
import android.os.Vibrator;

import android.view.KeyEvent;
import android.view.WindowManager;


/**
 * @author Jose María Valle Rodríguez , Ernesto Lage Tejero
 * 
 */

// add the IOnSceneTouchListener to the implemented interfaces to add touch screen support (for the face generator)
public class NewLevel extends BaseGameActivity implements IAccelerometerListener, IOnMenuItemClickListener , IOnSceneTouchListener{
        // ===========================================================
        // Constants
        // ===========================================================

        private static final int CAMERA_WIDTH = 480;
        private static final int CAMERA_HEIGHT = 240;
       
        // variables for the shake detection
        
        //private static final int SHAKE_THRESHOLD 	= 1000;
    	//private static final int TIME_THRESHOLD 	= 100;
        
        
        //ingame menu entries
    	
    	protected static final int MENU_RETRY = 0;
    	protected static final int MENU_QUIT = MENU_RETRY + 1;
    	protected static final int MENU_SHARE = MENU_QUIT + 1;
    	
    	
    	//Java enum class for the color-value handling of the collectibles
    	public enum CollectibleColor {
    		Blue (50),
    		Grey  (100),
    		Lime (150),
    		Pink (200),
    		Red (250);
    		
    		private final int value;
    		
    		CollectibleColor(int value){
    			this.value = value;
    		}
    		
    		public int getValue(){
    			return this.value;
    		}
    	}


        // ===========================================================
        // Fields
        // ===========================================================
    	
    	private Vibrator vibrator;
    	
    	private int numCollectibles;
    	private SmoothCamera mCamera;
    	
    	private ScoreHUD mScoreHUD;
    	 
        private Texture mTexture;
        
        //private Sprite background;       
        //private Texture mBackgroundTexture;
    	//private TextureRegion mBackgroundTextureRegion;
        
        private Texture mFontTexture;
    	private Font mFont;
    	
    	protected MenuScene mMenuScene;
    	protected Scene mMainScene;
    	
    	private Music mMusic;
    	
        private TextureRegion mPlayerTextureRegion;
        
        //Texture regions for the collectibles
        
        private TextureRegion mCollectibleGreyTextureRegion;
        private TextureRegion mCollectibleBlueTextureRegion;
        private TextureRegion mCollectibleLimeTextureRegion;
        private TextureRegion mCollectiblePinkTextureRegion;
        private TextureRegion mCollectibleRedTextureRegion;
        
        private TMXTiledMap mTMXTiledMap;
        
        private static String mapName;
        private static int posXStart;
        private static int posYStart;
        
		
        private PhysicsWorld mPhysicsWorld;
        //private int mFaceCount = 0;
        
        //Player def
        private Player player1;
        private Body playerBody;
        
        //List of physical properties used for the elements of the game
        
        private static final FixtureDef wallFixtureDef = PhysicsFactory.createFixtureDef(10, 0, 3);
        private static final FixtureDef iceFixtureDef = PhysicsFactory.createFixtureDef(10, 0, 0);
        private static final FixtureDef deathFixtureDef = PhysicsFactory.createFixtureDef(10,1,3);
        private static final FixtureDef playerFixtureDef = PhysicsFactory.createFixtureDef(10, 0.1f, 3f);
        
    
        
        // Control variables
        // Acceleration variables
        private float accelX,accelY;
        
        //private float accelZ, deadAccelX, deadAccelY, lastAccelX, lastAccelY, lastAccelZ;
        //private long lastShake;
        
        //Variable used in the "death" timer in ms.
        private long lastPenalty;
        private float touchDownX , touchDownY, touchUpX, touchUpY;
        
        // Handlers
        
        //This list contains the update handler that check collision with each death surface
        //private List<IUpdateHandler> deathHandlers = new LinkedList<IUpdateHandler>();

        //Sounds 
        private Sound mDeathSound;
        private Sound mCollectSound;
           

        // ===========================================================
        // Constructors
        // ===========================================================

        // ===========================================================
        // Getter & Setter
        // ===========================================================
        
        protected static void setStartPosition(int x , int y){
        	posXStart = x;
        	posYStart = y;
        	
        }
        
        protected static void setMapName(String name){
        	mapName = name;
        }
        
        // ===========================================================
        // Methods for/from SuperClass/Interfaces
        // ===========================================================

        @Override
        public Engine onLoadEngine() {
        	
        	  vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
               
               
        		this.mCamera = new SmoothCamera(0,0,CAMERA_WIDTH,CAMERA_HEIGHT,200,200,0);      		
        	
               
                return new Engine(new EngineOptions(true, ScreenOrientation.LANDSCAPE, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT),mCamera).setNeedsMusic(true).setNeedsSound(true));
        }

        @Override
        public void onLoadResources() {
        	
        	
        	try {
    			mMusic = MusicFactory.createMusicFromAsset(this.mEngine.getMusicManager(), this, "mfx/levelmusic.mp3");
    			mMusic.setLooping(true);    			
    		} catch (final IOException e) {
    			Debug.e("Error", e);
    		}
    		
    		SoundFactory.setAssetBasePath("sfx/");
    		try {
    			this.mDeathSound = SoundFactory.createSoundFromAsset(this.mEngine.getSoundManager(), this, "death.wav");
    		} catch (final IOException e) {
    			Debug.e("Error", e);
    		}
    		
    		try {
    			this.mCollectSound = SoundFactory.createSoundFromAsset(this.mEngine.getSoundManager(), this, "button-37.wav");
    		} catch (final IOException e) {
    			Debug.e("Error", e);
    		}
              
    			//Loading the texture font for the timer, points and menu entries font
                this.mFontTexture = new Texture(256, 256, TextureOptions.BILINEAR);
                FontFactory.setAssetBasePath("fonts/");
                this.mFont = FontFactory.createFromAsset(this.mFontTexture, this, "Plok.ttf", 32, true, Color.WHITE);
                this.mEngine.getFontManager().loadFont(this.mFont);
                
                TextureRegionFactory.setAssetBasePath("gfx/");
                
               
                //this.mBackgroundTexture = new Texture(1024, 512, TextureOptions.DEFAULT);
                //this.mBackgroundTexture = new Texture(1024, 1024, TextureOptions.DEFAULT);
        		//this.mBackgroundTextureRegion = TextureRegionFactory.createFromAsset(this.mBackgroundTexture, this, "backgrounds/2.jpg", 0, 0);
                
                              
                /* Textures. */
                this.mTexture = new Texture(32, 128, TextureOptions.BILINEAR);
                
                /* TextureRegions. */
                
                this.mPlayerTextureRegion = TextureRegionFactory.createFromAsset(this.mTexture, this, "models/gnbmodel32.png", 0, 0); // 32x32
                this.mCollectibleBlueTextureRegion = TextureRegionFactory.createFromAsset(this.mTexture, this, "collectibles/collectibleblue.png",0,32); //16x16
                this.mCollectibleGreyTextureRegion = TextureRegionFactory.createFromAsset(this.mTexture, this, "collectibles/collectiblegrey.png",0,48); //16x16
                this.mCollectibleLimeTextureRegion = TextureRegionFactory.createFromAsset(this.mTexture, this, "collectibles/collectiblelime.png",0,64); //16x16
                this.mCollectiblePinkTextureRegion = TextureRegionFactory.createFromAsset(this.mTexture, this, "collectibles/collectiblepink.png",0,80); //16x16
                this.mCollectibleRedTextureRegion = TextureRegionFactory.createFromAsset(this.mTexture, this, "collectibles/collectiblered.png",0,96); //16x16
                
            
                this.mEngine.getTextureManager().loadTextures(this.mTexture, this.mFontTexture);
                
                
                this.enableAccelerometerSensor(this,new AccelerometerSensorOptions(SensorDelay.GAME));
                
                
        }

        @Override
        public Scene onLoadScene() {
                this.mEngine.registerUpdateHandler(new FPSLogger());
                
                this.mMenuScene = this.createMenuScene();

                this.mMainScene = new Scene(4);
                
                mMainScene.setBackgroundEnabled(true);    
                
				mMainScene.getBackground().setColor(0, 0, 0);
               
                mMainScene.setOnSceneTouchListener(this);
                
                this.mPhysicsWorld = new PhysicsWorld(new Vector2(0, SensorManager.GRAVITY_JUPITER), false);
                
                //Assign group index for collision management if needed
               
              
                
                ///////////*****MAP XML PARSER****////
                try {
        			final TMXLoader tmxLoader = new TMXLoader(this, this.mEngine.getTextureManager(), TextureOptions.DEFAULT, new ITMXTilePropertiesListener() {
        				@Override
        				public void onTMXTileWithPropertiesCreated(final TMXTiledMap pTMXTiledMap, final TMXLayer pTMXLayer, final TMXTile pTMXTile, final TMXProperties<TMXTileProperty> pTMXTileProperties) {
        					final int tmxTilePropertyCount = pTMXTileProperties.size();
        					
        					//For each property in each tile of the map
        					for(int i = 0; i < tmxTilePropertyCount; i++) {
        						final TMXTileProperty tmxTileProperty = pTMXTileProperties.get(i);
        						
        						//If collidable we create a matching physical shape
        						if(tmxTileProperty.getName().equals("collidable")) {

        				             Shape tile = new Rectangle(pTMXTile.getTileX(), pTMXTile.getTileY(), pTMXTile.getTileHeight(), pTMXTile.getTileWidth());        	                        
        	                       
        	                         //All shape physics functions in "ShapeCreator" class
        	                         ShapeCreator.createShape(mPhysicsWorld, tile, BodyType.StaticBody, wallFixtureDef, tmxTileProperty.getValue());
        	                        
        	                         tile.setUpdatePhysics(false);
        	                         
        	                         
        	                         
        	 
        						}
        						
        						//If death , we add a matching physical shape with rebound and we create
        						//a death handler to check for collisions with the object
        						if(tmxTileProperty.getName().equals("death")){
        							
        							final Shape tile = new Rectangle(pTMXTile.getTileX(), pTMXTile.getTileY(), pTMXTile.getTileHeight(), pTMXTile.getTileWidth());
        							
        							ShapeCreator.createShape(mPhysicsWorld, tile, BodyType.StaticBody, deathFixtureDef, tmxTileProperty.getValue());
        							
        							tile.setUpdatePhysics(false);
        							
        							/*
        							deathHandlers.add(new IUpdateHandler() {
        			    				
        			    				@Override
        			    				public void reset() { }

        			    				@Override
        			    				public void onUpdate(final float pSecondsElapsed) {
        			    					
        			    					//Last time collided check to avoid over penalty
        			    					if(System.currentTimeMillis() - lastPenalty > 3000){
        			    						player1.setAlpha(1);
        			    						
        			    					//If collided remove score and add invulnerability to the player
        			    					if(tile.collidesWith(player1)) {
        			    						
        			    						mDeathSound.play();
          			    			        	lastPenalty = System.currentTimeMillis();	
          			    			        	player1.setAlpha(0.6f);
          			    			        	mScoreHUD.addScore(-50);
          			    			        	vibrator.vibrate(200);
        			    						}
        			    						    			    							
        			    						
        			    					}
        			    				}
        			    			});  */     							
        							
        						}
        						
        						//For ice we create the same as a collidable but with matching
        						//ice surface fixture
        						if(tmxTileProperty.getName().equals("ice")) {

       				             Shape tile = new Rectangle(pTMXTile.getTileX(), pTMXTile.getTileY(), pTMXTile.getTileHeight(), pTMXTile.getTileWidth());        	                        
       	                       
       	                         //All shape physics functions in "ShapeCreator" class
       	                         ShapeCreator.createShape(mPhysicsWorld, tile, BodyType.StaticBody, iceFixtureDef, tmxTileProperty.getValue());
       	                        
       	                         tile.setUpdatePhysics(false);
       	                         
       	                         
       	                         
       	 
       						}
        						
        						
        						
        					}
        				}
        				        				
        			});
        			
        			this.mTMXTiledMap = tmxLoader.loadFromAsset(this, mapName);

        			
        		} catch (final TMXLoadException tmxle) {
        			Debug.e(tmxle);
        		}
        		

        		final TMXLayer tmxLayer = this.mTMXTiledMap.getTMXLayers().get(0);
        		
        		//Adding the graphical tile map to the scene to show it up
        		mMainScene.getLayer(0).addEntity(tmxLayer);
        		
        		//Registering the death handlers with the game logic update loop
        		/*
        		for (IUpdateHandler i:deathHandlers) {
        			mMainScene.registerUpdateHandler(i);
        			
        		}
        		*/
        		
        		//  Grabs the first object layer , then the first element of that layer (that should be the starting position)
        		// and modifies the starting positions accordingly
        		 
        		TMXObject startPos = mTMXTiledMap.getTMXObjectGroups().get(0).getTMXObjects().get(0);  		
        			
        			posXStart = startPos.getX();
        			posYStart = startPos.getY();
        			
        		
        		// The following part deals with the object layer with the collectibles positions , creating them
        		// inside the game and creating the proper handlers for the collision detection.
        			
        			
        		
        		
        		
        
        	
        		//The next section of codes stretches the background image to cover the sides of the screen without map        		
        		/* background = new Sprite(- CAMERA_WIDTH / 2, - CAMERA_HEIGHT / 2,this.mBackgroundTextureRegion);
        		
        		background.setHeight((this.mTMXTiledMap.getTileRows() * this.mTMXTiledMap.getTileHeight()) + CAMERA_HEIGHT);
        		background.setWidth((this.mTMXTiledMap.getTileColumns() * this.mTMXTiledMap.getTileWidth())+ CAMERA_WIDTH );
               
                
                mMainScene.getLayer(0).addEntity(background);*/
        		
        		
                /*************/       		
                
        		//PLAYER
        	   
        		//New sprite and physical body to link them up
        		player1 = new Player(posXStart, posYStart, this.mPlayerTextureRegion);
                playerBody = PhysicsFactory.createCircleBody(this.mPhysicsWorld, player1, BodyType.DynamicBody, playerFixtureDef);               
                playerBody.setUserData(playerFixtureDef);
                
                
                //Adding the player sprite to the scene to show it up and registering the physical connector to the physics engine
                mMainScene.getLayer(2).addEntity(player1);
                this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(player1, playerBody, true, true, false, false));
                
                mCamera.setChaseShape(player1);
                
                //here we join the ScoreHUD with the camera in order to follow it
                this.mScoreHUD = new ScoreHUD (this.mFont,this.mCamera);
				mCamera.setHUD(mScoreHUD);
				
				
				createCollectibles();		
        		
		        
        		mPhysicsWorld.setContactListener(new ContactListener() {
					
					@Override
					public void endContact(Contact contact) {
						// TODO Auto-generated method stub						
					}
					
					@Override
					public void beginContact(Contact contact) {						
						
						Object fixA, fixB;
						fixA = contact.getFixtureA().getBody().getUserData();
						fixB = contact.getFixtureB().getBody().getUserData();
						
						if((fixA == playerFixtureDef || fixA == deathFixtureDef) && (fixB == playerFixtureDef || fixB == deathFixtureDef) && player1.getAlpha() == 1){
							
								mDeathSound.play();
	    			        	lastPenalty = System.currentTimeMillis();	
	    			        	player1.setAlpha(0.6f);
	    			        	mScoreHUD.addScore(-50);
	    			        	vibrator.vibrate(200);
						}
						
						
											
					}
				});
        		
        		mMainScene.registerUpdateHandler(new IUpdateHandler() {
					
					@Override
					public void reset() {
						// TODO Auto-generated method stub
						
					}
					
					@Override
					public void onUpdate(float pSecondsElapsed) {
						// TODO Auto-generated method stub
						if(System.currentTimeMillis() - lastPenalty > 3000)							
    						player1.setAlpha(1);
						
					}
				});
				
				
				
				
       
                               
                mMainScene.registerUpdateHandler(this.mPhysicsWorld);
                
                // Timer handler to manage the updates of the HUD clock                
                mMainScene.registerUpdateHandler(new TimerHandler(1.0f, true, new ITimerCallback() {
        			@Override
        			public void onTimePassed(final TimerHandler pTimerHandler) {
        				mScoreHUD.addTime(1);        				
        			}
        		}));       
                



                return mMainScene;
        }

        public void onLoadComplete() {
        	
        	//Music handling
        	Menu.pauseMusic();
        	if(Menu.isMusicOn())
        	this.mMusic.play();
        	
        	//This is a flag to keep screen activated when playing
        	this.getWindow().setFlags(
      			  WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
      			  WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        }
        
        
        // ===========================================================
        // Methods
        // ===========================================================
        
        
        private void createCollectibles(){
        	
        	//We take the objects from the XML map object layer
        	ArrayList<TMXObject> collectibles = mTMXTiledMap.getTMXObjectGroups().get(1).getTMXObjects();
    		
        	
    		numCollectibles = collectibles.size();
    		
    		TMXObject collectible = null;
    		
    		ArrayList<Collectible> collectibleList = new ArrayList<Collectible>();
    		
    		//For each of the TMXobject we get it's name and create a collectible with the color and proper value
    		//using the Java enum ColectibleColor class. Then we add in to a list.
    		for (int i = 0; i< numCollectibles; i++){
    			
    			collectible = collectibles.get(i);
    			
    			if(collectible.getType().equals(CollectibleColor.Blue.name()))      			
    			collectibleList.add( new Collectible(collectible.getX(), collectible.getY(), mCollectibleBlueTextureRegion, CollectibleColor.Blue));
    			
    			if(collectible.getType().equals(CollectibleColor.Grey.name()))      			
        			collectibleList.add( new Collectible(collectible.getX(), collectible.getY(), mCollectibleGreyTextureRegion, CollectibleColor.Grey));
    			
    			if(collectible.getType().equals(CollectibleColor.Lime.name()))      			
        			collectibleList.add( new Collectible(collectible.getX(), collectible.getY(), mCollectibleLimeTextureRegion, CollectibleColor.Lime));
    			
    			if(collectible.getType().equals(CollectibleColor.Pink.name()))      			
        			collectibleList.add( new Collectible(collectible.getX(), collectible.getY(), mCollectiblePinkTextureRegion, CollectibleColor.Pink));
    			
    			if(collectible.getType().equals(CollectibleColor.Red.name()))      			
        			collectibleList.add( new Collectible(collectible.getX(), collectible.getY(), mCollectibleRedTextureRegion, CollectibleColor.Red));
    			
    			
    			}
    			  
    			//For each collectible now we add it to the main scene layer to show them
    		//and we create an update handler to check collisions.
    		for (final Collectible i : collectibleList){
    			       		
    			mMainScene.getLayer(3).addEntity(i);
    		
    		
    			mMainScene.registerUpdateHandler(new IUpdateHandler() {
    				
    				@Override
    				public void reset() { }

    				@Override
    				public void onUpdate(final float pSecondsElapsed) {
    					
    					//if collides we add score to the HUD and remove the collectible.
    					if(i.collidesWith(player1)) {
    						mCollectSound.play();
    						mScoreHUD.addScore(i.getScore());
    						mMainScene.getLayer(3).removeEntity(i);
    						mMainScene.unregisterUpdateHandler(this); 
    						numCollectibles--;
    						
    						//When all collected the game menu shows up to quit or share game
    						if(numCollectibles == 0)
    							
    							mMainScene.setChildScene(mMenuScene, false, true, true);
    						   						
    					} 
    				}
    			});
    			
    		}
        }
        
        
        //Show ingame menu when option phone button is pressed
        @Override
    	public boolean onKeyDown(final int pKeyCode, final KeyEvent pEvent) {
    		if(pKeyCode == KeyEvent.KEYCODE_MENU && pEvent.getAction() == KeyEvent.ACTION_DOWN) {
    			if(this.mMainScene.hasChildScene()) {
    				/* Remove the menu and reset it. */
    				this.mMenuScene.back();
    			} else {
    				/* Attach the menu. */
    				this.mMainScene.setChildScene(this.mMenuScene, false, true, true);
    			}
    			return true;
    		} else {
    			return super.onKeyDown(pKeyCode, pEvent);
    		}
    	}

    	//How every option in the menu works
    	public boolean onMenuItemClicked(final MenuScene pMenuScene, final IMenuItem pMenuItem, final float pMenuItemLocalX, final float pMenuItemLocalY) {
    		switch(pMenuItem.getID()) {
    			
    			case MENU_RETRY:
    				// Resets all the collectibles, timers and player.    				
    				mMainScene.clearUpdateHandlers();
    				
    				// Clear the remaining collectibles if any
    				mMainScene.getLayer(3).clear();
    				
    				mMainScene.registerUpdateHandler(mPhysicsWorld);
    				
    				
    				// Registers the time increase handler
    				mMainScene.registerUpdateHandler(new TimerHandler(1.0f, true, new ITimerCallback() {
            			@Override
            			public void onTimePassed(final TimerHandler pTimerHandler) {
            				
            				mScoreHUD.addTime(1);
            				
            			}
            		}));  
    				
    				
    				mMainScene.registerUpdateHandler(new IUpdateHandler() {
    					
    					@Override
    					public void reset() {
    						// TODO Auto-generated method stub
    						
    					}
    					
    					@Override
    					public void onUpdate(float pSecondsElapsed) {
    						// TODO Auto-generated method stub
    						if(System.currentTimeMillis() - lastPenalty > 3000)							
        						player1.setAlpha(1);
    						
    					}
    				});
    				
    				
    				// Registers again the handlers for the death collisions
    				/*for (IUpdateHandler i:deathHandlers) {
            			mMainScene.registerUpdateHandler(i);
            			
            		}*/
    				
    				//Creates and registers the handlers for the collectibles, and the collectibles
    				createCollectibles();
    			
    				this.mPhysicsWorld.destroyBody(playerBody);    				
    				//mMainScene.getLayer(2).removeEntity(player1);
    				player1.setPosition(posXStart, posYStart);
    				
    				//player1 = new Player(posXStart, posYStart, this.mPlayerTextureRegion);
                    playerBody = PhysicsFactory.createCircleBody(this.mPhysicsWorld, player1, BodyType.DynamicBody, playerFixtureDef);
                    
                    //mMainScene.getLayer(2).addEntity(player1);
                    this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(player1, playerBody, true, true, false, false));
                    playerBody.setUserData(playerFixtureDef);
                    
                    mCamera.setChaseShape(player1);
                    
                    mScoreHUD.resetHUD();
                        				
    				this.mMenuScene.back();
    							
    				return true;
    			
    			
    			case MENU_QUIT:
    				/* End Activity. */ 
    				//wl.release();
    				   				
    				this.finish();    				
    								
    				return true;
    				
    			case MENU_SHARE:
    				/* Share score on Heyzap */
    				
    				if(numCollectibles == 0)
    				HeyzapLib.checkin(this, "Completed " + NewLevel.mapName.subSequence(0, mapName.length() -4) + " with " + this.mScoreHUD.getScore() + " points in " + this.mScoreHUD.getTime() + " seconds.");
    				    				
    				   				
    								
    				return true;
    			
    			default:
    				return false;
    		}
    	}

      
    	
    	
   

		@Override
		public void onAccelerometerChanged(AccelerometerData pAccelerometerData) { 
		
		    accelX = pAccelerometerData.getX();
            accelY = pAccelerometerData.getY();
            //accelZ = pAccelerometerData.getZ(); //used for deadzone acceleration check
            
            this.mPhysicsWorld.setGravity(new Vector2(accelY,accelX));

            /*   This section activates the DEADZONE to avoid horizontal playing
            if(Math.abs(accelZ) < 6)
            {
				this.mPhysicsWorld.setGravity(new Vector2(accelY,accelX));
				deadAccelX = accelX;
				deadAccelY = accelY;
			}				
			else
			{
				this.mPhysicsWorld.setGravity(new Vector2(deadAccelY,deadAccelX));
			}*/
            
            
            
			/* SHAKE DETECTION, remember to uncomment the global variables.
			long currentTime = System.currentTimeMillis();         
            
           
            if((currentTime - lastShake) > TIME_THRESHOLD) {
           
                    long diffTime = currentTime - lastShake;
                    
                   
                    lastShake = currentTime;
                   
                
                   
                    float force = Math.abs(accelX+accelZ+accelY-lastAccelX-lastAccelZ-lastAccelY) / diffTime * 10000;
                    
                   
                    if(force > SHAKE_THRESHOLD)  //set this lower or higher to change the sensitivity
                    {                    
             
                    		
                    	
                    	this.playerBody.applyAngularImpulse(force * 0.05f * Math.signum(this.playerBody.getAngularVelocity()));
                    }
                  
                    lastAccelX = accelX;
                    lastAccelY = accelY;
                    lastAccelZ = accelZ;
                    
                   
                    
            }
             */
		}
		
		//Mechanics to handle the "Slide" touch gesture, we store the the position of the 
		//touch down and touch up , calculate an impulse vector and apply it to the player
		@Override
		public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) {
			if(this.mPhysicsWorld != null) {
				if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN) {
					this.runOnUpdateThread(new Runnable() {
						@Override
						public void run() {
							NewLevel.this.touchDownX = pSceneTouchEvent.getX();
							NewLevel.this.touchDownY = pSceneTouchEvent.getY();
						}
					});
					return true;
				}
				
				if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_UP) {
					this.runOnUpdateThread(new Runnable() {
						@Override
						public void run() {
							NewLevel.this.touchUpX = pSceneTouchEvent.getX();
							NewLevel.this.touchUpY = pSceneTouchEvent.getY();
							NewLevel.this.playerBody.setLinearVelocity(new Vector2(touchUpX - touchDownX , touchUpY - touchDownY).mul(0.07f));
						}
					});
					return true;
				}
			}
			return false;
		}
		
		

        protected MenuScene createMenuScene() {
            final MenuScene menuScene = new MenuScene(this.mCamera);

            
            final IMenuItem quitMenuItem = new ColorMenuItemDecorator(new TextMenuItem(MENU_QUIT, this.mFont, "QUIT"), 1.0f,0.0f,0.0f, 1.0f,1.0f,1.0f);
            quitMenuItem.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
            
            final IMenuItem retryMenuItem = new ColorMenuItemDecorator(new TextMenuItem(MENU_RETRY, this.mFont, "RETRY"), 1.0f,0.0f,0.0f, 1.0f,1.0f,1.0f);
            quitMenuItem.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
            
            final IMenuItem shareMenuItem = new ColorMenuItemDecorator(new TextMenuItem(MENU_SHARE, this.mFont, "SHARE"), 1.0f,0.0f,0.0f, 1.0f,1.0f,1.0f);
            quitMenuItem.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
            
            menuScene.addMenuItem(retryMenuItem);
            menuScene.addMenuItem(quitMenuItem);
            menuScene.addMenuItem(shareMenuItem);
           
            
            menuScene.buildAnimations();

            menuScene.setBackgroundEnabled(false);

            menuScene.setOnMenuItemClickListener(this);
            return menuScene;
    }
        
 public void onWindowFocusChanged(boolean pHasWindowFocus) {
        	
            super.onWindowFocusChanged(pHasWindowFocus);
            
            /*
            if(pHasWindowFocus == false)
            	wl.release();
            else
            	wl.acquire(); */
            
           if(Menu.isMusicOn()){ 
        	if(pHasWindowFocus == false)
        		mMusic.pause();
        	else 
        		mMusic.resume();     
        	}
        
        }
         


        // ===========================================================
        // Inner and Anonymous Classes
        // ===========================================================
}
