/**
 * @author Twenty Codes
 * @author ricky barrette
 */
package com.TwentyCodes.android.SweetDreamsLib;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;

/**
 * this class is responsible for setting up the ui and handling ui events
 * @author ricky
 */
public class SweetDreamsFull extends Activity implements OnClickListener, OnSeekBarChangeListener{
	
	private boolean isPlaying;
	private ImageButton mPlayPauseButton;
	private AudioManager mAudioManager;
	private final int STREAM = AudioManager.STREAM_MUSIC;
	protected static MediaPlayer mMediaPlayer;
	private PostMortemReportExceptionHandler mDamageReport;
	private final int SETTINGS = Menu.FIRST;
	private final int QUIT = Menu.FIRST +1;
	private SharedPreferences mSettings;
	protected static final String TAG = "WhiteNoise";
	private Timer mTimer;
	protected static TextView mTimeLeftTextView;
	protected static boolean isFUll = true;
	
    /**
	 * adjusts the provided Stream volume to the provided level
	 * @param stream
	 * @param level
	 * @author ricky barrette
	 */
	private void adjustVolume(int stream, int level) {
			
		/*
		 * if the seek bar is set to a value that is higher than what the the stream value is set for
		 * then subtract the seek bar's value from the current volume of the stream, and then
		 * raise the stream by that many times 
		 */
		if (level > mAudioManager.getStreamVolume(stream)) {
			int adjust = level - mAudioManager.getStreamVolume(stream);
			for (int i = 0; i < adjust; i++) {
				mAudioManager.adjustSuggestedStreamVolume(AudioManager.ADJUST_RAISE, stream, AudioManager.FLAG_VIBRATE);
			}
		}
		
		/*
		 * if the seek bar is set to a value that is lower than what the the stream value is set for
		 * then subtract the current volume of the stream from the seek bar's value, and then
		 * lower the stream by that many times 
		 */
		if (level < mAudioManager.getStreamVolume(stream)) {
			int adjust = mAudioManager.getStreamVolume(stream) - level;
			for (int i = 0; i < adjust; i++) {
				mAudioManager.adjustSuggestedStreamVolume(AudioManager.ADJUST_LOWER, stream, AudioManager.FLAG_VIBRATE);
			}
		}	
	}
    
    /**
     * loads the sound from shared_prefs that the user wants, and set the mediaplayer to loop
     * loads river sound track by default.
     * 
     * @author ricky barrette
     */
    private void loadSound(){
    	Log.i(TAG,"loadSound()");
    	try {
			mMediaPlayer.reset();
		} catch (Exception e) {
			e.printStackTrace();
		}
    	String sound = mSettings.getString("sounds", Settings.SOUND_RIVER);
    	Log.v(TAG,"sound = "+ sound);
    	if (sound != null){
			if (sound.equals(Settings.SOUND_BEACH)){
				mMediaPlayer = MediaPlayer.create(this, R.raw.beach);
				mMediaPlayer.setLooping(true);
			}
			if (sound.equals(Settings.SOUND_AC)){
				mMediaPlayer = MediaPlayer.create(this, R.raw.ac);
				mMediaPlayer.setLooping(true);
			}
			if (sound.equals(Settings.SOUND_CRICKETS)){
				mMediaPlayer = MediaPlayer.create(this, R.raw.crickets);
				mMediaPlayer.setLooping(true);
			}
			if (sound.equals(Settings.SOUND_FALLS)){
				mMediaPlayer = MediaPlayer.create(this, R.raw.falls);
				mMediaPlayer.setLooping(true);
			}
			if (sound.equals(Settings.SOUND_RIVER)){
				mMediaPlayer = MediaPlayer.create(this, R.raw.river);
				mMediaPlayer.setLooping(true);
			}
    	}
    }
    
