#!/usr/bin/python3


# Program to generate the downcast file for the swig generated bindings.

# TODO Omit abstract classes. Unfortunately abstract detection in doxygen is
# broken, see https://bugzilla.gnome.org/show_bug.cgi?id=785402.


import utils
from functools import reduce


def gatherer(node):
    tmp = []
    for successor in sorted(utils.classes.successors(node)):
        tmp += gatherer(successor)
    tmp.append(node)
    return tmp


print("""
// This file is generated by utils/generate-downcast.py.

// Background is provided at http://nickdarnell.com/swig-casting-revisited/
// and https://github.com/swig/swig/blob/master/Lib/typemaps/factory.swg.

// In most cases the downcast is not required since polymorphism is handled in
// C++. But if you e.g. extend the Device classes in Ruby it is required.

// Order of classes is crucial: The first one wins so the most derived class
// must be first, e.g. Luks before Encryption. Abstract classes should not be
// listed.

%include \"factory.i\"
""")

device_names = gatherer("storage::Device")

print("%factory(storage::Device* storage::downcast,")
print("\t " + ",\n\t ".join(device_names) + ")")
print("")

print("%factory(const storage::Device* storage::downcast,")
print("\t " + ",\n\t ".join(["const " + name for name in device_names]) + ")")
print("")

holder_names = gatherer("storage::Holder")

print("%factory(storage::Holder* storage::downcast,")
print("\t " + ",\n\t ".join(holder_names) + ")")
print("")

print("%factory(const storage::Holder* storage::downcast,")
print("\t " + ",\n\t ".join(["const " + name for name in holder_names]) + ")")

print("""
%inline %{

    namespace storage
    {

	storage::Device*
	downcast(storage::Device* device)
	{
	    return device;
	}

	const storage::Device*
	downcast(const storage::Device* device)
	{
	    return device;
	}

	storage::Holder*
	downcast(storage::Holder* holder)
	{
	    return holder;
	}

	const storage::Holder*
	downcast(const storage::Holder* holder)
	{
	    return holder;
	}

    }

%}
""")
