/loaders/BMloader.py
import pygame
import os.path
import re
from bmevent import *
from keyfile import *
from util import *

# Required information for a loader module. If this isn't here, the game 
# will crash and burn and it will be ALL YOUR FAULT.
name = "BeMusic BMS/BME"
version = 0.0

def detect(file):
	res = [re.compile("^#PLAYLEVEL"), re.compile("^#WAV"), re.compile("^#BMP")]
	match = [0,0,0]

	f = open(file)
	for line in f:
		for n in range(0,len(res)):
			if res[n].match(line):
				match[n] = 1
	return sum(match) / float(len(match))

def info(file):
	d = {}
	f = open(file,'r')
	r = re.compile('(WAV|BMP|\d{5}:)')
	for line in f:
		if len(line) == 0 or line[0] != "#":
			continue
		line = line[1:]
		l = line.split(' ')
		arg = ''
		cmd = l[0]
		if len(l) >= 2:
			arg = ' '.join(l[1:])
		if not r.match(cmd):
			d[cmd.lower()] = arg.strip()
	return d

def load(file,status=lambda x,y:None):
	keymapping = {0:1, 1:2, 2:3, 3:4, 4:5, 5:0, 7:6, 8:7}
	kf = KeyFile()
	kf.numkeys = len(keymapping)
	lastbpm = 0
	dir = os.path.dirname(file)
	f = open(file,'r')
	kf.track = -1
	for line in f:
		line = line.strip()
		if len(line) == 0 or line[0] != "#":
			continue
		line = line[1:]
		l = line.split(' ')
		arg = ''
		cmd = l[0]
		if len(l) >= 2:
			arg = ' '.join(l[1:])
		if cmd == "PLAYER":
			kf.player = arg
		elif cmd == "GENRE":
			kf.genre = arg
		elif cmd == "TITLE":
			kf.title = arg
		elif cmd == "ARTIST":
			kf.artist = arg
		elif cmd == "BPM":
			try:
				lastbpm = float(arg)
				kf.add(BMEvent(0, BME_TEMPO, None, lastbpm))
			except ValueError:
				print "Invalid value for BPM"
			#kf.ms_per_measure = 240000.0 / kf.bpm
		elif cmd == "PLAYLEVEL":
			try:
				kf.playlevel = int(arg)
			except ValueError:
				print "Invalid value for PLAYLEVEL"
		elif cmd == "RANK":
			try:
				kf.rank = int(arg)
			except ValueError:
				print "Invalid value for RANK"
		elif cmd == "STAGEFILE":
			# This will stay here for now. Eventually, this
			# will go into the "status" routine or somewhere
			# further up.
			if arg:
				kf.stagefile = loadBMP(os.path.join(dir,arg))
				status("STAGEFILE",kf.stagefile)
		elif cmd == "VOLWAV":
			kf.volwav = float(arg) / 100.0
		elif cmd[0:3] == "WAV":
			slot = int(cmd[3:5],36)
			if arg[-3:].lower() == 'mp3':
				wav = loadMP3(os.path.join(dir,arg))
			else:
				wav = loadWAV(os.path.join(dir,arg))
				if wav:
					wav.set_volume(kf.volwav)
			if wav:
				kf.wavs[slot] = wav
				status("WAV",arg)
			else:
				status("ERROR","Could not load " + arg)
				pygame.time.wait(1500)
		elif cmd[0:3] == "BMP":
			slot = int(cmd[3:5],36)
			bmp = loadBMP(os.path.join(dir,arg))
			if bmp:
				kf.bmps[slot] = bmp
				status("BMP",arg)
			else:
				status("ERROR","Could not load " + arg)
		elif len(cmd) > 5 and cmd[5] == ":":
			# Hmm. Should "track" really be "measure"?
			track = int(cmd[0:3])
			channel = int(cmd[3:5])
			message = cmd[6:]

			if channel == 2:
				# Channel 2 is a floating-point
				# multiplier that changes the length of
				# the measure.
				kf.add(BMEvent(track*4, BME_LONGMEASURE, None, float(message)))
				continue
			if track != kf.track:
				status("TRACK",track)
			kf.track = track

			v = [int(message[n*2:n*2+2],36) for n in range(0,len(message)/2)]
			l = float(len(v)) / 4.0

			bme = None
			if channel == 1:
				for n in range(0,len(v)):
					if v[n] == 0:
						continue
					bme = BMEvent(track*4 + n / l, BME_BGM, None, v[n])
					kf.add(bme)
			if channel == 3:
				v = [int(message[n*2:n*2+2],16) for n in range(0,len(message)/2)]
				for n in range(0,len(v)):
					# WTF is up with the low tempos?
					if v[n] == 0 or v[n] < 30:
						continue
					print "new BPM: " + str(v[n])
					bme = BMEvent(track*4 + n / l, BME_TEMPO, None, v[n])
					kf.add(bme)
					lastbpm = v[n]
			if channel == 4:
				for n in range(0,len(v)):
					if v[n] == 0:
						continue
					bme = BMEvent(track*4 + n / l, BME_BGA, None, v[n])
					kf.add(bme)
			elif (channel >= 11 and channel <= 19) or (channel >= 21 and channel <= 29):
				if channel >= 21 and channel <= 29:
					type = BME_NOTE2
					b = 21
				else:
					type = BME_NOTE1
					b = 11
				for n in range(0,len(v)):
					if v[n] == 0 or not (channel - b) in keymapping:
						continue
					bme = BMEvent(track*4 + n / l, type, keymapping[channel - b], v[n])
					kf.add(bme)
		else:
			print "Unknown command:",cmd
	kf.sort()
	f.close()

	return kf