/*
 * Land Sea Air -- an interactive music game
 * demonstrating the "secret yanni" techique, with key changes
 * design, animation, audio, and code by peter "pdx" drescher
 * twittering machine
 * 
 */
package com.twittering.landseaair;

import java.util.Random;
import com.twittering.landseaair.R;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.view.Gravity;
import android.widget.Toast;

public class SeaAnimation {

	private Bitmap mSeaBed;
    private Bitmap mSprite[] = new Bitmap[10];
    private Bitmap mPlankton[] = new Bitmap[NUMBER_OF_PLANKTON];

    private Random mRnd = new Random();
	FMODaudio mFMODaudio = new FMODaudio();
    private Canvas mCanvas;
    private Context mContext;
	private Activity mActivity;
	
    public static final int FPS = 30; // milliseconds
    public static final int PLANK_RELEASE = 5000; // milliseconds
    public static final int DRUNKARDS_WALK_AMT = 75; // pixels
    public static final int PLANKY_SPEED = 2; // pixels
    public static final int PLANKX_SPEED = 1; // pixels

    private float mSpriteX = 0;
    private float mSpriteY = 0;
    private static final int SPRITE_FRAME_SPEED = 5; // frames
    private static final int SPRITE_FRAMES = 9; // index, start at 0
    private static final int NUMBER_OF_PLANKTON = 16; // bitmaps
    private static int backgroundHeight;
    private static int spriteWidth;
    private static int spriteHeight;
    
    private int topBackgroundY = 0;
	private int bottomBackgroundY = 0;
    private int nextPlankX[] = new int [NUMBER_OF_PLANKTON];
    private int mPlankX[] = new int [NUMBER_OF_PLANKTON];
    private int mPlankY[] = new int [NUMBER_OF_PLANKTON];
	private boolean planktonEaten[] = new boolean [NUMBER_OF_PLANKTON];
    private int mSpriteDx = 0;
    private int mSpriteFrameCtr = 0;
	boolean spriteDxToggle = true;
    private int prevKey, currKey = 0;
    
    public long mGameTimer;
    private long mPlankTimer[] = new long[NUMBER_OF_PLANKTON];

    public SeaAnimation() { }
    
