package com.lloydm.geosword.common;

import java.io.File;
import java.io.IOException;
import java.util.Random;

import android.annotation.SuppressLint;
import android.app.Service;
import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

@SuppressLint("HandlerLeak")
public class MenuMusicService extends Service
{
     private static MediaPlayer menumediaplayer;

     public volatile static boolean audiomuted = false;

     private static volatile boolean threadrunning = false;
     private volatile int cmd = -1;
     private static Handler handler;

     private final float volume = (float) (1 - (Math.log(80) / Math.log(100)));

     private final static int CMD_PLAY = 0;
     private final static int CMD_PAUSE = 1;
     private final static int CMD_FADEOUT = 2;
     private final static int CMD_FADEIN = 3;
     private final static int CMD_FINISH = 4;
     private final static int CMD_START = 5;

     // volume on/off
     private final static int CMD_MUTEON = 6;
     private final static int CMD_MUTEOFF = 7;

     private volatile boolean usecustommusic = false;
     private String custommusicfilename = "";

     private final static String TAG = "com.lloydm.geosword.common.MenuMusicService";

     private static AssetManager assetmgr = null;

     @Override
     public void onCreate()
     {

     }

     @Override
     public IBinder onBind(Intent intent)
     {

                     return null;
     }

     @Override
     public int onStartCommand(Intent intent, int flags, int startId)
     {
                     if (intent == null)
                     {
                                     return START_STICKY;
                     }
                     String action = intent.getAction();
                     if (action != null)
                     {
                                     if (action.equals("com.lloydm.geosword.common.MenuMusicService.start"))
                                     {
                                                     cmd = CMD_START;
                                                     // init, load and begin playback....
                                                     if (!threadrunning)
                                                     {
                                                                     threadrunning = true;
                                                                     new Thread(new Runnable()
                                                                     {

                                                                                     @Override
                                                                                     public void run()
                                                                                     {

                                                                                                     initmusic();
                                                                                                     Looper.prepare();
                                                                                                     handler = new Handler()
                                                                                                     {
                                                                                                                     public void handleMessage(Message msg)
                                                                                                                     {
                                                                                                                                     switch (msg.what)
                                                                                                                                     {
                                                                                                                                     case CMD_MUTEON:
                                                                                                                                                     if (menumediaplayer != null)
                                                                                                                                                     {
                                                                                                                                                                     try
                                                                                                                                                                     {
                                                                                                                                                                                     Log.i(TAG, "muting audio");

                                                                                                                                                                                     audiomuted = true;
                                                                                                                                                                                     menumediaplayer.setVolume(0, 0);
                                                                                                                                                                                     Log.i(TAG, "audio muted");
                                                                                                                                                                     }
                                                                                                                                                                     catch (Exception e)
                                                                                                                                                                     {
                                                                                                                                                                                     Log.e(TAG, "music player in wrong state");
                                                                                                                                                                     }
                                                                                                                                                     }
                                                                                                                                                     else
                                                                                                                                                     {
                                                                                                                                                                     Log.w(TAG, "Music player should be available but isn't");
                                                                                                                                                     }
                                                                                                                                                     break;
                                                                                                                                     case CMD_MUTEOFF:
                                                                                                                                                     if (menumediaplayer != null)
                                                                                                                                                     {
                                                                                                                                                                     try
                                                                                                                                                                     {
                                                                                                                                                                                     Log.i(TAG, "unmuting audio");
                                                                                                                                                                                     audiomuted = false;
                                                                                                                                                                                     menumediaplayer.setVolume(volume, volume);
                                                                                                                                                                                     Log.i(TAG, "audio unmuted");
                                                                                                                                                                     }
                                                                                                                                                                     catch (Exception e)
                                                                                                                                                                     {
                                                                                                                                                                                     Log.e(TAG, "music player in wrong state");
                                                                                                                                                                     }
                                                                                                                                                     }
                                                                                                                                                     else
                                                                                                                                                     {
                                                                                                                                                                     Log.w(TAG, "Music player should be available but isn't");
                                                                                                                                                     }

                                                                                                                                                     break;
                                                                                                                                     case CMD_PLAY:
                                                                                                                                                     handler.removeCallbacksAndMessages(null);
                                                                                                                                                     if (menumediaplayer != null)
                                                                                                                                                     {
                                                                                                                                                                     try
                                                                                                                                                                     {
                                                                                                                                                                                     if (!menumediaplayer.isPlaying())
                                                                                                                                                                                     {
                                                                                                                                                                                                     menumediaplayer.start();
                                                                                                                                                                                                     if (!audiomuted)
                                                                                                                                                                                                     {
                                                                                                                                                                                                                     menumediaplayer.setVolume(volume, volume);
                                                                                                                                                                                                     }
                                                                                                                                                                                                     else
                                                                                                                                                                                                     {
                                                                                                                                                                                                                     menumediaplayer.setVolume(0, 0);
                                                                                                                                                                                                     }
                                                                                                                                                                                     }
                                                                                                                                                                     }
                                                                                                                                                                     catch (Exception e)
                                                                                                                                                                     {
                                                                                                                                                                                     Log.e(TAG, "music player in wrong state");
                                                                                                                                                                     }
                                                                                                                                                     }
                                                                                                                                                     else
                                                                                                                                                     {
                                                                                                                                                                     Log.w(TAG, "Music player should be available but isn't");
                                                                                                                                                     }
                                                                                                                                                     break;

                                                                                                                                     case CMD_PAUSE:
                                                                                                                                                     handler.removeCallbacksAndMessages(null);
                                                                                                                                                     if (menumediaplayer != null)
                                                                                                                                                     {
                                                                                                                                                                     try
                                                                                                                                                                     {
                                                                                                                                                                                     if (menumediaplayer.isPlaying())
                                                                                                                                                                                     {
                                                                                                                                                                                                     menumediaplayer.pause();
                                                                                                                                                                                     }
                                                                                                                                                                     }
                                                                                                                                                                     catch (Exception e)
                                                                                                                                                                     {
                                                                                                                                                                                     Log.e(TAG, "music player in wrong state");
                                                                                                                                                                     }
                                                                                                                                                     }
                                                                                                                                                     else
                                                                                                                                                     {
                                                                                                                                                                     Log.w(TAG, "Music player should be available but isn't");
                                                                                                                                                     }

                                                                                                                                                     break;

                                                                                                                                     case CMD_FINISH:
                                                                                                                                                     finishmusic();
                                                                                                                                                     handler.removeCallbacksAndMessages(null);
                                                                                                                                                     handler.getLooper().quit();
                                                                                                                                                     threadrunning = false;
                                                                                                                                                     stopSelf(); // important!
                                                                                                                                                     break;

                                                                                                                                     default: // currently fade in and fade out will come here - not used yet...
                                                                                                                                                     handler.removeCallbacksAndMessages(null);
                                                                                                                                                     break;
                                                                                                                                     }
                                                                                                                     }
                                                                                                     };

                                                                                                     Looper.loop();
                                                                                                     Message msg = new Message();
                                                                                                     msg.what = cmd;
                                                                                                     if (handler != null)
                                                                                                     {
                                                                                                                     handler.sendMessage(msg);
                                                                                                     }
                                                                                     }
                                                                     }).start();
                                                     }
                                                     else
                                                     {
                                                                     // cancel the CMD_FINISH if it is there.....ie get in early! - assumes there was a 'resume' command
                                                                     // which was to start the process again between activity onpause/onresumes...
                                                                     // we should probably try and run a 'play' command....regardless...just in case...
                                                                     if (handler != null)
                                                                     {
                                                                                     try
                                                                                     {
                                                                                                     handler.removeMessages(CMD_FINISH);
                                                                                     }
                                                                                     catch (Exception e)
                                                                                     {
                                                                                                     Log.e(TAG, "Error - failed to cancel finish command");
                                                                                     }
                                                                                     try
                                                                                     {
                                                                                                     Message msg2 = new Message();
                                                                                                     msg2.what = CMD_PLAY;
                                                                                                     handler.sendMessage(msg2);
                                                                                     }
                                                                                     catch (Exception e)
                                                                                     {
                                                                                                     Log.e(TAG, "Error - failed to play music 123");
                                                                                     }
                                                                     }
                                                     }
                                     }
                                     if (action.equals("com.lloydm.geosword.common.MenuMusicService.muteon"))
                                     {
                                                     try
                                                     {
                                                                     cmd = CMD_MUTEON;
                                                                     Message msg = new Message();
                                                                     msg.what = cmd;
                                                                     if (handler != null)
                                                                     {
                                                                                     handler.sendMessage(msg);
                                                                     }
                                                     }
                                                     catch (Exception e)
                                                     {
                                                                     Log.w(TAG, "handler problem when muting");
                                                     }
                                     }
                                     if (action.equals("com.lloydm.geosword.common.MenuMusicService.muteoff"))
                                     {
                                                     try
                                                     {
                                                                     cmd = CMD_MUTEOFF;
                                                                     Message msg = new Message();
                                                                     msg.what = cmd;
                                                                     if (handler != null)
                                                                     {
                                                                                     handler.sendMessage(msg);
                                                                     }
                                                     }
                                                     catch (Exception e)
                                                     {
                                                                     Log.w(TAG, "handler problem when unmuting");
                                                     }
                                     }
                                     if (action.equals("com.lloydm.geosword.common.MenuMusicService.play"))
                                     {
                                                     cmd = CMD_PLAY; // resume basically...
                                                     Message msg = new Message();
                                                     msg.what = cmd;
                                                     if (handler != null)
                                                     {
                                                                     handler.sendMessage(msg);
                                                     }
                                     }
                                     if (action.equals("com.lloydm.geosword.common.MenuMusicService.pause"))
                                     {
                                                     cmd = CMD_PAUSE;
                                                     // if the music is playing then pause it.....(temporarily)
                                                     Message msg = new Message();
                                                     msg.what = cmd;
                                                     if (handler != null)
                                                     {
                                                                     handler.sendMessage(msg);
                                                     }
                                     }
                                     if (action.equals("com.lloydm.geosword.common.MenuMusicService.fadeout"))
                                     {
                                                     cmd = CMD_FADEOUT;
                                                     // fade out to 0.1 volume...
                                                     Message msg = new Message();
                                                     msg.what = cmd;
                                                     if (handler != null)
                                                     {
                                                                     handler.sendMessage(msg);
                                                     }
                                     }
                                     if (action.equals("com.lloydm.geosword.common.MenuMusicService.fadein"))
                                     {
                                                     cmd = CMD_FADEIN;
                                                     // fade in to maxvolume (0.4f?)
                                                     Message msg = new Message();
                                                     msg.what = cmd;
                                                     if (handler != null)
                                                     {
                                                                     handler.sendMessage(msg);
                                                     }
                                     }
                                     if (action.equals("com.lloydm.geosword.common.MenuMusicService.finish"))
                                     {
                                                     cmd = CMD_FINISH;
                                                     // release all resources and stop playing etc...kill the looper etc...
                                                     Message msg = new Message();
                                                     msg.what = cmd;
                                                     if (handler != null)
                                                     {
                                                                     handler.sendMessageDelayed(msg, 2750);
                                                     }

                                     }
                                     if (action.equals("com.lloydm.geosword.common.MenuMusicService.instantkill"))
                                     {
                                                     cmd = CMD_FINISH;
                                                     // release all resources and stop playing etc...kill the looper etc...
                                                     Message msg = new Message();
                                                     msg.what = cmd;
                                                     if (handler != null)
                                                     {
                                                                     handler.sendMessageDelayed(msg, 1000); // almost instant...not quite!
                                                     }

                                     }

                     }
                     return START_STICKY;
     }

