#include "MidiChannelEventAdapter.h"

#include "BinaryStream.h"
#include "ByteUtils.h"

#include <iostream>
#include <bitset>

int MidiChannelEventAdapter::ReadEvent(std::ifstream* file, char firstByte, MidiChannelEvent* event, MidiChannelEvent::Type& lastEventType)
{
    int first_four_bits = 0xF0;
    int second_four_bits = 0xF;
    int event_type = (firstByte & first_four_bits) >> 4;
    int midi_channel = (firstByte & second_four_bits) >> 4;
    unsigned byteCount = 0;
    std::cout << "Channel: " << midi_channel << std::endl;

    const bool isStatusByte = ByteUtils::MostSignificantBitIsOne(firstByte);
    if(isStatusByte)
    {
        event->SetTypeAndChannel(firstByte);
        lastEventType = event->GetType();
    }
    else
    {
        event->SetType(lastEventType);
    }
    std::cout << "MC Type " << static_cast<int>(event->GetType()) << std::endl;
    switch(event->GetType())
    {
    case MidiChannelEvent::Type::NOTE_ON:
    case MidiChannelEvent::Type::NOTE_OFF:
    case MidiChannelEvent::Type::CONTROLLER:
    {
        if (isStatusByte)
        {
            byteCount += ReadEventData(file, event);
        }
        else
        {
            byteCount += ReadEventData(file, event, firstByte);
        }
        break;
    }
    case MidiChannelEvent::Type::PROGRAM:
    {
        int value0 = *BinaryStream::getNextByteAsInt(file);
        byteCount ++;
        break;
    }
    default:
        std::cout << "Unknown status event: " << std::bitset<8>(firstByte) << "|" << event_type <<std::endl;
        break;
    }
    return byteCount;
}

int MidiChannelEventAdapter::ReadEventData(std::ifstream* file, MidiChannelEvent* event, char c)
{
    int value0 = int(c);
    int value1 = *BinaryStream::getNextByteAsInt(file);
    event->SetValues(value0, value1);
    return 1;
}

int MidiChannelEventAdapter::ReadEventData(std::ifstream* file, MidiChannelEvent* event)
{
    int value0 = *BinaryStream::getNextByteAsInt(file);
    int value1 = *BinaryStream::getNextByteAsInt(file);
    event->SetValues(value0, value1);
    return 2;
}
