#!/usr/bin/env python
# coding=utf-8
#
# Copyright (C) 2009 Aurelio A. Heckert, aurium (a) gmail dot com
#
# 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; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
"""
Interpolation of attributes in selected objects or group's children.
"""

import inkex

class InterpAttG(inkex.EffectExtension):
    """
    This effect applies a value for any interpolatable attribute for all
    elements inside the selected group or for all elements in a multiple selection.
    """
    def __init__(self):
        super(InterpAttG, self).__init__()
        self.arg_parser.add_argument(
            "-a", "--att", type=str, dest="att", default="fill",
            help="Attribute to be interpolated.")
        self.arg_parser.add_argument(
            "-o", "--att-other", type=str, dest="att_other",
            help="Other attribute (for a limited UI).")
        self.arg_parser.add_argument(
            "-t", "--att-other-type", type=str, dest="att_other_type",
            help="The other attribute type.")
        self.arg_parser.add_argument(
            "-w", "--att-other-where", type=str, dest="att_other_where",
            help="That is a tag attribute or a style attribute?")
        self.arg_parser.add_argument(
            "-s", "--start-val", type=str, dest="start_val", default="#F00",
            help="Initial interpolation value.")
        self.arg_parser.add_argument(
            "-e", "--end-val", type=str, dest="end_val", default="#00F",
            help="End interpolation value.")
        self.arg_parser.add_argument(
            "-u", "--unit", type=str, dest="unit", default="color",
            help="Values unit.")
        self.arg_parser.add_argument(
            "--zsort", type=inkex.Boolean, dest="zsort", default=True,
            help="use z-order instead of selection order")
        self.arg_parser.add_argument(
            "--tab", type=str, dest="tab",
            help="The selected UI-tab when OK was pressed")

    def get_color_steps(self, total):
        """Get the color value, returning the start color and a single increment step"""
        start_value = inkex.Color(self.options.start_val)
        end_value = inkex.Color(self.options.end_val)

        color_inc = [
            (end_value[v] - start_value[v]) / float(total - 1)
            for v in range(3)]

        return start_value, color_inc

    def get_number_steps(self, total):
        """Get the number value, returning the start float and a single increment step"""
        start_value = self.options.start_val.replace(",", ".")
        end_value = self.options.end_val.replace(",", ".")
        unit = self.options.unit

        if unit != 'none':
            start_value = self.svg.unittouu(start_value + unit)
            end_value = self.svg.unittouu(end_value + unit)

        try:
            start_value = float(start_value)
            end_value = float(end_value)
        except ValueError:
            inkex.errormsg(
                _("Bad values for a number field: {}, {}.".format(start_value, end_value)))
            return 0, 0

        val_inc = (end_value - start_value) / float(total - 1)
        return start_value, val_inc

    def get_elements(self):
        """Returns a list of elements to work on"""
        if not self.svg.selection:
            return []

        if len(self.svg.selection) > 1:
            # multiple selection
            if self.options.zsort:
                return list(self.svg.selection.paint_order().values())
            return list(self.svg.selected.values())

        # must be a group
        node = self.svg.selection.filter(inkex.Group).first()
        return list(node) or []

    def effect(self):
        if self.options.att == 'other':
            if self.options.att_other is not None:
                inte_att = self.options.att_other
            else:
                inkex.errormsg(_("You selected 'Other'. Please enter an attribute to interpolate."))
                return

            inte_att_type = self.options.att_other_type
            where = self.options.att_other_where
        else:
            inte_att = self.options.att
            inte_att_type = 'float'
            if inte_att in ('width', 'height'):
                where = 'tag'
            elif inte_att in ('scale', 'trans-x', 'trans-y'):
                where = 'transform'
            elif inte_att == 'opacity':
                where = 'style'
            elif inte_att in ('fill', 'stroke'):
                inte_att_type = 'color'
                where = 'style'

        collection = self.get_elements()

        if not collection:
            inkex.errormsg(_('There is no selection to interpolate'))
            return False

        if inte_att_type == 'color':
            cur, inc = self.get_color_steps(len(collection))
        else:
            cur, inc = self.get_number_steps(len(collection))

        for node in collection:
            if inte_att_type == 'color':
                val = inkex.Color([int(cur[i]) for i in range(3)])
            elif inte_att_type == 'float':
                val = cur
            elif inte_att_type == 'int':
                val = int(round(cur))
            else:
                raise KeyError("Unknown attr type: {}".format(inte_att_type))

            if where == 'style':
                node.style[inte_att] = str(val)
            elif where == 'transform':
                if inte_att == 'trans-x':
                    node.transform.add_translate(val, 0)
                elif inte_att == 'trans-y':
                    node.transform.add_translate(0, val)
                elif inte_att == 'scale':
                    node.transform.add_scale(val)
            elif where == 'tag':
                node.set(inte_att, str(val))
            else:
                raise KeyError("Unknown update {}".format(where))

            if inte_att_type == 'color':
                cur = [cur[i] + inc[i] for i in range(3)]
            else:
                cur += inc

        return True

if __name__ == '__main__':
    InterpAttG().run()