     private static void finishmusic()
     {
                     if (menumediaplayer != null)
                     {
                                     Log.i(TAG, "ending any music");
                                     try
                                     {
                                                     if (menumediaplayer.isPlaying())
                                                     {
                                                                     menumediaplayer.stop();
                                                     }
                                     }
                                     catch (Exception e)
                                     {
                                                     Log.e(TAG, "Music player not in right state");
                                     }
                                     Log.i(TAG, "Releasing music player");
                                     menumediaplayer.release();
                                     menumediaplayer = null;
                     }

     }

     private void initmusic()
     {
                     // get default system volume for app.....
                     if (menumediaplayer != null)
                     {
                                     Log.i(TAG, "Releasing music player");
                                     menumediaplayer.release();
                                     menumediaplayer = null;
                     }
                     Log.i(TAG, "new media player");
                     menumediaplayer = new MediaPlayer();
                     menumediaplayer.reset();
                     Log.i(TAG, "setting stream type and volume music player");
                     menumediaplayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
                     if (!audiomuted)
                     {
                                     menumediaplayer.setVolume(volume, volume);
                     }
                     {
                                     menumediaplayer.setVolume(0, 0);
                     }
                     menumediaplayer.setOnErrorListener(new MediaPlayer.OnErrorListener()
                     {
                                     @Override
                                     public boolean onError(MediaPlayer mp, int what, int extra)
                                     {
                                                     Log.e(TAG, "Error with media player:what:" + what + " extra:" + extra);

                                                     return true;
                                     }
                     });

                     // determine whether to use the standard music or the user's music....based on the presence of files...and set the appropriate file...
                     checkcustommusic();

                     loadaudiotrack();
     }

