package com.homescreenarcade.pinball;

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

import android.content.Context;
import android.content.res.AssetManager;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.SoundPool;
import android.util.Log;

import com.homescreenarcade.R;

public class VPSoundpool {

    private static SoundPool mSoundPool;
    private static HashMap<Integer, Integer> mSoundPoolMap;
    private static AudioManager  mAudioManager;
    private static Context mContext;
    private static Random mRandom = new Random();

    private static boolean soundEnabled = true;
    private static boolean musicEnabled = true;
    private static int cScore = 0;
    private static int prevDing, currentDing = 0;
    private static int andrModAmt = 10;
//    private static MediaPlayer drumbass;
//    private static MediaPlayer androidpad;
    //private final static float SEMITONE = 1.059463094f;

    private static volatile boolean soundsLoaded = false;

    static int ID_DING_START 	= 0;
    static int NUM_DINGS 		= 6;

    static int ID_LAUNCH 		= 100;
    static int ID_FLIPPER 		= 101;
    static int ID_MESSAGE 		= 102;
    static int ID_START 		= 103;

    static int ID_ROLLOVER 		= 200;

    static int ID_ANDROIDPAD 	= 300;
    static int ID_DRUMBASSLOOP 	= 301;

    private static final String LOG_TAG = "VPSoundPool";

    public static void initSounds(Context theContext) {
        Log.v(LOG_TAG, "initSounds");
        mContext = theContext;
        mSoundPool = new SoundPool(32, AudioManager.STREAM_RING, 0);
        mSoundPoolMap = new HashMap<Integer, Integer>();
        mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
    }

    // On some devices running Lollipop (seen on Nexus 5 and emulator), SoundPool slows down
    // significantly after loading ~6 sounds, taking several seconds for each additional call to
    // load(). To avoid blocking the main thread (and delaying the app launch), this method is
    // called in an AsyncTask from the main activity.
    // See https://code.google.com/p/android-developer-preview/issues/detail?id=1812
    public static void loadSounds() {
        Log.v(LOG_TAG, "loadSounds start");
        soundsLoaded = false;
        mSoundPoolMap.clear();
        AssetManager assets = mContext.getAssets();
        try {
            mSoundPoolMap.put(ID_DING_START+0, mSoundPool.load(assets.openFd("audio/bumper/dinga1.ogg"), 1));
            mSoundPoolMap.put(ID_DING_START+1, mSoundPool.load(assets.openFd("audio/bumper/dingc1.ogg"), 1));
            mSoundPoolMap.put(ID_DING_START+2, mSoundPool.load(assets.openFd("audio/bumper/dingc2.ogg"), 1));
            mSoundPoolMap.put(ID_DING_START+3, mSoundPool.load(assets.openFd("audio/bumper/dingd1.ogg"), 1));
            mSoundPoolMap.put(ID_DING_START+4, mSoundPool.load(assets.openFd("audio/bumper/dinge1.ogg"), 1));
            mSoundPoolMap.put(ID_DING_START+5, mSoundPool.load(assets.openFd("audio/bumper/dingg1.ogg"), 1));

            mSoundPoolMap.put(ID_LAUNCH, mSoundPool.load(assets.openFd("audio/misc/andBounce2.ogg"), 1));
            mSoundPoolMap.put(ID_FLIPPER, mSoundPool.load(assets.openFd("audio/misc/flipper1.ogg"), 1));
            mSoundPoolMap.put(ID_MESSAGE, mSoundPool.load(assets.openFd("audio/misc/message2.ogg"), 1));
            mSoundPoolMap.put(ID_START, mSoundPool.load(assets.openFd("audio/misc/startup1.ogg"), 1));
            mSoundPoolMap.put(ID_ROLLOVER, mSoundPool.load(assets.openFd("audio/misc/rolloverE.ogg"), 1));

//            drumbass = MediaPlayer.create(mContext, R.raw.drumbassloop);
//            androidpad = MediaPlayer.create(mContext, R.raw.androidpad);

            soundsLoaded = true;
            resetMusicState();
            Log.v(LOG_TAG, "loadSounds finished");
        }
        catch(IOException ex) {
            Log.e(LOG_TAG, "Error loading sounds", ex);
        }
    }

    public static void setSoundEnabled(boolean enabled) {
        soundEnabled = enabled;
    }

    public static void setMusicEnabled(boolean enabled) {
        musicEnabled = enabled;
        if (!musicEnabled) {
            resetMusicState();
        }
    }

