package com.tradhero;

import chromaticTuner.tuner.AboutActivity;
import chromaticTuner.tuner.NoteCalculator;
import chromaticTuner.tuner.OnAudioBufferListener;
import chromaticTuner.tuner.OnAudioLevelListener;
import chromaticTuner.tuner.OnAudioRecorderInitializeErrorListener;
import chromaticTuner.tuner.OnFrequencyUpdateListener;
import chromaticTuner.tuner.PitchDetector;
import chromaticTuner.tuner.Recorder;
import chromaticTuner.tuner.SettingsActivity;

import com.example.tradhero.R;

import abc.notation.Music;
import abc.notation.Tune;
import abc.parser.AbcNode;
import abc.parser.TuneParser;
import abc.parser.TuneParserListenerInterface;
import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MainActivity extends Activity {
  private MainDisplay mainDisplay;
  private Recorder m_recorder= null;
  private MainActivity m_activity = null;
  private float m_audioLevel=0.0f;
  private boolean m_stopped = false;
  private PitchDetector m_pitchDetector = null;
  private float m_frequency = 0.0f;
  private float m_volumeThreshold = -48.0f;
  private float m_aFrequency = 440.0f;
  private final int AUDIO_RECORDING_ERROR = 1;
  private int m_previousDetectedNote = -1;
  private boolean m_debugOn = false;
  private Button quitButton = null;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // Sey up tuner
    initAudioLevel();
    initFrequencyValue();
    m_recorder = new Recorder();
    m_recorder.setOnAudioBufferListener(m_audioBufferListener);
    m_recorder.setOnAudioRecorderInitializeError(m_audioRecorderInitializeError);
    m_pitchDetector = new PitchDetector(m_recorder.getSampleRate());
    m_pitchDetector.setOnFrequencyUpdateListener(m_frequencyUpdateListener);
    m_pitchDetector.setOnVisualizationValueListener(m_audioLevelListener);
    m_activity = this;
    // Load ABC string
    Intent i = this.getIntent();
    Music music = (Music) i.getSerializableExtra("com.tradhero.abc");
    mainDisplay = (MainDisplay) findViewById(R.id.tuner_display);
    mainDisplay.setMusic(music);
    new Thread(mainDisplay).start();
    // Initialize Buttons
    quitButton = (Button) findViewById(R.id.quit_button);
    quitButton.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
          finish();
        }
    });
  }


  private void initAudioLevel()
  {
      m_audioLevel=Float.NEGATIVE_INFINITY;
      updateAudioLevel();
  }
  
  private void initFrequencyValue()
  {
    m_frequency=0.0f;
    updateFrequency();
  }
  
  private void updateAudioLevel()
  {
    if (m_debugOn)
    {
      TextView view = (TextView)findViewById(R.id.input_level_view);
      view.setText("Input volume: " + m_audioLevel + " dB");
    }
    MainDisplay tunerDisp = (MainDisplay)findViewById(R.id.tuner_display);
    tunerDisp.setAudioLevel(m_audioLevel);
  }
  
  private void updateFrequency()
  {
    if (m_debugOn)
    {
      TextView view = (TextView)findViewById(R.id.frequency_view);
          view.setText("Frequency: " + m_frequency + " Hz");
    }
    updateNote();
  }
  
  private void updateNote()
  {
    MainDisplay tunerDisp = (MainDisplay)findViewById(R.id.tuner_display);
        if (m_frequency<0.01)
        {
          tunerDisp.erase();
          m_previousDetectedNote=-1;
          return;
        }
    
    float note = NoteCalculator.calculateNoteFromFrequency(m_frequency, m_aFrequency);
    int noteInt=Math.round(note);
    if (noteInt!=m_previousDetectedNote)
    {
      tunerDisp.erase();
      m_previousDetectedNote=noteInt;
      return;
    }
    float noteDiff = note - noteInt;
    int cents=(int) Math.round(noteDiff*100.0);
    if (m_debugOn) {
      TextView view = (TextView)findViewById(R.id.note_view);
      view.setText("Note: " + NoteCalculator.noteNumberToNoteName(noteInt) + " Cents: " + cents);
    }
    tunerDisp.setNote(noteInt);
        tunerDisp.setCents(cents);
  }

  public void onResume()
  {
    super.onResume();
    m_aFrequency = SettingsActivity.getAFrequency(this);
    m_pitchDetector.setAFrequency(m_aFrequency);
    m_volumeThreshold = SettingsActivity.getVolumeThreshold(this);
    m_pitchDetector.setRmsThreshold(m_volumeThreshold);
    m_debugOn = SettingsActivity.getDebugVisible(this);
    checkDebugVisibility();
    MainDisplay tunerDisp = (MainDisplay)findViewById(R.id.tuner_display);
    tunerDisp.setMinimumInputLevel(m_volumeThreshold);
    tunerDisp.setKeepScreenOn(true);
    stop();
    start();
  }
  
  public void onPause()
  {
    super.onPause();
    stop();
  }
  