    /** 
     * called when the user clicks on a view that has been registered with this onClickListener
     * @author ricky barrette
     */
	@Override
	public void onClick(View v) {
		/*
		 * if the sound track is no playing then
		 * change the button background from a play symbol to a pause symbol, set isPlaying to true, load the user preferred sound track, and play it
		 * else
		 * change the button background from a pause symbol to a play symbol, set isPlaying to false, and stop playing the sound track
		 */
		if (!isPlaying){
			mPlayPauseButton.setBackgroundDrawable(getResources().getDrawable(R.drawable.pause_button));
			isPlaying = true;
			loadSound();
			mMediaPlayer.start();
			if (mSettings.getBoolean(Settings.TIMER_ENABLED, false)){
				Log.v(TAG,"Starting timer");
				long time = + (mSettings.getInt("timer_length", 30) * 60000);
				Log.v(TAG,"time = " + time);
				mTimer  = new Timer(time);
				mTimer.start();
			}
		} else {
			stopPlaying();
		}
	}
	
	/**
	 * called when the activity is first created
	 * (non-Javadoc)
	 * @see android.app.Activity#onCreate(android.os.Bundle)
	 * @param savedInstanceState
	 * @author ricky barrette
	 */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(R.layout.main);
        Log.i(TAG,"onCreate()");
        
        // setup crash report handler
        mDamageReport = new PostMortemReportExceptionHandler(this);
    	mDamageReport.run();
        Thread.setDefaultUncaughtExceptionHandler(mDamageReport);
        
        //initialize the play_pause button and set onClickListener
        mPlayPauseButton = (ImageButton) findViewById(R.id.play_pause_button);
        mPlayPauseButton.setOnClickListener(this);
        
        //initialize audio manager so we can control stream volumes
        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        
        //initialize the volume seekbar and set 
        SeekBar sbVolume = (SeekBar) findViewById(R.id.volume);
        sbVolume.setOnSeekBarChangeListener(this);
        sbVolume.setMax(mAudioManager.getStreamMaxVolume(STREAM));
		sbVolume.setProgress(mAudioManager.getStreamVolume(STREAM));
		
		//load shared_prefs
		mSettings = getSharedPreferences(Settings.SETTINGS, 0);
		
		loadSound();
		