    public void init (Context context) { 
    	mContext = context;
		mActivity = (Activity) context;
    	
        mSprite[0]  = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_manta00);
        mSprite[1]  = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_manta01);
        mSprite[2]  = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_manta02);
        mSprite[3]  = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_manta03);
        mSprite[4]  = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_manta04);
        mSprite[5]  = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_manta05);
        mSprite[6]  = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_manta06);
        mSprite[7]  = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_manta07);
        mSprite[8]  = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_manta08);
        mSprite[9]  = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_manta09);
        spriteWidth  = mSprite[0].getWidth();
        spriteHeight = mSprite[0].getHeight();

        //scale the background bitmaps to fit the screen width
        Bitmap fromRes;
        int screenWidth = (int) GameSurfaceView.mScreenWidth;
        fromRes    = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_seabed);
        mSeaBed    = Bitmap.createScaledBitmap(fromRes, screenWidth, fromRes.getHeight(), true);
        backgroundHeight = mSeaBed.getHeight();
        startAnimation();
        
        mPlankton[0]    = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_plankton00);
        mPlankton[1]    = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_plankton01);
        mPlankton[2]    = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_plankton02);
        mPlankton[3]    = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_plankton03);
        mPlankton[4]    = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_plankton04);
        mPlankton[5]    = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_plankton05);
        mPlankton[6]    = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_plankton06);
        mPlankton[7]    = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_plankton07);
        mPlankton[8]    = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_plankton08);
        mPlankton[9]    = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_plankton09);
        mPlankton[10]   = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_plankton10);
        mPlankton[11]   = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_plankton11);
        mPlankton[12]   = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_plankton12);
        mPlankton[13]   = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_plankton13);
        mPlankton[14]   = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_plankton14);
        mPlankton[15]   = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.sea_plankton15);
        
        for (int i=0;i<NUMBER_OF_PLANKTON;i++) {
            nextPlankX[i] = 0;
        	mPlankX[i] = 0;
        	mPlankY[i] = 0;
        	planktonEaten[i] = true;
        	mPlankTimer[i] = System.currentTimeMillis();
        }
    }
    
    public void startAnimation() {
    	prevKey = 0; currKey = 0;
        showKeyToast();
    }
    
	public void updatePhysics(float mSensorX[], float mSensorY[]) {
		
		int length = mSensorX.length;
		int i = 0;
		float totalSensorX = 0f;
		float totalSensorY = 0f;
		while (i < length){
			totalSensorX += mSensorX[i] * 1f;
			totalSensorY += mSensorY[i] * 1f;
			i += 1;
		}
		float averageSensorX = totalSensorX / length;
		float averageSensorY = totalSensorY / length;
		
		//infinite field: if sprite hits edge, transport to other side
		mSpriteX = mSpriteX - averageSensorX;
		if (mSpriteX >= GameSurfaceView.mScreenWidth) {
			mSpriteX = -spriteWidth;
		}
		if (mSpriteX < -spriteWidth) {
			mSpriteX = GameSurfaceView.mScreenWidth;
		}

		mSpriteY = mSpriteY - averageSensorY;
		if (mSpriteY >= GameSurfaceView.mScreenHeight) {
			mSpriteY = -spriteHeight;
		}
		if (mSpriteY < -spriteHeight) {
			mSpriteY = GameSurfaceView.mScreenHeight;
		}
	}
	
	private void checkCollision() {
		//make a small rect at the center of the sprite
		Rect spriteRect = new Rect((int) (mSpriteX + (spriteWidth  / 2) - 7),
				   				   (int) (mSpriteY + (spriteHeight / 2) - 7),
				   				   (int) (mSpriteX + (spriteWidth  / 2) + 7),
				   				   (int) (mSpriteY + (spriteHeight / 2) + 7));

		//check if it intersects one of the 16 plankton in a rectangle ~half the size of the bitmap
		for (int i=0; i<NUMBER_OF_PLANKTON;i++) {
			if (!planktonEaten[i]) {
				Rect plankRect = new Rect(mPlankX[i] + (int)(mPlankton[i].getWidth()  * 0.20),
										  mPlankY[i] + (int)(mPlankton[i].getHeight() * 0.20),
										  mPlankX[i] + (int)(mPlankton[i].getWidth()  * 0.80),
										  mPlankY[i] + (int)(mPlankton[i].getHeight() * 0.80));	
				if (Rect.intersects(spriteRect, plankRect)) {
					mPlankTimer[i] = mGameTimer;
					planktonEaten[i] = true;
					mFMODaudio.playPlanktonSound();
				}		
			}
		}
	}
	
	public void doDraw(Canvas canvas) {	
		mCanvas = canvas;
		drawBackground();
		drawPlankton();
		drawSprite();
		checkCollision();
	}
	
	private void drawBackground() {
		currKey = mFMODaudio.checkSeaKey();
		if (currKey != prevKey) {
			showKeyToast();
		}

		//scroll background up, wrapping from below with the correct background 
	    topBackgroundY -= 2;
	    bottomBackgroundY = topBackgroundY + backgroundHeight;
	    if (bottomBackgroundY <= 0) {
	    	bottomBackgroundY = backgroundHeight;
	    	topBackgroundY = 0;
	    }
        mCanvas.drawBitmap(mSeaBed, 0, topBackgroundY, null);
        mCanvas.drawBitmap(mSeaBed, 0, bottomBackgroundY, null);
	}
	
	private void showKeyToast() {
		mActivity.runOnUiThread(new Runnable() {
		    public void run() {
				CharSequence keyText;
				switch (currKey) {
				case 0: keyText = "Key of G minor"; break;
				case 1: keyText = "Key of Bb minor"; break;
				case 2: keyText = "Key of C# minor"; break;
				case 3: keyText = "Key of E minor"; break;
		    	default:keyText = "???";break;
		    	}
				Toast keyToast = Toast.makeText(mActivity, keyText, Toast.LENGTH_SHORT);
		    	keyToast.setGravity(Gravity.TOP|Gravity.LEFT, 0, 0);
		    	keyToast.show();
		    }
		});
		prevKey = currKey;
	}
	
	private void drawPlankton() {
		for (int i=0;i<NUMBER_OF_PLANKTON;i++) {
			drawAPlankton(i);
		}
	}
	
	private void drawAPlankton(int plankNumber) {
		// when a plankton gets swallowed, wait an increasing amount of time per plankton, then re-release the plankton
		if (planktonEaten[plankNumber]) {
			if (mGameTimer > mPlankTimer[plankNumber] + (PLANK_RELEASE + (plankNumber*500))) {
				planktonEaten[plankNumber] = false;
				mPlankY[plankNumber] = (int) (GameSurfaceView.mScreenHeight + mPlankton[plankNumber].getHeight());
				mPlankX[plankNumber] = mRnd.nextInt((int)GameSurfaceView.mScreenWidth);
			} else {
				return;  // don't draw a plankton
			}
		}
			        
		mPlankY[plankNumber] -= PLANKY_SPEED; //+ plankNumber; // vary the speed per plankton
		if (mPlankY[plankNumber] < -mPlankton[plankNumber].getHeight()) {
			mPlankY[plankNumber] = (int) (GameSurfaceView.mScreenHeight + mPlankton[plankNumber].getHeight());
		}
		
		// determine the X axis using a "drunkard's walk" (brownian motion) algorithm:
		// flip a coin to determine which direction to move a small random amount, then move to that point incrementally
		if (mPlankX[plankNumber] < nextPlankX[plankNumber]) {
			mPlankX[plankNumber] += PLANKX_SPEED; //+ plankNumber; // vary the speed per plankton
			if (mPlankX[plankNumber] >= nextPlankX[plankNumber]) {
				mPlankX[plankNumber] = nextPlankX[plankNumber];
			}			
		} else
		if (mPlankX[plankNumber] > nextPlankX[plankNumber]) {
			mPlankX[plankNumber] -= PLANKX_SPEED; //+ plankNumber; // vary the speed per plankton
			if (mPlankX[plankNumber] <= nextPlankX[plankNumber]) {
				mPlankX[plankNumber] = nextPlankX[plankNumber];
			}			
		} else
		if (mPlankX[plankNumber] == nextPlankX[plankNumber]) {
    		int flipCoin = mRnd.nextInt(2);
    		if (flipCoin == 0) {
    			nextPlankX[plankNumber] += mRnd.nextInt(DRUNKARDS_WALK_AMT);
    		} else {
    			nextPlankX[plankNumber] -= mRnd.nextInt(DRUNKARDS_WALK_AMT);
    		}    		
    		// bounce off screen edges
    		if (nextPlankX[plankNumber] > GameSurfaceView.mScreenWidth - mPlankton[plankNumber].getWidth()) {
    			nextPlankX[plankNumber] -= DRUNKARDS_WALK_AMT;
    		} else if (nextPlankX[plankNumber] < 0) {
    			nextPlankX[plankNumber] += DRUNKARDS_WALK_AMT;
    		}
		}
        mCanvas.drawBitmap(mPlankton[plankNumber], mPlankX[plankNumber], mPlankY[plankNumber], null);
	}

	private void drawSprite() {
		if (mSpriteFrameCtr > SPRITE_FRAME_SPEED) {
			mSpriteFrameCtr = 0;
			switch (mSpriteDx) {
			case (0):
				spriteDxToggle = true; //increment
				break;
			case (SPRITE_FRAMES):
				spriteDxToggle = false; //decrement
				break;
			}
			
			if (spriteDxToggle) {
				mSpriteDx++;
			} else {
				mSpriteDx--;
			}
		} else {
			mSpriteFrameCtr++;
		}
        mCanvas.drawBitmap(mSprite[mSpriteDx], mSpriteX, mSpriteY, null);
	}
	
	public void cleanSea() {
		int i;
		mSeaBed.recycle(); mSeaBed = null;
		for (i=0;i<10;i++){
			mSprite[i].recycle(); mSprite[i] = null;
		}
		for (i=0;i<NUMBER_OF_PLANKTON;i++) {
			mPlankton[i].recycle(); mPlankton[i] = null;
		}
		System.gc();
	}

}