private void stop()
{
  m_stopped=true;
  m_recorder.stop();
    initFrequencyValue();
    initAudioLevel();
    MainDisplay tunerDisp = (MainDisplay)findViewById(R.id.tuner_display);
    tunerDisp.onPauseDisplay();
    getWindow().clearFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}

private void start()
{
  m_stopped=false;
  m_recorder.start();
  m_pitchDetector.setBufferSize(m_recorder.getBufferSize());
  MainDisplay tunerDisp = (MainDisplay)findViewById(R.id.tuner_display);
    tunerDisp.onResumeDisplay();
    getWindow().addFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}

public Dialog onCreateDialog(int id)
{
  // only audio recording error
  AlertDialog.Builder builder = new AlertDialog.Builder(this);
  builder.setMessage("Failed to start recording audio. Application will quit.")
         .setCancelable(false)
         .setPositiveButton("Quit", new DialogInterface.OnClickListener() {
             public void onClick(DialogInterface dialog, int id) {
                  MainActivity.this.finish();
             }
         });
  AlertDialog alert = builder.create();
  return alert;
}


private void checkDebugVisibility() {
  if (m_debugOn) {
    TextView view = (TextView)findViewById(R.id.input_level_view);
    view.setVisibility(View.VISIBLE);
    view = (TextView)findViewById(R.id.frequency_view);
    view.setVisibility(View.VISIBLE);
    view = (TextView)findViewById(R.id.note_view);
    view.setVisibility(View.VISIBLE);
  } else {
    TextView view = (TextView)findViewById(R.id.input_level_view);
    view.setVisibility(View.GONE);
    view = (TextView)findViewById(R.id.frequency_view);
    view.setVisibility(View.GONE);
    view = (TextView)findViewById(R.id.note_view);
    view.setVisibility(View.GONE);
  }
}

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
  }

  public boolean onOptionsItemSelected(MenuItem item) {
      switch (item.getItemId()) {
          case R.id.settings:
              startActivity(new Intent(this, SettingsActivity.class));
              return true;
          case R.id.about:
              startActivity(new Intent(this, AboutActivity.class));
              return true;
      }
      return false;
  }
 
  private OnAudioLevelListener m_audioLevelListener = new OnAudioLevelListener() {
    public void onAudioLevel(float value) {
      m_audioLevel=value;
      m_activity.runOnUiThread(new Runnable() {
            public void run() {
              updateAudioLevel();
            }
          });
    }
  };
  
  private OnAudioBufferListener m_audioBufferListener = new OnAudioBufferListener() {
    public void onAudioBuffer(short[] buffer) {
      if (!m_stopped)
      {
        m_pitchDetector.processBuffer(buffer);
      }
    }
  };
  
  private OnFrequencyUpdateListener m_frequencyUpdateListener = new OnFrequencyUpdateListener() {
    public void onFrequencyUpdate(float frequency) {
      m_frequency=frequency;
      m_activity.runOnUiThread(new Runnable() {
            public void run() {
              updateFrequency();
            }
          });
    }
  };
  
  public OnAudioRecorderInitializeErrorListener m_audioRecorderInitializeError = new OnAudioRecorderInitializeErrorListener() {
    public void audioRecorderInitializeError() {
      m_activity.runOnUiThread(new Runnable() {
          public void run() {
            m_activity.showDialog(m_activity.AUDIO_RECORDING_ERROR);
          }
        });
    }
  };
}
