/**
 * Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr)
 * Copyright (C) 2010 Robert B. Denny, Mesa, AZ, USA
 * This file is part of CSipSimple.
 *
 *  CSipSimple is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *  If you own a pjsip commercial license you can also redistribute it
 *  and/or modify it under the terms of the GNU Lesser General Public License
 *  as an android library.
 *
 *  CSipSimple is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with CSipSimple.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * This file contains relicensed code from Apache copyright of 
 * Copyright (C) 2008 The Android Open Source Project
 */


package com.voiceblue.phone.utils;

import android.app.Activity;
import android.content.Context;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.os.Vibrator;

import java.util.Timer;
import java.util.TimerTask;

public class DialingFeedback {

	/** The length of vibrate (haptic) feedback in milliseconds */
	private static final int HAPTIC_LENGTH_MS = 50;
	
    /** The length of DTMF tones in milliseconds */
    private static final int TONE_LENGTH_MS = 150;

    /** The DTMF tone volume relative to other sounds in the stream */
    private static final int TONE_RELATIVE_VOLUME = 80;

    private boolean inCall;
    private int toneStream;
    private Activity context;
    
	private ToneGenerator toneGenerator = null;
	private Object toneGeneratorLock = new Object();
	private Vibrator vibrator = null;
	private Timer toneTimer = null;

	private PreferencesWrapper prefsWrapper;
	private boolean dialPressTone = false;
	private boolean dialPressVibrate = false;

	private int ringerMode;

	public DialingFeedback(Activity context, boolean inCall) {
		
		this.context = context;
		this.inCall = inCall;
		toneStream = inCall ? AudioManager.STREAM_VOICE_CALL : AudioManager.STREAM_MUSIC;
		prefsWrapper = new PreferencesWrapper(context);
	}
	
	public void resume() {
		
		dialPressTone = prefsWrapper.dialPressTone(inCall);
		dialPressVibrate = prefsWrapper.dialPressVibrate();

        if (dialPressTone) {
            // Create dialtone just for user feedback
            synchronized (toneGeneratorLock) {
                if (toneTimer == null) {
                    toneTimer = new Timer("Dialtone-timer");
                }
                if (toneGenerator == null) {
                    try {
                        toneGenerator = new ToneGenerator(toneStream, TONE_RELATIVE_VOLUME);
                        // Allow user to control dialtone
                        if (!inCall) {
                            context.setVolumeControlStream(toneStream);
                        }
                    } catch (RuntimeException e) {
                        // If impossible, nothing to do
                        toneGenerator = null;
                    }
                }
            }
        } else {
            toneTimer = null;
            toneGenerator = null;
        }
		
		//Create the vibrator
		if (dialPressVibrate) {
			if (vibrator == null) {
				vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
			}
		} else {
			vibrator = null;
		}

		//Store the current ringer mode
		AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
		ringerMode = am.getRingerMode();

	}
	
	public void pause() {

		//Destroy dialtone
		synchronized (toneGeneratorLock) {
			if (toneGenerator != null) {
			    toneGenerator.stopTone();
				toneGenerator.release();
				toneGenerator = null;
			}
			if(toneTimer != null) {
				toneTimer.cancel();
				toneTimer.purge();
				toneTimer = null;
			}
		}
		
	}

	/**
	 * Tone play to be used when a button in dialpad
	 * is pressed
	 * @param tone The tone associated to the button
	 */
	public void giveFeedback(int tone) {
		
		switch (ringerMode) {
			case AudioManager.RINGER_MODE_NORMAL:
				if (dialPressVibrate) {
				    vibrator.vibrate(HAPTIC_LENGTH_MS);
				}
				if (dialPressTone) {
				    ThreadedTonePlay threadedTone = new ThreadedTonePlay(tone);
				    threadedTone.start();
				}
				break;
			case AudioManager.RINGER_MODE_VIBRATE:
				if (dialPressVibrate) {
				    vibrator.vibrate(HAPTIC_LENGTH_MS);
				}
				break;
			case AudioManager.RINGER_MODE_SILENT:
				break;
		}
	}
	
	/**
	 * Haptic vibration to be used when a button in dialpad 
	 * is long pressed for example.
	 */
	public void hapticFeedback() {
		if (dialPressVibrate && ringerMode != AudioManager.RINGER_MODE_SILENT) {
			vibrator.vibrate(HAPTIC_LENGTH_MS);
		}
	}
	
	class ThreadedTonePlay extends Thread {
	    private final int tone;
        
	    ThreadedTonePlay(int t){
	        tone = t;
	    }
	    
	    @Override
	    public void run() {
            synchronized (toneGeneratorLock) {
                if (toneGenerator == null) {
                    return;
                }
                toneGenerator.stopTone();
                toneGenerator.startTone(tone);
                toneTimer.schedule(new StopTimerTask(), TONE_LENGTH_MS);
            }
	    }
	}
	
	class StopTimerTask extends TimerTask{
		@Override
		public void run() {
			synchronized (toneGeneratorLock) {
				if (toneGenerator == null) {
					return;
				}
				toneGenerator.stopTone();
			}
		}
	}

}
