package jp.crestmuse.cmx.amusaj.commands;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.xml.sax.SAXException;

import jp.crestmuse.cmx.amusaj.filewrappers.ArffWrapper;
import jp.crestmuse.cmx.commands.CMXCommand;
import jp.crestmuse.cmx.filewrappers.FileWrapperCompatible;
import jp.crestmuse.cmx.filewrappers.InvalidFileTypeException;
import jp.crestmuse.cmx.filewrappers.SCCXMLWrapper;
import jp.crestmuse.cmx.filewrappers.SCCXMLWrapper.Annotation;
import jp.crestmuse.cmx.filewrappers.SCCXMLWrapper.Note;

/**
 * 複数のSCCからARFFを生成して返す． デフォルトで標準出力に書き出す． ファイルに書き出したい場合はpostprocをいじる．
 */
public class SCC2ARFF extends
    CMXCommand<FileWrapperCompatible, FileWrapperCompatible> {

  /**
   * 最終的に書き出すARFF
   */
  private ArffWrapper arff;

  SCC2ARFF() {
    arff = new ArffWrapper("chord");

    // 学習データ内に存在する可能性のあるNoteナンバー．
    // 12種類に圧縮している
    String[] notenums = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
        "10", "11" };

    // 存在する可能性のあるコード M,m,aug,dim,(#5),(b5)
    String[] chords = {
    		"A", "A#", "A#aug", "A#dim", "A#m", "Aaug", "Adim", "Am",
    		"B", "Baug", "Bdim", "Bm", "C", "C#", "C#aug", "C#dim", "C#m",
    		"Caug", "Cdim", "Cm", "D", "D#", "D#aug", "D#dim", "D#m", "Daug",
    		"Ddim", "Dm", "E", "Eaug", "Edim", "Em", "F", "F#", "F#aug", "F#dim",
    		"F#m", "Faug", "Fdim", "Fm", "G", "G#", "G#aug", "G#dim", "G#m",
    		"Gaug", "Gdim", "Gm"};	
    
     
    
    arff.addAttribute("CurrentNote", notenums);
    arff.addAttribute("CurrentChord", chords);
    arff.addAttribute("NextNote", notenums);
    arff.addAttribute("NextChord", chords);
  }

  protected FileWrapperCompatible run(FileWrapperCompatible f)
      throws IOException, ParserConfigurationException, SAXException,
      TransformerException, InvalidFileTypeException {
    SCCXMLWrapper scc = (SCCXMLWrapper) f;
    ChordConverter cc = new ChordConverter();
    //Iterator<Note> itr = Arrays.asList(scc.getPartList()[0].getNoteList())
    //    .iterator();	//パートが一つしかないものとして[0]のパート
    int prevNote = -1;
    String prevChord = null;
    
    // 曲のキーを取得
    String musickey = "UNDEFINED";
    for(int i=0; i < scc.getHeaderElementList().length; i++){
    	if(scc.getHeaderElementList()[i].name().equals("KEY")){
    		musickey = cc.getPrefix(scc.getHeaderElementList()[i].content());
    		break;
    	}
    }
    if(musickey.equals("UNDEFINED")){
    	System.out.println(f+" is invalid musickey");
    	return null;
    }
    
    for (Annotation a : scc.getChordList()) {
      String currentChord = a.content(); //コード取得
      // 謎のデータをスキップ
      if (currentChord.equals("D'"))
        continue;
      //
      int currentNote = -1;
      //
      /*while (itr.hasNext()) {	//ノートのリスト
        Note n = itr.next();
        if (n.onset() >= a.onset()) {
          currentNote = n.notenum() % 12;
          break;
        }
      }
      */
      for(Note n : scc.getPartList()[0].getNoteList()){
	        if (n.onset() >= a.onset()) {
	          currentNote = n.notenum() % 12;
	          break;
	        }
	  }
      if (currentNote == -1)
        return null;
      
      currentNote = cc.noteTransfer(musickey, currentNote);
      
      //currentChordが"/"の時はprevChordを代入
      currentChord = cc.chordOmitter(cc.chordTransfer(musickey, currentChord));
      if(currentChord.equals("/")){
    	  currentChord = prevChord;
      }
      
      
      if (prevChord != null) {
    	  //TODO 追加した部分、ChordConverterの無視するコードに該当するものが無いなら書き込むつもりの処理
    	  if(!(prevChord.matches(cc.ignore_chords)) && !(currentChord.matches(cc.ignore_chords)))
	        arff.addData(prevNote + "," + prevChord + "," + currentNote + ","
	            + currentChord);
      }
      prevNote = -1;
      for(Note n : scc.getPartList()[0].getNoteList()){
    	  if(n.onset() < a.offset()){
    		  prevNote = n.notenum();
    	  }
    	  else{
    		  break;
    	  }
      }
      if(prevNote == -1){
    	  return null;
      }
      else{
    	  prevNote %= 12;
      }
      prevChord = currentChord;
    }
    return null;
  }

  protected void postproc() throws IOException, ParserConfigurationException,
      SAXException, TransformerException {
    FileOutputStream out = new FileOutputStream(new File("hoge.arff"));
    arff.write(out);
  }

  public static void main(String[] args) {
	  /*
    SCC2ARFF s2a = new SCC2ARFF();
    
    try {
      s2a.start(args);
    } catch (Exception e) {
      e.printStackTrace();
    }
    */
	  System.out.println("ugoita--!");
  }

}
