package jp.crestmuse.cmx.inference;

import jp.crestmuse.cmx.amusaj.filewrappers.BayesNetWrapper;
import jp.crestmuse.cmx.inference.Calculator;
import jp.crestmuse.cmx.inference.MusicRepresentation;
import jp.crestmuse.cmx.inference.MusicRepresentation.MusicElement;
import jp.crestmuse.cmx.inference.MusicRepresentation.Type;

public class AccompanimentCalculator implements Calculator {

  private MusicRepresentation musicRepresentation;
  private BayesNetWrapper bayesNet;
  //private int lastPredictMeasure;

  public AccompanimentCalculator(MusicRepresentation mr,
      BayesNetWrapper bayesNet) {
    this.musicRepresentation = mr;
    this.bayesNet = bayesNet;
    //this.lastPredictMeasure = 0;
  }
/*
  public boolean isCalc(MusicElement me, int track, int index) {
    if (track == 0
        && index < (musicRepresentation.getMeasureNum() - 1)
            * musicRepresentation.getDivision())
      return true;
    return false;
  }
*/

  public Type[] drivenBy() {
    return new Type[]{Type.Melody};
  }

  public void update(MusicElement me, int index) {
    int measure = index / musicRepresentation.getDivision() + 1;
    if(measure == musicRepresentation.getMeasureNum()) return;
    //if (measure != lastPredictMeasure && measure < musicRepresentation.getMeasureNum()) {
      //lastPredictMeasure = measure;
      // 一つ前の小節の後ろと前のインデックス
      int tail = (measure - 1) * musicRepresentation.getDivision() - 1;
      int head = (measure - 2) * musicRepresentation.getDivision();
      String prevNote = "/";
      for(int i=index-1; i>head && i>=0; i--){
        MusicElement e = musicRepresentation.getMelodyElement(i);
        if(e == null) continue;
        //prevNote = e.getLabel(e.getHighestProbIndex());
        prevNote = (e.getHighestProbIndex() % 12) + "";
        break;
      }
      /*
      for (int i = tail; i >= Math.max(head, 0); i--) {
        MusicElement m = musicRepresentation.getMelodyElement(i);
        if (m == null) continue;
        prevNote = m.getLabel(m.getHighestProbIndex());
        break;
      }
      */
      String prevChord = "/";
      try {
        //prevChord = musicRepresentation.getMusicElement(1, head).getName();
        MusicElement m = musicRepresentation.getChordElement(head);
        prevChord = m.getLabel(m.getHighestProbIndex());
      } catch (ArrayIndexOutOfBoundsException e) {
      }
      //String currentChord = musicRepresentation.getMusicElement(1, tail + 1).getName();
      MusicElement m = musicRepresentation.getChordElement(tail + 1);
      String currentChord = m.getLabel(m.getHighestProbIndex());
      //String currentNote = me.getLabel(me.getHighestProbIndex());
      String currentNote = (me.getHighestProbIndex() % 12) + "";
      bayesNet.setEvidence(0, prevNote);
      bayesNet.setEvidence(1, prevChord);
      bayesNet.setEvidence(2, currentNote);
      bayesNet.setEvidence(3, currentChord);
      bayesNet.update();
      // 予測したnextNoteをMusicRepresentationに書き込む
      MusicElement nextNote = musicRepresentation.addMelodyElement(index + 1);
      for(int i=0; i<bayesNet.getMargin(4).length; i++){
        nextNote.setProb(i, bayesNet.getMargin(4)[i]);
      }
      int highestIndex = bayesNet.getHighestMarginIndex(5);
      String nextChord = bayesNet.getValueName(5, highestIndex);
      //ChordElement ce = new ChordElement(nextChord);
      //musicRepresentation.setPredict(1, measure * musicRepresentation.getDivision(), ce);
      int nextIndex = measure * musicRepresentation.getDivision();
      MusicElement chord = musicRepresentation.addChordElement(nextIndex);
      //chord.setProb(chord.indexOf(nextChord), bayesNet.getMargin(5)[highestIndex]);
      double[] margins = bayesNet.getMargin(5);
      printChordLabels(chord, margins.length);
      System.err.print("|");
      for(int i=0; i<margins.length; i++) {
        chord.setProb(i, margins[i]);
	for (int k = 0; k < 10; k++)
	    if (margins[i] > (double)k / 10) 
		System.err.print("*");
	    else
		System.err.print(" ");
	System.err.print("|");
      }
      System.err.println();
      musicRepresentation.update(Type.Chord, chord, nextIndex);

      // Prediction of the next of the next chord
      // tantative comment out because NaiveVoicingCalculator is used
      /*
      // 次の次のコードを予測
      if (measure >= musicRepresentation.getMeasureNum() - 1)
        return;
      bayesNet.setEvidence(0, currentNote);
      bayesNet.setEvidence(1, currentChord);
      bayesNet.setEvidence(2, "/");
      bayesNet.setEvidence(3, nextChord);
      bayesNet.update();
      highestIndex = bayesNet.getHighestMarginIndex(5);
      nextChord = bayesNet.getValueName(5, highestIndex);
      //ce = new ChordElement(bayesNet.getHighestMarginName(5));
      nextIndex = (measure + 1) * musicRepresentation.getDivision();
      chord = musicRepresentation.addChordElement(nextIndex);
      margins = bayesNet.getMargin(5);
      printChordLabels(chord, margins.length);
      System.err.print("|");
      for(int i=0; i<margins.length; i++) {
	  chord.setProb(i, margins[i]);
	System.err.printf("%7s: ", chord.getLabel(i));
	for (int k = 0; k < 10; k++)
	    if (margins[i] > (double)k / 10) 
		System.err.print("*");
	    else
		System.err.print(" ");
	System.err.print("|");
      }
      System.err.println();
      */
      //musicRepresentation.setPredict(1, (measure + 1) * musicRepresentation.getDivision(), ce);
    //}
  }

    private void printChordLabels(MusicElement me, int n) {
	System.err.print("|");
	for (int i = 0; i < n; i++) 
	    System.err.printf("%-10s|", me.getLabel(i));
	System.err.println();
    }
	

}