		saveStreamVolume(STREAM);
    }

    /**
	 * creates a menu
	 * @author ricky barrette 3-30-2010
	 */
	@Override
	public boolean onCreateOptionsMenu (Menu menu) {
		menu.add(1, SETTINGS, 0, "Options");
		menu.add(1, QUIT, 0, "Quit");
		return true;
	}

	/**
	 * here we set the Stream volume back to what ever it was when the activity started
	 * (non-Javadoc)
	 * @see android.app.Activity#onDestroy()
	 * @author ricky barrette
	 */
	@Override
	public void onDestroy(){
		adjustVolume(STREAM,mSettings.getInt(Settings.MUSIC_VOLUME, 0));
		super.onDestroy();
	}

	/**
	 * handles menu selection 
	 * @author ricky barrette 3-30-2010
	 */
	@Override
	public boolean onOptionsItemSelected (MenuItem item) {	
		switch (item.getItemId()){
			case SETTINGS:
				Intent intent = new Intent().setClass(this, Settings.class);
	            startActivity(intent);
				stopPlaying(); 
				return true;
				
			case QUIT:
				stopPlaying();
				finish();
				return true;
		}
		return false;
	}

	@Override
	public void onPause(){
		super.onPause();
	}

	/** 
	 * called when the seekbar progress is changed
	 * @param seekbar that was changed
	 * @param progress of the seekbar
	 * @param fromUser 
	 */
	@Override
	public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
		/*
		 * if the change was cause by the user then
		 * set the output stream the the desired level
		 */
		if(fromUser){
			adjustVolume(STREAM, progress);
		}
	}
	
	@Override
	public void onRestart(){
		super.onRestart();
	}
	
	/**
	 * we load the track title textview in onResume so it will update every time the activity loads
	 * (non-Javadoc)
	 * @see android.app.Activity#onResume()
	 * @author ricky barrette
	 */
	@Override
	public void onResume(){
		super.onResume();
		TextView trackTitle = (TextView) findViewById(R.id.track_title);
		trackTitle.setText(mSettings.getString(Settings.SOUNDS,"Rainy River"));
	}
	
	@Override
	public void onStart(){
		super.onStart();
	}
	
	@Override
	public void onStartTrackingTouch(SeekBar seekBar) {
		/*
		 * NOT YET IMPLEMENTED
		 * needed for OnSeekBarChangeListener
		 */
	}
	
	/**
	 * we stop the music from playing and release the media player
	 * (non-Javadoc)
	 * @see android.app.Activity#onStop()
	 * @author ricky barrette
	 */
	@Override
	public void onStop(){
		stopPlaying();
		try {
			mMediaPlayer.release();
		} catch (Exception e) {
			e.printStackTrace();
		}
		super.onStop();
	}

	@Override
	public void onStopTrackingTouch(SeekBar seekBar) {
		/*
		 * NOT YET IMPLEMENTED
		 * needed for OnSeekBarChangeListener
		 */	
	}
	
	/**
	 * saves the current volume levels for the supplied audio stream
	 * @param stream to be saved
	 * @return true id save was successful
	 * @author ricky barrette
	 */
	private boolean saveStreamVolume(int stream){
		Editor edit = mSettings.edit();
		edit.putInt(Settings.MUSIC_VOLUME, mAudioManager.getStreamVolume(stream));
		return edit.commit();
	}
	
	/**
	 * stops music from playing, sets the pay_pause button background to a play symbol, and if the time is enabled, cancels the timer
	 * 
	 * @author ricky barrette
	 */
	private void stopPlaying(){
		mPlayPauseButton.setBackgroundDrawable(getResources().getDrawable(R.drawable.play_button));
		isPlaying = false;
		try {
			mMediaPlayer.stop();
		} catch (IllegalStateException e) {
			e.printStackTrace();
			Log.e(TAG,"failed to stop media player");
		}
		if (mTimer != null) {
			mTimer.cancel();
			mTimer = null;
			mTimeLeftTextView.setText("");
		}
	}
	
	/**
	 * this internal class will handle timing functions such as a timer that stops play back of a sound track & updates timeLeft textview every second
	 * @author ricky barrette
	 */
	class Timer extends CountDownTimer {
		
		/**
		 * creates a new count down timer that stops play back of a sound track after specified time, and
		 * updates timeLeft textview every second
		 * @param millisInFuture
		 */
		public Timer(long millisInFuture) {
			super(millisInFuture, 1000l);
			Log.i(TAG,"Timer()");
			Log.v(TAG,"millisInFuture = "+ millisInFuture);
			mTimeLeftTextView = (TextView) findViewById(R.id.time_left);
			int hours = (int) (millisInFuture / 3600000);
			millisInFuture = millisInFuture - (hours * 3600000);
			int minutes = (int) ( millisInFuture / 60000);
			int seconds = (int) (millisInFuture % 60000);
			seconds = seconds / 1000;
			mTimeLeftTextView.setText(hours +" : "+ padTime(minutes) +" : "+ padTime(seconds));
		}

		/**
		 * stops the sound track being played by the media player
		 * (non-Javadoc)
		 * @see android.os.CountDownTimer#onFinish()
		 * @author ricky barrette
		 */
		@Override
		public void onFinish() {
			Log.i(TAG,"onFinish()");
			mTimeLeftTextView.setText("");
			stopPlaying();
			//if the user enables exit on finish, then kill the application
			if(mSettings.getBoolean(Settings.TIMER_EXIT_ON_FINISH, false)){
				Log.v(TAG,"exit on finish enabled, calling finish()");
				finish();
			}
		}

		/**
		 * updates the timeLeft textView to display the current time left till sound stops
		 * @see android.os.CountDownTimer#onTick(long)
		 * @param millisUntilFinished
		 * @author ricky barrette
		 */
		@Override
		public void onTick(long millisUntilFinished) {
			Log.i(TAG,"onTick()");
			int hours = (int) (millisUntilFinished / 3600000);
			millisUntilFinished = millisUntilFinished - (hours * 3600000);
			int minutes = (int) ( millisUntilFinished / 60000);
			int seconds = (int) (millisUntilFinished % 60000);
			seconds = seconds / 1000;
			mTimeLeftTextView.setText(hours +" : "+ padTime(minutes) +" : "+ padTime(seconds));
		}
		
		/**
		 * convince method for formating the seconds string
		 * @param seconds
		 * @return formated string
		 * @author ricky barrette
		 */
		private String padTime(int seconds){
			if (seconds <= 9)
				return "0"+ seconds;
			return ""+ seconds;
		}
		
	}
}