///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB                                   //
//                                                                               //
// This program is free software; you can redistribute it and/or modify          //
// it under the terms of the GNU General Public License as published by          //
// the Free Software Foundation as version 3 of the License, or                  //
// (at your option) any later version.                                           //
//                                                                               //
// This program is distributed in the hope that it will be useful,               //
// but WITHOUT ANY WARRANTY; without even the implied warranty of                //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
// GNU General Public License V3 for more details.                               //
//                                                                               //
// You should have received a copy of the GNU General Public License             //
// along with this program. If not, see .          //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRBASE_PIPES_ELEMNTPIPESREGISTRATION_H_
#define SDRBASE_PIPES_ELEMNTPIPESREGISTRATION_H_
#include 
#include 
#include 
#include 
#include "elementpipescommon.h"
template
class ElementPipesRegistrations
{
public:
    ElementPipesRegistrations() :
        m_typeCount(0),
        m_mutex(QMutex::Recursive)
    {}
    ~ElementPipesRegistrations()
    {
        typename QMap, QList>::iterator mit = m_elements.begin();
        for (; mit != m_elements.end(); ++mit)
        {
            typename QList::iterator elIt = mit->begin();
            for (; elIt != mit->end(); ++elIt) {
                delete *elIt;
            }
        }
    }
    Element *registerProducerToConsumer(const Producer *producer, Consumer *consumer, const QString& type)
    {
        int typeId;
        QMutexLocker mlock(&m_mutex);
        if (m_typeIds.contains(type))
        {
            typeId = m_typeIds.value(type);
        }
        else
        {
            typeId = m_typeCount++;
            m_typeIds.insert(type, typeId);
        }
        const typename ElementPipesCommon::RegistrationKey regKey
            = ElementPipesCommon::RegistrationKey{producer, typeId};
        Element *element;
        if (m_consumers[regKey].contains(consumer))
        {
            int i = m_consumers[regKey].indexOf(consumer);
            element = m_elements[regKey][i];
        }
        else
        {
            element = new Element();
            m_elements[regKey].append(element);
            m_consumers[regKey].append(consumer);
        }
        return element;
    }
    Element *unregisterProducerToConsumer(const Producer *producer, Consumer *consumer, const QString& type)
    {
        Element *element = nullptr;
        if (m_typeIds.contains(type))
        {
            int typeId = m_typeIds.value(type);
            const typename ElementPipesCommon::RegistrationKey regKey
                = ElementPipesCommon::RegistrationKey{producer, typeId};
            if (m_consumers.contains(regKey) && m_consumers[regKey].contains(consumer))
            {
                QMutexLocker mlock(&m_mutex);
                int i = m_consumers[regKey].indexOf(consumer);
                m_consumers[regKey].removeAt(i);
                element = m_elements[regKey][i];
                // delete element; // will be deferred to GC
                m_elements[regKey].removeAt(i);
            }
        }
        return element;
    }
    QList* getElements(const Producer *producer, const QString& type)
    {
        if (!m_typeIds.contains(type)) {
            return nullptr;
        }
        QMutexLocker mlock(&m_mutex);
        const typename ElementPipesCommon::RegistrationKey regKey
            = ElementPipesCommon::RegistrationKey{producer, m_typeIds.value(type)};
        if (m_elements.contains(regKey)) {
            return &m_elements[regKey];
        } else {
            return nullptr;
        }
    }
    QMap, QList> *getElements() { return &m_elements; }
    QMap, QList>  *getConsumers() { return &m_consumers; }
    QMutex *getMutex() { return &m_mutex; }
private:
    QHash m_typeIds;
    int m_typeCount;
    QMap, QList> m_elements;
    QMap, QList> m_consumers;
    QMutex m_mutex;
};
#endif // SDRBASE_PIPES_ELEMNTPIPESREGISTRATION_H_