#include <core/service.h>
#include <algorithm>

namespace extra2d {

SvcMgr& SvcMgr::inst() {
    static SvcMgr instance;
    return instance;
}

void SvcMgr::reg(IService* svc) {
    if (!svc) return;
    SvcMap::accessor acc;
    svcMap_.insert(acc, svc->name());
    acc->second = Ptr<IService>(svc);
    sortSvcs();
}

void SvcMgr::unreg(const char* name) {
    svcMap_.erase(name);
    sortSvcs();
}

Ptr<IService> SvcMgr::get(const char* name) {
    SvcMap::const_accessor acc;
    if (svcMap_.find(acc, name)) {
        return acc->second;
    }
    return nullptr;
}

bool SvcMgr::initAll() {
    for (auto& svc : sortedSvcs_) {
        if (svc && svc->state_ == SvcState::None) {
            if (!svc->init()) {
                return false;
            }
            svc->state_ = SvcState::Inited;
        }
    }
    return true;
}

void SvcMgr::pauseAll() {
    for (auto& svc : sortedSvcs_) {
        if (svc && svc->state_ == SvcState::Running) {
            svc->pause();
            svc->state_ = SvcState::Paused;
        }
    }
}

void SvcMgr::resumeAll() {
    for (auto& svc : sortedSvcs_) {
        if (svc && svc->state_ == SvcState::Paused) {
            svc->resume();
            svc->state_ = SvcState::Running;
        }
    }
}

void SvcMgr::shutdownAll() {
    for (auto it = sortedSvcs_.rbegin(); it != sortedSvcs_.rend(); ++it) {
        if (*it && (*it)->state_ >= SvcState::Inited) {
            (*it)->shutdown();
            (*it)->state_ = SvcState::Shutdown;
        }
    }
}

void SvcMgr::updateAll(float dt) {
    for (auto& svc : sortedSvcs_) {
        if (svc && svc->state_ >= SvcState::Inited && svc->isEnabled()) {
            if (svc->state_ == SvcState::Inited) {
                svc->state_ = SvcState::Running;
            }
            svc->update(dt);
        }
    }
}

void SvcMgr::lateUpdateAll(float dt) {
    for (auto& svc : sortedSvcs_) {
        if (svc && svc->state_ >= SvcState::Running && svc->isEnabled()) {
            svc->lateUpdate(dt);
        }
    }
}

void SvcMgr::fixedUpdateAll(float dt) {
    for (auto& svc : sortedSvcs_) {
        if (svc && svc->state_ >= SvcState::Running && svc->isEnabled()) {
            svc->fixedUpdate(dt);
        }
    }
}

bool SvcMgr::has(const char* name) const {
    SvcMap::const_accessor acc;
    return svcMap_.find(acc, name);
}

size_t SvcMgr::count() const {
    return svcMap_.size();
}

void SvcMgr::sortSvcs() {
    sortedSvcs_.clear();
    for (auto it = svcMap_.begin(); it != svcMap_.end(); ++it) {
        sortedSvcs_.push_back(it->second);
    }
    std::sort(sortedSvcs_.begin(), sortedSvcs_.end(),
        [](const Ptr<IService>& a, const Ptr<IService>& b) {
            return a->pri() < b->pri();
        });
}

} // namespace extra2d
