# -*- coding: utf-8 -*-
# Copyright (c) 2020-2021 Salvador E. Tropea
# Copyright (c) 2020-2021 Instituto Nacional de Tecnología Industrial
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
# Description: Implements a filter to rotate footprints.
#              This is inspired in JLCKicadTools by Matthew Lai.
from re import compile
from .gs import GS
from .optionable import Optionable
from .error import KiPlotConfigurationError
from .macros import macros, document, filter_class  # noqa: F401
from . import log

logger = log.get_logger()


# Known rotations for JLC
DEFAULT_ROTATIONS = [["^R_Array_Convex_", 90.0],
                     ["^R_Array_Concave_", 90.0],
                     ["^SOT-223", 180.0],
                     ["^SOT-23", 180.0],
                     ["^TSOT-23", 180.0],
                     ["^SOT-353", 180.0],
                     ["^QFN-", 270.0],
                     ["^LQFP-", 270.0],
                     ["^TQFP-", 270.0],
                     ["^SOP-(?!18_)", 270.0],
                     ["^TSSOP-", 270.0],
                     ["^DFN-", 270.0],
                     ["^SOIC-", 270.0],
                     # ["^SOP-18_", 0],
                     ["^VSSOP-10_", 270.0],
                     ["^CP_EIA-3216-18_", 180.0],
                     ["^CP_EIA-3528-15_AVX-H", 180.0],
                     ["^CP_EIA-3528-21_Kemet-B", 180.0],
                     ["^CP_Elec_8x10.5", 180.0],
                     ["^CP_Elec_6.3x7.7", 180.0],
                     ["^CP_Elec_8x6.7", 180.0],
                     ["^CP_Elec_8x10", 180.0],
                     ["^(.*?_|V)?QFN-(16|20|24|28|40)(-|_|$)", 270.0],
                     ["^Bosch_LGA-8_2x2.5mm_P0.65mm_ClockwisePinNumbering", 90.0],
                     ["^PowerPAK_SO-8_Single", 270.0],
                     ["^HTSSOP-28-1EP_4.4x9.7mm*", 270.0],
                     ]


@filter_class
class Rot_Footprint(BaseFilter):  # noqa: F821
    """ Rot_Footprint
        This filter can rotate footprints, used for the positions file generation.
        Some manufacturers use a different rotation than KiCad.
        The internal `_rot_footprint` filter implements the simplest case """
    def __init__(self):
        super().__init__()
        self._is_transform = True
        with document:
            self.extend = True
            """ Extends the internal list of rotations with the one provided.
                Otherwise just use the provided list """
            self.negative_bottom = True
            """ Rotation for bottom components is computed via subtraction as `(component rot - angle)` """
            self.invert_bottom = False
            """ Rotation for bottom components is negated, resulting in either: `(- component rot - angle)`
                or when combined with `negative_bottom`, `(angle - component rot)` """
            self.rotations = Optionable
            """ [list(list(string))] A list of pairs regular expression/rotation.
                Components matching the regular expression will be rotated the indicated angle """
            self.skip_bottom = False
            """ Do not rotate components on the bottom """
            self.skip_top = False
            """ Do not rotate components on the top """

    def config(self, parent):
        super().config(parent)
        self._rot = []
        if isinstance(self.rotations, list):
            for r in self.rotations:
                if len(r) != 2:
                    raise KiPlotConfigurationError("Each regex/angle pair must contain exactly two values, not {} ({})".
                                                   format(len(r), r))
                regex = compile(r[0])
                try:
                    angle = float(r[1])
                except ValueError:
                    raise KiPlotConfigurationError("The second value in the regex/angle pairs must be a number, not {}".
                                                   format(r[1]))
                self._rot.append([regex, angle])
        if self.extend:
            for regex_str, angle in DEFAULT_ROTATIONS:
                self._rot.append([compile(regex_str), angle])
        if not self._rot:
            raise KiPlotConfigurationError("No rotations provided")

    def filter(self, comp):
        """ Apply the rotation """
        if (self.skip_top and not comp.bottom) or (self.skip_bottom and comp.bottom):
            # Component should be excluded
            return
        for regex, angle in self._rot:
            if regex.search(comp.footprint):
                old_angle = comp.footprint_rot
                if self.negative_bottom and comp.bottom:
                    comp.footprint_rot -= angle
                else:
                    comp.footprint_rot += angle
                if self.invert_bottom and comp.bottom:
                    comp.footprint_rot = -comp.footprint_rot
                comp.footprint_rot = comp.footprint_rot % 360
                if GS.debug_level > 2:
                    logger.debug('Rotating ref: {} {}: {} -> {}'.
                                 format(comp.ref, comp.footprint, old_angle, comp.footprint_rot))
                return
