package kompose;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeMap;


import com.cycling74.max.*;

public class MIDIFileInfo extends MaxObject
	{
	private static String sourceWork;
	private TreeMap<Integer, ArrayList<Atom[]>> completeSequence;
	
	public MIDIFileInfo()
		{
		completeSequence = new TreeMap<Integer, ArrayList<Atom[]>>();
		}
	
	public void read(String midifile) 
		{
		String temp = "";
		StringTokenizer st = new StringTokenizer(midifile, "/");
		while(st.hasMoreTokens())
			temp = st.nextToken();
		StringTokenizer st2 = new StringTokenizer(temp, ".");
		sourceWork = st2.nextToken();
		post("" +sourceWork);
		jbm_MidiParse _midiParser = new jbm_MidiParse();
		completeSequence = _midiParser.parseMidiFile(midifile);
		reportLengthInBars();
		}
	
	public void dumpTrackEvents(int track)
		{
		ArrayList<Atom[]> events = new ArrayList<Atom[]>();
		Integer trackNum = new Integer(track);
		if(completeSequence.containsKey(trackNum))
			{
			events = completeSequence.get(trackNum);
			}
		for(int i=0;i < events.size();i++)
			{
			Atom[] event = events.get(i);
			if(event[4].toLong() > 0)
				outlet(0, reformat(event));
			}
		}
	
	public void dump()
		{
		ArrayList<Atom[]> events = new ArrayList<Atom[]>();
		Set keys = completeSequence.keySet();
		for(Iterator itr=keys.iterator();itr.hasNext();)
			{
			Integer trackNum = (Integer)itr.next();
			if(trackNum.intValue() == 999)
				continue;
			if(completeSequence.containsKey(trackNum))
				{
				events = completeSequence.get(trackNum);
				for(int i=0;i < events.size();i++)
					{
					Atom[] event = events.get(i);
					if(event[4].toLong() > 0)
						outlet(0, reformat(events.get(i)));
					}
				}
			}
		}
	
	// Utility methods
	private Atom[] reformat(Atom[] input)
		{
		int res = input[2].getInt() * 2;
		long tick = input[1].toLong();
		int modulo = 4/input[4].getInt() * res;
		double fractionalTick = ((double)(tick % modulo)/(double)modulo);
		Atom tickOut = Atom.newAtom((double)fractionalTick);
		int absoluteBeat = (int)tick/modulo;
		int beat = absoluteBeat % input[3].getInt() + 1;
		int bar = (absoluteBeat/input[3].getInt()) + 1;
		Atom[] reformatted = null;
		reformatted = new Atom[]{input[0], Atom.newAtom((int)bar), Atom.newAtom((int)beat), tickOut, input[5], input[7], input[8], tickOut};
		return reformatted;
		}

	private void reportLengthInBars()
		{
		ArrayList<Atom[]> events = new ArrayList<Atom[]>();
		Set keys = completeSequence.keySet();
		long highTick = 0;
		Atom[] lastEvent = new Atom[4];
		for(Iterator itr=keys.iterator();itr.hasNext();)
			{
			Integer trackNum = (Integer)itr.next();
			if(completeSequence.containsKey(trackNum))
				{
				if(trackNum.intValue() != 999)
					continue;
				events = completeSequence.get(trackNum);
				for(int i=0;i < events.size();i++)
					{
					Atom[] event = events.get(i);
					long tickstamp = event[0].toLong();
					if(tickstamp > highTick)
						{
						highTick = tickstamp;
						lastEvent = event;
						post("Last End of Track event: " +Atom.toDebugString(event));
						}
					}
				}
			}
		int res = lastEvent[1].getInt();
		long tick = lastEvent[0].toLong();
		int modulo = lastEvent[2].getInt()/lastEvent[3].getInt() * res;
		int absoluteBeat = (int)tick/modulo;
		int bar = (absoluteBeat/lastEvent[2].getInt());
		outlet(1, bar);
		}
	}



