#
# LSST Data Management System
# Copyright 2008, 2009, 2010 LSST Corporation.
#
# This product includes software developed by the
# LSST Project (http://www.lsst.org/).
#
# 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 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 for more details.
#
# You should have received a copy of the LSST License Statement and
# the GNU General Public License along with this program.  If not,
# see <http://www.lsstcorp.org/LegalNotices/>.
#
import functools
import numpy
import lsst.geom
from lsst.pex.config import Config, ListField, makeRegistry, \
    ConfigDictField, ConfigurableField
from .transformFactory import makeTransform, makeIdentityTransform, \
    makeRadialTransform
__all__ = ["transformRegistry", "OneTransformConfig", "TransformConfig",
           "IdentityTransformConfig", "AffineTransformConfig", "RadialTransformConfig",
           "MultiTransformConfig"]
transformRegistry = makeRegistry(
    """"A registry of ``Transform`` factories
    A ``Transform`` factory is a function that obeys these rules:
    - has an attribute ``ConfigClass``
    - takes one argument, ``config`` (an instance of ``ConfigClass``) by name
    - returns a ``Transform``
    """
)
def identityFactory(config):
    """Make an identity ``Transform``
    """
    return makeIdentityTransform()
identityFactory.ConfigClass = IdentityTransformConfig
transformRegistry.register("identity", identityFactory)
def invertingFactory(config):
    """Invert a ``Transform`` specified by config.
    """
    return config.transform.apply().getInverse()
invertingFactory.ConfigClass = OneTransformConfig
transformRegistry.register("inverted", invertingFactory)
def affineFactory(config):
    """Make an affine ``Transform``
    """
    linear = numpy.array(config.linear)
    linear.shape = (2, 2)
    translation = numpy.array(config.translation)
    return makeTransform(lsst.geom.AffineTransform(linear, translation))
affineFactory.ConfigClass = AffineTransformConfig
transformRegistry.register("affine", affineFactory)
def radialFactory(config):
    """Make a radial ``Transform``
    """
    return makeRadialTransform(config.coeffs._list)
radialFactory.ConfigClass = RadialTransformConfig
transformRegistry.register("radial", radialFactory)
def multiFactory(config):
    """Concatenate multiple ``Transforms``
    """
    transformKeys = sorted(config.transformDict.keys())
    transformList = [config.transformDict[key].transform.apply()
                     for key in transformKeys]
    # Can't use then(self, other) directly because no single Transform class
    def concat(transform1, transform2):
        return transform1.then(transform2)
    return functools.reduce(concat, transformList)
multiFactory.ConfigClass = MultiTransformConfig
transformRegistry.register("multi", multiFactory)