using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using UnityEngine;

class BMS
{
    // metadata

    public string title;
    public double bpm;
    public string genre;
    public string author;

    public List<BmsNote> notes = new List<BmsNote>();

    public Level ToLevel()
    {
        var level = new Level();

        // convert metadata

        level.bpm = bpm;

        // sort all notes
        notes.Sort((note1, note2) =>
        {
            var diff = note1.barTime - note2.barTime;

            if (diff < 0)
                return -1;
            else if (diff == 0)
                return 0;
            else
                return 1;
        });

        // convert all bms note to level note
        foreach (var note in notes)
        {
            var levelNote = Note.Create(note, bpm);

            if (levelNote != null)
                level.AddNote(levelNote);
        }



        return level;
    }
}

class BmsNote
{
    public string num;
    public string lane;
    public double barTime;
}

class BmsParser
{
    private static char[] SEP_NEWLINE = { '\n' };
    private static char[] SEP_SPACE = { ' ' };
    private static char[] SEP_COLON = { ':' };

    private static Regex RX_DATALINE = new Regex(@"#[0-9]{5}");

    public BMS Parse(string raw)
    {
        var lines = raw.Split(SEP_NEWLINE);

        var bms = new BMS();

        foreach (var line in lines)
        {
            // metadata
            if (line.StartsWith("#TITLE"))
                bms.title = line.Substring(line.IndexOf(' ') + 1);

            if (line.StartsWith("#GENRE"))
                bms.genre = line.Substring(line.IndexOf(' ') + 1);

            if (line.StartsWith("#BPM"))
                bms.bpm = double.Parse(line.Substring(line.IndexOf(' ') + 1));

            if (line.StartsWith("#ARTIST"))
                bms.author = line.Substring(line.IndexOf(' ') + 1);

            // data lane
            if (RX_DATALINE.IsMatch(line))
            {
                var bar = int.Parse(line.Substring(1, 3));
                var lane = line.Substring(4, 2);
                var data = line.Substring(7).Trim();

                // no support for variable bar length or bpm yet
                if ((data.Length & 1) == 1 || data.Contains("."))
                {
                    // ignore these lines
                }

                var denominator = data.Length / 2;

                // process notes in the bar
                for (int i = 0; i < denominator; i++)
                {
                    var num = data.Substring(i * 2, 2);
                    var barTime = bar + i / (double)denominator;

                    // ignore empty notes
                    if (num != "00")
                    {
                        var note = new BmsNote();

                        note.num = num;
                        note.lane = lane;
                        note.barTime = barTime;

                        bms.notes.Add(note);
                    }
                }
            }
        }

        Debug.Log(bms.author);
        Debug.Log(bms.bpm);
        Debug.Log(bms.title);
        Debug.Log(bms.genre);
        return bms;
    }
}
