//  synth factory
//  Copyright (C) 2008, 2009, 2010 Tim Blechmann
//
//  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; either version 2 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 for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; see the file COPYING.  If not, write to
//  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
//  Boston, MA 02111-1307, USA.

#pragma once

#include <map>
#include <string>

#include "synth.hpp"
#include "synth_definition.hpp"

namespace nova {

class synth_factory
{
public:
    void register_definition(synth_definition_ptr && prototype)
    {
        prototype_map_type::iterator it = definition_map.find(prototype->name(), named_hash_hash(), named_hash_equal());
        if (it != definition_map.end()) {
            definition_map.erase(it);
            it->release();
        }

        synth_definition_ptr ptr( std::forward<synth_definition_ptr>(prototype) );

        ptr->add_ref();
        definition_map.insert(*ptr.get());
    }

    abstract_synth * create_instance(const char * name, int node_id)
    {
        prototype_map_type::iterator it = definition_map.find(name, named_hash_hash(), named_hash_equal());
        if (it == definition_map.end())
            return nullptr;

        return it->create_instance(node_id);
    }

    void remove_definition(const char * name)
    {
        prototype_map_type::iterator it = definition_map.find(name, named_hash_hash(), named_hash_equal());
        if (it == definition_map.end())
            return;

        definition_map.erase(it);
        it->release();
    }

    std::size_t definition_count(void) const
    {
        return definition_map.size();
    }

    synth_factory(void):
        definition_map(prototype_map_type::bucket_traits(buckets, bucket_count))
    {}

    ~synth_factory(void)
    {
        while(definition_map.begin() != definition_map.end()) {
            prototype_map_type::iterator it = definition_map.begin();
            definition_map.erase(it);
            it->release();
        }
    }

private:
    static const int bucket_count = 2048;

    typedef boost::intrusive::unordered_set<synth_definition,
                                            boost::intrusive::power_2_buckets<true>
                                           > prototype_map_type;
    prototype_map_type::bucket_type buckets[bucket_count];
    prototype_map_type definition_map;
};

} /* namespace nova */
