/**
 * 
 */
package com.tradhero;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import chromaticTuner.tuner.NoteCalculator;

import abc.notation.BarLine;
import abc.notation.EndOfStaffLine;
import abc.notation.Music;
import abc.notation.Note;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;

/**
 * @author ronanodriscoll
 *
 */
public class MainDisplay extends SurfaceView implements Runnable {
  private static final int AUDIO_LEVEL_OK = -10;
  private static final int LINE_HEIGHT = 60;
  private static final int ROW_START = 40;
  private static final int CHAR_WIDTH = 24;
  private SurfaceHolder m_surfaceHolder;
  private Thread m_thread = null;
  private boolean m_running = false;
  private Paint textPaint = null;
  private int m_cents=0;
  private int m_drawingCents=0;
  private float m_centsDrawStepSize=0f;
  private int m_drawnBackgrounds = 0;
  private final float m_drawSteps = 4f;
  private boolean m_dirty = true;
  private int m_note=-1;
  private float m_minimumLevel=-96.0f;
  enum AudioLevel {
    BELOW_MIN,
    OK,
    HIGH
  }
  private AudioLevel m_currentLevel = AudioLevel.BELOW_MIN;
  private ArrayList<Link> notes;
  private int currentNoteIndex = 0;
  public MainDisplay(Context context) {
    super(context);
    init();
  }
  public MainDisplay(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
  } 

  public MainDisplay(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
  }

  private void init() {
    textPaint = new Paint();
    textPaint.setColor(Color.GREEN);
    textPaint.setTextSize(24);
    m_surfaceHolder = getHolder();
  }

  @Override
  public void run() {
    while (m_running) {
      if (!m_surfaceHolder.getSurface().isValid()) {
        continue;
      }
      if (m_dirty) {
        Canvas canvas = m_surfaceHolder.lockCanvas();
        if (canvas != null) {
          drawNotes(canvas);
          m_surfaceHolder.unlockCanvasAndPost(canvas);
          m_dirty=false;
        }
      }
    }
  }

  /**
   * Draw notes from Music.
   * @param canvas
   */
  private void drawNotes(Canvas canvas) {
    Iterator <Link> i = notes.iterator();
    int rowCount = 0;
    int index = 0;
    int lineCount = 1;
    while (i.hasNext()) {
      Link link = i.next();
      if (index == currentNoteIndex) {
        textPaint.setColor(Color.WHITE);
      } else if (index < currentNoteIndex) {
        textPaint.setColor(Color.GREEN);
      } else {
        textPaint.setColor(Color.RED);
      }
      rowCount++;
      canvas.drawText(link.text, ROW_START + (rowCount * CHAR_WIDTH), LINE_HEIGHT * lineCount, textPaint);
      if (link.note == -1) {
        rowCount = 0;
        lineCount++;
      }
      index++;
    }
  }

  public void onResumeDisplay(){
    if (m_running)
    {
      m_drawnBackgrounds=0;
      return;
    }
    m_running = true;
    m_drawnBackgrounds=0;
    m_thread = new Thread(this);
    m_thread.start();
  }

  public void onPauseDisplay(){
    if (!m_running)
    {
      return;
    }
    boolean retry = true;
    m_running = false;
    while(retry)
    {
      try
      {
        m_thread.join();
        retry = false;
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }

  public void setNote(int note)
  {
    if (note<0) {
      m_note=note;
    } else {
      m_note=note % 12; 
    }
    // Check the current note index
    if (notes != null) {
      int current = notes.get(currentNoteIndex).note;
      if (current <= 0) {
        currentNoteIndex++;
        if (currentNoteIndex == notes.size()) { // Success!!
          currentNoteIndex = 0;
          CharSequence text = "You did it! Try again...";
          int duration = Toast.LENGTH_SHORT;

          Toast toast = Toast.makeText(getContext(), text, duration);
          toast.show();
        } else {
          current = notes.get(currentNoteIndex).note;
        }
      }
      if (current > 0 && current == m_note) {
        currentNoteIndex++;
        // TODO: Check for end of list. Tell them they're finished!
      }
    }
    m_dirty=true;
  }
  
  public void erase()
  {
    setNote(-1);
    setCents(Integer.MIN_VALUE);
  }
  
  public void setCents(int cents)
  {
    m_cents=cents;
    if (m_cents>Integer.MIN_VALUE)
    {
      if (m_drawingCents==Integer.MIN_VALUE)
      {
        m_drawingCents=m_cents;
        m_centsDrawStepSize=0;
      }
      else
      {
        m_centsDrawStepSize=(m_cents-m_drawingCents)/m_drawSteps;
      }
    }
    else
    {
      m_centsDrawStepSize=0.0f;
      m_drawingCents=Integer.MIN_VALUE;
    }
    m_dirty=true;
  }
  
  public void setMinimumInputLevel(float minimumLevel)
  {
    if (minimumLevel<0.0)
    {
      m_minimumLevel=minimumLevel;
    }
    else
    {
      m_minimumLevel=-0.0001f;
    }
    m_dirty=true;
  }
  
  public void setAudioLevel(float audioLevel)
  {
    if (audioLevel<m_minimumLevel)
    {
      m_currentLevel = AudioLevel.BELOW_MIN;
    }
    else if (audioLevel < AUDIO_LEVEL_OK)
    {
      m_currentLevel = AudioLevel.OK;
    }
    else
    {
      m_currentLevel = AudioLevel.HIGH;
    }
    m_dirty=true;
  }

  public void setMusic(Music music) {
    ArrayList<Link> notes = new ArrayList<Link>();
    Iterator i = music.iterator();
    int marker = 0;
    while (i.hasNext()) {
      Object it = i.next();
      Class klass = it.getClass();
      if (klass == Note.class) {
        Note n = (Note) it;
        notes.add(new Link(convertNoteToInt(n.getName()), n.getName()));
      } else if (klass == BarLine.class) {
        notes.add(new Link(0, "|"));
      } else if (klass == EndOfStaffLine.class) {
        notes.add(new Link(-1, " "));
        List<Link> oneLine = notes.subList(marker, notes.size());
        notes.addAll(oneLine);
        marker = notes.size(); // Set next marker
      } else {
        //Log.i("DRAWING", klass.getCanonicalName());
      }
    }
    this.notes = notes;
  }

  private int convertNoteToInt(String note) {
    if (note.equals("G'")) {
      return NoteCalculator.Gs;
    } else if (note.equals("A")) {
      return NoteCalculator.A;
    } else if (note.equals("A'")) {
      return NoteCalculator.As;
    } else if (note.equals("B")) {
      return NoteCalculator.B;
    } else if (note.equals("C")) {
      return NoteCalculator.C;
    } else if (note.equals("C'")) {
      return NoteCalculator.Cs;
    } else if (note.equals("D")) {
      return NoteCalculator.D;
    } else if (note.equals("D'")) {
      return NoteCalculator.Ds;
    } else if (note.equals("E")) {
      return NoteCalculator.E;
    } else if (note.equals("F")) {
      return NoteCalculator.F;
    } else if (note.equals("F'")) {
      return NoteCalculator.Fs;
    } else if (note.equals("G")) {
      return NoteCalculator.G;
    } else {
      return 0;
    }
  }
  final class Link {
    public int note;
    public String text;
    public Link(int n, String t) {
      note = n;
      text = t;
    }
  }
}
