#include "ImageBuffer.h"

#include "Texture2D.h"
#include "Core/Thread/ScopeLock.h"

ImageBuffer* Singleton<ImageBuffer>::instance_ = nullptr;

bool ImageBuffer::Initialize() {
    return true;
}

void ImageBuffer::Uninitialize() {

}

void ImageBuffer::PushImage(ImageBuffer::IBType type, std::vector<unsigned char> data,
    uint32 width, uint32 height, uint32 comp) {
	switch (type) {
	case ImageBuffer::IBType::Human:
        PushHumanImage(std::move(data), width, height, comp);
		break;
    case ImageBuffer::IBType::Face:
        PushFaceImage(std::move(data), width, height, comp);
        break;
    case ImageBuffer::IBType::FaceMask:
        PushFaceMaskImage(std::move(data), width, height, comp);
        break;
	default:
		break;
	}
}

void ImageBuffer::Update(IBType type, Texture2D* texture) {
    switch (type) {
    case ImageBuffer::IBType::Human:
        UpdateHuman(texture);
        break;

    case IBType::Face:
        UpdateFace(texture);

    case IBType::FaceMask:
        UpdateFaceMask(texture);

    default:
        break;
    }
}

void ImageBuffer::PushHumanImage(std::vector<uint8> data, uint32 width, uint32 height, uint32 comp) {
    ScopeLock<CriticalSection> lock(&human_cs_);
 
    human_.data = std::move(data);
    human_.width = width;
    human_.height = height;
    human_.comp = comp;
    human_.updated = true;
}

void ImageBuffer::UpdateHuman(Texture2D* texture) {
    if (human_.data.empty()) {
        return;
    }

    ScopeLock<CriticalSection> lock(&human_cs_);
    if (!human_.updated) {
        return;
    }
    human_.updated = false;
    texture->Update(human_.width, human_.height, human_.comp, human_.data.data());
}

void ImageBuffer::PushFaceImage(std::vector<uint8> data, uint32 width, uint32 height, uint32 comp) {
    ScopeLock<CriticalSection> lock(&face_cs_);

    face_.data = std::move(data);
    face_.width = width;
    face_.height = height;
    face_.comp = comp;
}

void ImageBuffer::UpdateFace(class Texture2D* texture) {
    if (face_.data.empty()) {
        return;
    }

    ScopeLock<CriticalSection> lock(&face_cs_);
    texture->Update(face_.width, face_.height, face_.comp, face_.data.data());
}

void ImageBuffer::PushFaceMaskImage(std::vector<uint8> data, uint32 width, uint32 height, uint32 comp) {
    ScopeLock<CriticalSection> lock(&face_mask_cs_);

    faceMask_.data = std::move(data);
    faceMask_.width = width;
    faceMask_.height = height;
    faceMask_.comp = comp;
}

void ImageBuffer::UpdateFaceMask(class Texture2D* texture) {
    if (faceMask_.data.empty()) {
        return;
    }

    ScopeLock<CriticalSection> lock(&face_mask_cs_);
    texture->Update(faceMask_.width, faceMask_.height, faceMask_.comp, faceMask_.data.data());
}