    public static void resetMusicState() {
        if (!soundsLoaded) return;

        pauseMusic();
        cScore = 0;
        andrModAmt = 10;
//        if (drumbass!=null) drumbass.seekTo(0);
//        if (androidpad!=null) androidpad.seekTo(0);
    }

    static void playSound(int soundKey, float volume, float pitch) {
        if (!soundsLoaded) return;

        if (soundEnabled && mSoundPoolMap!=null) {
            Integer soundID = mSoundPoolMap.get(soundKey);
            if (soundID!=null) {
                mSoundPool.play(soundID, volume, volume, 1, 0, pitch);
            }
        }
    }

    public static void playScore() {
        if (!soundsLoaded) return;

        //prevent repeated dings
        while (currentDing == prevDing) {
            currentDing = mRandom.nextInt(NUM_DINGS);
        }
        playSound(ID_DING_START + currentDing, 0.5f, 1);
        prevDing = currentDing;
/*
        //start playing the drumbassloop after 20 scoring hits
        cScore++;
        if (musicEnabled && cScore%20 == 0 && drumbass!=null && !drumbass.isPlaying()){
            drumbass.setVolume(1.0f, 1.0f);
            drumbass.start();
        }
        //play the androidpad after 10 scoring hits the first time
        //then increase the mod amount each time the pad is played,
        //so that it will be heard less frequently over time
        if (musicEnabled && androidpad!=null && cScore%andrModAmt == 0){
            androidpad.setVolume(0.5f, 0.5f);
            androidpad.start();
            andrModAmt += 42;
        }
*/
    }

    // Play up to three events, each randomly pitched to a different note in the pentatonic scale.
    // The rollover ding is E, so in semitones, the other pitches are
    // -4 (C), -2 (D), +3 (G), +5 (A), +8 (C). For Soundpool, that translates to:
    // 0.7937008 (C), 0.8908991 (D), 1.1892079 (G), 1.3348408 (A), 1.5874025 (C).
    private static final float[] PITCHES = {
        0.7937008f, 0.8908991f, 1f, 1.1892079f, 1.3348408f, 1.5874025f
    };
    private static final float ROLLOVER_DURATION = 0.3f;

    public static void playRollover() {
        if (!soundsLoaded) return;

        int p1 = mRandom.nextInt(6);
        int p2 = mRandom.nextInt(6);
        int p3 = mRandom.nextInt(6);

        // Only play distinct notes.
        playSound(ID_ROLLOVER, ROLLOVER_DURATION, PITCHES[p1]);
        if (p2 != p1) {
            playSound(ID_ROLLOVER, ROLLOVER_DURATION, PITCHES[p2]);
        }
        if (p3 != p1 && p3 != p2) {
            playSound(ID_ROLLOVER, ROLLOVER_DURATION, PITCHES[p3]);
        }
    }

    public static void playBall() {
        playSound(ID_LAUNCH, 1, 1);
    }

    public static void playFlipper() {
        playSound(ID_FLIPPER, 1, 1);
    }

    public static void playStart() {
        resetMusicState();
        playSound(ID_START, 0.5f, 1);
    }

    public static void playMessage() {
        playSound(ID_MESSAGE, 0.66f, 1);
    }

    public static void pauseMusic() {
        if (!soundsLoaded) return;

//        if (drumbass!=null && drumbass.isPlaying()) {
//            drumbass.pause();
//        }
//        if (androidpad!=null && androidpad.isPlaying()) {
//            androidpad.pause();
//        }
    }

    public static void cleanup() {
        Log.v(LOG_TAG, "cleanup start");
        mSoundPool.release();
        mSoundPool = null;
        mSoundPoolMap.clear();
        mAudioManager.unloadSoundEffects();
//        drumbass.release();
//        drumbass = null;
//        androidpad.release();
//        androidpad = null;
        Log.v(LOG_TAG, "cleanup finished");
    }

    public static class Player implements AudioPlayer {
        @Override public void playStart() {
            VPSoundpool.playStart();
        }

        @Override public void playBall() {
            VPSoundpool.playBall();
        }

        @Override public void playFlipper() {
            VPSoundpool.playFlipper();
        }

        @Override public void playScore() {
            VPSoundpool.playScore();
        }

        @Override public void playMessage() {
            VPSoundpool.playMessage();
        }

        @Override public void playRollover() {
            VPSoundpool.playRollover();
        }
    }
}