package kr.gui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;

import javax.sound.midi.Sequence;
import javax.sound.midi.Track;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.event.ChangeEvent;
import javax.swing.filechooser.FileFilter;

import kr.AudioModel;
import kr.midireader.MidiAnalyzer;
import kr.midireader.krwriter.KRPackager;
import kr.midireader.krwriter.KRUnpackager;
import kr.midireader.krwriter.KRWriter;
import kr.util.Listener;
import kr.util.ListenerManager;
import kr.util.NotificationManager;

public class KRMenuController implements ActionListener, Listener {
	private KRMenuBar menuBar;
	private JFileChooser fileChooser;
	private Model model;
	private MidiChooserPanel chooserPanel;
	private JFrame mainFrame;
	private KRCreateDialog createDialog;
	private AudioModel audioModel;
	
	public KRMenuController()
	{
	}

	public void init(Model model, KRMenuBar menuBar, JFrame mainFrame) {
		this.fileChooser = new JFileChooser();
		fileChooser.setCurrentDirectory(new File("."));
		
		createDialog = new KRCreateDialog();
		createDialog.submitButton.addActionListener(this);
		
		this.model = model;
		this.audioModel = model.getAudioModel();
		this.menuBar = menuBar;
		this.mainFrame = mainFrame;
		menuBar.loadBkg.addActionListener(this);
		menuBar.loadMidi.addActionListener(this);
		menuBar.loadVocals.addActionListener(this);
		menuBar.clearBkg.addActionListener(this);
		menuBar.clearVocals.addActionListener(this);
		menuBar.saveKR.addActionListener(this);
		menuBar.showMidiTrackChooser.addActionListener(this);
		menuBar.saveKRPackage.addActionListener(this);
		menuBar.deriveBackgroundFromVocals.addActionListener(this);
//		menuBar.normalizeBackground.addActionListener(this);
//		menuBar.normalizeVocals.addActionListener(this);
		menuBar.viewVocalsFFT.addActionListener(this);
		menuBar.generateKREvents.addActionListener(this);
		
		updateMenuBar();
		
		ListenerManager.inst().registerListener(audioModel, this);
		ListenerManager.inst().registerListener(model.getGuiModel(), this);
	}

	public void actionPerformed(ActionEvent e) 
	{
		if(e.getSource() == menuBar.loadBkg)
		{
			File bkgFile = chooseFile("Load Background", "Audio files(.wav, .mp3)", ".wav", ".mp3");
			
			if(bkgFile != null)
				audioModel.setBkgFile(bkgFile);
		}
		else if(e.getSource() == menuBar.deriveBackgroundFromVocals)
		{
			audioModel.
			   setDeriveBackgroundFromVocalsFlag(menuBar.deriveBackgroundFromVocals.isSelected());
		}
		else if(e.getSource() == menuBar.loadVocals)
		{
			File vocalsFile = chooseFile("Load Vocals", "Audio files(.wav, .mp3)", ".wav", ".mp3");
			
			if(vocalsFile != null)
				audioModel.setVocalsFile(vocalsFile);
		}
//		else if(e.getSource() == menuBar.normalizeBackground)
//		{
//			audioModel.
//			   setNormalizeBackgroundFlag(menuBar.normalizeBackground.isSelected());
//		}
//		else if(e.getSource() == menuBar.normalizeVocals)
//		{
//			audioModel.
//			   setNormalizeVocalsFlag(menuBar.normalizeVocals.isSelected());
//		}
		else if(e.getSource() == menuBar.viewVocalsFFT)
		{
			model.getGuiModel().
			   setViewVocalsFFTFlag(menuBar.viewVocalsFFT.isSelected());
		}
		else if(e.getSource() == menuBar.generateKREvents)
		{
			model.getMidiFileModel().getMidiTuneModel().createDefaultKREvents();
		}
		else if(e.getSource() == menuBar.loadMidi)
		{
			File midiFile = chooseFile("Load Midi", "Midi(.mid) and Karaoke(.kar) files", ".mid", ".kar");
					
			if(midiFile != null)
			{
				model.getMidiFileModel().setFile(midiFile);
				
				Track [] tracks = model.getMidiFileModel().getTracks();
				if(MidiAnalyzer.guessIsKRMidi(tracks))
				{
					//in a kr midi, the vocals and lyrics track is the same
					loadTracks(tracks[1], tracks[1], tracks[2], tracks[0], true);
				}
				else {
					showMidiChooserPanel(true);
				
					updateMenuBar();
				}
			}
			
		}
		else if(e.getSource() == menuBar.showMidiTrackChooser)
		{
			if(model.getMidiFileModel().getFile() != null)
			{
				showMidiChooserPanel(false);
			}
		}
		else if(e.getSource() == menuBar.clearVocals)
		{
			audioModel.setVocalsFile(null);
		}
		else if(e.getSource() == menuBar.clearBkg)
		{
			audioModel.setBkgFile(null);
		}
		else if(e.getSource() == menuBar.saveKR)
		{
			File krFileBase = chooseFile("Save Midi", "Midi(.mid) and Karaoke(.kar) files", ".mid", ".kar");
			if(krFileBase == null) return;
			
			if(krFileBase.toString().endsWith(".mid"))
				krFileBase = new File(krFileBase.toString().substring(0, krFileBase.toString().length() - 4));
			
			model.getMidiFileModel().saveMidi(krFileBase.toString());
		}
		else if(e.getSource() == menuBar.saveKRPackage)
		{
			createDialog.initForNewSong(model.getMaxMilliSeconds());
			createDialog.setVisible(true);
		}
		else if(e.getSource() == menuBar.loadKRPackage)
		{
			File krFile = chooseFile("Open KR Package", "KR Package (.zip)", ".zip");
			
			model.loadKRPackage(krFile);
			
		}
		else if(chooserPanel != null && e.getSource() == chooserPanel.select)
		{
			Track lyrics = chooserPanel.getChosenLyrics();
			Track tune = chooserPanel.getChosenTune();
			Track krEvents = chooserPanel.getChosenKREvents();
			
			loadTracks(lyrics, tune, krEvents, chooserPanel.getTempoEvents(), false);
			chooserPanel.setVisible(false);
		}
		else if(e.getSource() == createDialog.submitButton)
		{
			createDialog.setVisible(false);
			
			GuiUtils.invokeInNonAwtThread(new Runnable()
			{
				public void run() {
					Sequence s = new KRWriter().createSequence(model.getMidiModel());
					try {
						String songAbbr = createDialog.songAbbr.getText();
						String dir = createDialog.directory.getText();
						String dbData = KRUnpackager.updateEntry(createDialog.dbData.getText(), songAbbr);
						String songsData = KRUnpackager.updateEntry(createDialog.songsData.getText(), songAbbr);
						File bkgFile = audioModel.getBkgFile();
						File vocalsFile = audioModel.getVocalsFile();
						
						KRPackager.packageKR(songAbbr, dir, dbData, songsData,	bkgFile, vocalsFile, s,
								audioModel.isDeriveBackgroundFromVocalsFlag());
						
						model.getMidiFileModel().notifyFileSaved();
					} catch (IOException e1) {
						NotificationManager.inst().error("IO error creating kr package: "+e1);
						e1.printStackTrace();
					}
				}
			});
			
		}
	}
	