     private void checkcustommusic()
     {
                     usecustommusic = false;
                     try
                     {
                                     File folder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC) + "/" + com.lloydm.geosword.common.Config.MENUMUSICFOLDER);
                                     try
                                     {
                                                     folder.mkdirs();
                                     }
                                     catch (Exception ff)
                                     {
                                                     Log.w(TAG, "error mkdir");
                                     }
                                     if (folder.isDirectory() && folder.canRead())
                                     {
                                                     Log.d(TAG, "custom folder exists");
                                                     File[] flist = folder.listFiles();
                                                     if (flist != null)
                                                     {
                                                                     Log.d(TAG, "files in folder");
                                                                     int ss = flist.length;
                                                                     int mcount = 0;
                                                                     for (int i = 0; i < ss; i++)
                                                                     {
                                                                                     Log.d(TAG, "looping files");
                                                                                     File f = flist[i];
                                                                                     if (f.isFile() && f.canRead())
                                                                                     {
                                                                                                     Log.d(TAG, "file is a file");
                                                                                                     // check if it is a valid audio file.....
                                                                                                     // mp3, ogg, m4a will do.....
                                                                                                     if (f.getAbsolutePath().endsWith("mp3") || f.getAbsolutePath().endsWith("ogg") || f.getAbsolutePath().endsWith("m4a"))
                                                                                                     {
                                                                                                                     Log.d(TAG, "file is audio");
                                                                                                                     mcount++;
                                                                                                     }
                                                                                     }
                                                                     }
                                                                     if (mcount > 0)
                                                                     {
                                                                                     Log.d(TAG, "mcount more than zero");
                                                                                     // pick a random number.....between 0 and mcount-1
                                                                                     Random mrand = new Random();
                                                                                     int mindex = 1 + (mrand.nextInt(mcount));
                                                                                     for (int i = 0; i < ss; i++)
                                                                                     {
                                                                                                     Log.d(TAG, "counting again");
                                                                                                     File f = flist[i];
                                                                                                     if (f.isFile() && f.canRead())
                                                                                                     {
                                                                                                                     Log.d(TAG, "is a file again");
                                                                                                                     // check if it is a valid audio file.....
                                                                                                                     // mp3, ogg, m4a will do.....
                                                                                                                     if (f.getAbsolutePath().endsWith("mp3") || f.getAbsolutePath().endsWith("ogg") || f.getAbsolutePath().endsWith("m4a"))
                                                                                                                     {
                                                                                                                                     Log.d(TAG, "is audio files");
                                                                                                                                     mindex--;
                                                                                                                                     if (mindex == 0)
                                                                                                                                     {
                                                                                                                                                     custommusicfilename = f.getAbsolutePath();
                                                                                                                                                     usecustommusic = true;
                                                                                                                                                     break;
                                                                                                                                     }
                                                                                                                     }
                                                                                                     }
                                                                                     }

                                                                     }
                                                     }
                                     }

                     }
                     catch (Exception e)
                     {
                                     Log.e(TAG, "error checking custom music");
                     }

     }

     private void loadaudiotrack()
     {
                     if (menumediaplayer != null)
                     {
                                     // pick a track at random.....
                                     AssetFileDescriptor fd = null;
                                     if (usecustommusic)
                                     {

                                     }
                                     else
                                     {
                                                     try
                                                     {
                                                                     if (assetmgr == null)
                                                                     {
                                                                                     assetmgr = getAssets();
                                                                     }
                                                                     fd = assetmgr.openFd("music/menutheme1.ogg");
                                                     }
                                                     catch (IOException e)
                                                     {
                                                                     // TODO Auto-generated catch block
                                                                     e.printStackTrace();
                                                     }
                                     }

                                     if (fd != null || usecustommusic == true)
                                     {
                                                     try
                                                     {
                                                                     Log.i(TAG, "setting data source for music");
                                                                     if (fd != null)
                                                                     {
                                                                                     menumediaplayer.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
                                                                                     fd.close();
                                                                     }
                                                                     else
                                                                     {
                                                                                     menumediaplayer.setDataSource(custommusicfilename);
                                                                     }
                                                                     menumediaplayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener()
                                                                     {
                                                                                     @Override
                                                                                     public void onPrepared(MediaPlayer mp)
                                                                                     {
                                                                                                     // then start playing!
                                                                                                     if (menumediaplayer != null)
                                                                                                     {
                                                                                                                     if (menumediaplayer != mp)
                                                                                                                     {
                                                                                                                                     return;
                                                                                                                     }
                                                                                                     }
                                                                                                     mp.start();
                                                                                                     if (!audiomuted)
                                                                                                     {
                                                                                                                     mp.setVolume(volume, volume);
                                                                                                     }
                                                                                                     else
                                                                                                     {
                                                                                                                     mp.setVolume(0, 0);
                                                                                                     }
                                                                                     }
                                                                     })
;
                                                                     menumediaplayer.setLooping(true);

                                                                     // set the volume...or mute it altogether.....
                                                                     menumediaplayer.prepareAsync();

                                                     }
                                                     catch (IllegalArgumentException e1)
                                                     {
                                                                     // TODO Auto-generated catch block
                                                                     e1.printStackTrace();
                                                                     Log.e(TAG, "Error opening music file - illegala rgument");
                                                     }
                                                     catch (IllegalStateException e1)
                                                     {
                                                                     // TODO Auto-generated catch block
                                                                     Log.e(TAG, "Error opening music file- illegal state");
                                                                     e1.printStackTrace();
                                                     }
                                                     catch (IOException e1)
                                                     {
                                                                     // TODO Auto-generated catch block
                                                                     Log.e(TAG, "Error opening music file - io exception");
                                                                     e1.printStackTrace();
                                                     }
                                                     try
                                                     {
                                                                     if (fd != null)
                                                                     {
                                                                                     fd.close();
                                                                     }
                                                     }
                                                     catch (IOException e)
                                                     {
                                                                     Log.i(TAG, "Error closing audio file - potentially already closed");
                                                     }
                                     }

                     }
     }

}