	private void loadTracks(Track lyrics, Track tune, Track krEvents, Track tempoEvents, boolean isKRMidi) {

		model.getMidiFileModel().getMidiTuneModel().clear();
		if(tune != null)
			model.getMidiFileModel().getMidiTuneModel().readTune(model.getMidiFileModel().getSequence(), lyrics, tune, isKRMidi );

		model.getMidiFileModel().getMidiTuneModel().readTempoEvents(model.getMidiFileModel().getSequence(), 
				tempoEvents, isKRMidi);

		if(krEvents != null)
			model.getMidiFileModel().getMidiTuneModel().readKREvents(model.getMidiFileModel().getSequence(), krEvents, isKRMidi );
		else
			model.getMidiFileModel().getMidiTuneModel().createDefaultKREvents();
		
	}

		
	private void updateMenuBar()
	{
		menuBar.showMidiTrackChooser.setEnabled(model.getMidiFileModel().getFile() != null);
	}
	
	private void showMidiChooserPanel(boolean refresh) {
		if(chooserPanel == null || refresh)
		{
			if(chooserPanel != null)
				chooserPanel.dispose();
			chooserPanel = new MidiChooserPanel(model.getMidiFileModel(), mainFrame);	
			chooserPanel.select.addActionListener(this);
		}
		chooserPanel.setVisible(true);
	}

	private File chooseFile(String text, final String desc, final String... exts)
	{
		fileChooser.setApproveButtonText(text);
		fileChooser.setFileFilter(new FileFilter() 
				{ 
					public String getDescription() { return desc; }
					public boolean accept(File f) 
					{ 
						if(f.isDirectory())
							return true;
						for(String ext : exts) 
						{ 
							if(f.getName().toLowerCase().endsWith(ext)) return true;
						}
						return false;
					}
				}
				);
		
	    int returnVal = fileChooser.showOpenDialog(menuBar);
	    if(returnVal == JFileChooser.APPROVE_OPTION) {
	       return fileChooser.getSelectedFile();
	    }
	    
	    return null;
	}

	public void notify(Object source, Object type, Object... values) {
		if(source == audioModel)
		{
			if(type == AudioModel.MessageType.EFFECT_FLAGS_UPDATED)
			{
				menuBar.deriveBackgroundFromVocals.setSelected(audioModel.isDeriveBackgroundFromVocalsFlag());
//				menuBar.normalizeBackground.setSelected(audioModel.isNormalizeBackgroundFlag());
//				menuBar.normalizeVocals.setSelected(audioModel.isNormalizeVocalsFlag());
			}
		}
		else if(source == model.getGuiModel())
		{
			if(type == GuiModel.MessageType.IS_PLAYING_UPDATED)
			{
				boolean enableMenus = !model.getGuiModel().isPlaying();
				
				menuBar.file.setEnabled(enableMenus);
				menuBar.edit.setEnabled(enableMenus);
			}
			//menuBar.viewVocalsFFT.setSelected(model.getGuiModel().isViewVocalsFFTFlag());
		}
		
	}

}
