import pygarment as pyg
from assets.garment_programs.circle_skirt import CircleArcPanel
from assets.garment_programs import skirt_paneled
from assets.garment_programs.base_classes import BaseBand

class StraightBandPanel(pyg.Panel):
    """One panel for a panel skirt"""

    def __init__(self, name, width, depth, match_int_proportion=None) -> None:
        super().__init__(name)

        # define edge loop
        self.edges = pyg.EdgeSeqFactory.from_verts(
            [0, 0], [0, depth], [width, depth], [width, 0], loop=True)

        # define interface
        self.interfaces = {
            'right': pyg.Interface(self, self.edges[0]),
            'top': pyg.Interface(self, 
                                 self.edges[1], 
                                 ruffle=width / match_int_proportion if match_int_proportion is not None else 1.
                                 ).reverse(True),
            'left': pyg.Interface(self, self.edges[2]),
            'bottom': pyg.Interface(self, 
                                    self.edges[3], 
                                    ruffle=width / match_int_proportion if match_int_proportion is not None else 1.
                                    )
        }

        # Default translation
        self.top_center_pivot()
        self.center_x()


class StraightWB(BaseBand):
    """Simple 2 panel waistband"""
    def __init__(self, body, design, rise=1.) -> None:
        """Simple 2 panel waistband

            * rise -- the rise value of the bottoms that the WB is attached to 
                Adapts the shape of the waistband to sit tight on top 
                of the given rise level (top measurement). If 1. or anything less than waistband width, 
                the rise is ignored and the StraightWB is created to sit well on the waist
        
        """
        super().__init__(body, design, rise=rise)

        # Measurements
        self.waist = design['waistband']['waist']['v'] * body['waist']
        self.waist_back_frac = body['waist_back_width'] / body['waist']
        self.hips = body['hips'] * design['waistband']['waist']['v']
        self.hips_back_frac = body['hip_back_width'] / body['hips']

        # Params
        self.width = design['waistband']['width']['v'] 
        self.rise = rise
        # Check correct values
        if self.rise + self.width > 1:
            self.rise = 1 - self.width

        self.top_width = pyg.utils.lin_interpolation(
            self.hips, self.waist, self.rise + self.width)
        self.top_back_fraction = pyg.utils.lin_interpolation(
            self.hips_back_frac, self.waist_back_frac, self.rise + self.width)
        
        self.width = self.width * body['hips_line']

        self.define_panels()

        self.front.translate_by([0, body['_waist_level'] + 10, 20])
        self.back.translate_by([0, body['_waist_level'] + 10, -20]) 
        
        self.stitching_rules = pyg.Stitches(
            (self.front.interfaces['right'], self.back.interfaces['right']),
            (self.front.interfaces['left'], self.back.interfaces['left'])
        )

        self.interfaces = {
            'bottom_f': self.front.interfaces['bottom'],  
            'bottom_b': self.back.interfaces['bottom'],

            'top_f': self.front.interfaces['top'],
            'top_b': self.back.interfaces['top'],

            'bottom': pyg.Interface.from_multiple(
                self.front.interfaces['bottom'],
                self.back.interfaces['bottom']),
            'top': pyg.Interface.from_multiple(
                self.front.interfaces['top'], 
                self.back.interfaces['top']),
        }

    def define_panels(self):
        back_width = self.top_width * self.top_back_fraction

        self.front = StraightBandPanel(
            'wb_front', 
            self.top_width - back_width, 
            self.width,
            match_int_proportion=self.body['waist'] - self.body['waist_back_width']
        )
          
        self.back = StraightBandPanel(
            'wb_back', 
            back_width, 
            self.width,
            match_int_proportion=self.body['waist_back_width']
        )


class FittedWB(StraightWB):
    """Also known as Yoke: a waistband that ~follows the body curvature,
            and hence sits tight
        Made out of two circular arc panels
    """
    def __init__(self, body, design, rise=1.) -> None:
        """A waistband that ~follows the body curvature, and hence sits tight
        
            * rise -- the rise value of the bottoms that the WB is attached to 
                Adapts the shape of the waistband to sit tight on top 
                of the given rise level. If 1. or anything less than waistband width, 
                the rise is ignored and the FittedWB is created to sit well on the waist
        """
        self.bottom_width = None
        self.bottom_back_fraction = None
        super().__init__(body, design, rise)

    def define_panels(self):
        self.bottom_width = pyg.utils.lin_interpolation(
            self.hips, self.waist, self.rise)
        self.bottom_back_fraction = pyg.utils.lin_interpolation(
            self.hips_back_frac, self.waist_back_frac, self.rise)
        
        self.front = CircleArcPanel.from_all_length(
            'wb_front', 
            self.width, 
            self.top_width * (1 - self.top_back_fraction), 
            self.bottom_width * (1 - self.bottom_back_fraction),
            match_top_int_proportion=self.body['waist'] - self.body['waist_back_width'],
            match_bottom_int_proportion=self.body['waist'] - self.body['waist_back_width']
        )
        
        self.back = CircleArcPanel.from_all_length(
            'wb_back', 
            self.width, 
            self.top_width * self.top_back_fraction, 
            self.bottom_width * self.bottom_back_fraction,
            match_top_int_proportion=self.body['waist_back_width'],
            match_bottom_int_proportion=self.body['waist_back_width']
        )


class CuffBand(BaseBand):
    """ Cuff class for sleeves or pants
        band-like piece of fabric with optional "skirt"
    """
    def __init__(self, tag, design, length=None) -> None:
        super().__init__(body=None, design=design, tag=tag)

        self.design = design['cuff']

        if length is None:
            length = self.design['cuff_len']['v']

        self.front = StraightBandPanel(
            f'{tag}_cuff_f', self.design['b_width']['v'] / 2, length)
        self.front.translate_by([0, 0, 15])  
        self.back = StraightBandPanel(
            f'{tag}_cuff_b', self.design['b_width']['v'] / 2, length)
        self.back.translate_by([0, 0, -15])  

        self.stitching_rules = pyg.Stitches(
            (self.front.interfaces['right'], self.back.interfaces['right']),
            (self.front.interfaces['left'], self.back.interfaces['left'])
        )

        self.interfaces = {
            'bottom': pyg.Interface.from_multiple(
                self.front.interfaces['bottom'], 
                self.back.interfaces['bottom']),
            'top_front': self.front.interfaces['top'],
            'top_back': self.back.interfaces['top'],
            'top': pyg.Interface.from_multiple(
                self.front.interfaces['top'], 
                self.back.interfaces['top']),
        }


class CuffSkirt(BaseBand):
    """A skirt-like flared cuff """

    def __init__(self, tag, design, length=None) -> None:
        super().__init__(body=None, design=design, tag=tag)

        self.design = design['cuff']
        width = self.design['b_width']['v']
        flare_diff = (self.design['skirt_flare']['v'] - 1) * width / 2

        if length is None:
            length = self.design['cuff_len']['v']

        self.front = skirt_paneled.SkirtPanel(
            f'{tag}_cuff_skirt_f', ruffles=self.design['skirt_ruffle']['v'], 
            waist_length=width / 2, length=length, 
            flare=flare_diff)
        self.front.translate_by([0, 0, 15])  
        self.back = skirt_paneled.SkirtPanel(
            f'{tag}_cuff_skirt_b', ruffles=self.design['skirt_ruffle']['v'], 
            waist_length=width / 2, length=length, 
            flare=flare_diff)
        self.back.translate_by([0, 0, -15])  

        self.stitching_rules = pyg.Stitches(
            (self.front.interfaces['right'], self.back.interfaces['right']),
            (self.front.interfaces['left'], self.back.interfaces['left'])
        )

        self.interfaces = {
            'top': pyg.Interface.from_multiple(
                self.front.interfaces['top'], self.back.interfaces['top']),
            'top_front': self.front.interfaces['top'],
            'top_back': self.back.interfaces['top'],
            'bottom': pyg.Interface.from_multiple(
                self.front.interfaces['bottom'], 
                self.back.interfaces['bottom']),
        }


class CuffBandSkirt(pyg.Component):
    """ Cuff class for sleeves or pants
        band-like piece of fabric with optional "skirt"
    """
    def __init__(self, tag, design) -> None:
        super().__init__(self.__class__.__name__)

        self.cuff = CuffBand(
            tag, 
            design, 
            length=design['cuff']['cuff_len']['v'] * (1 - design['cuff']['skirt_fraction']['v'])
        )
        self.skirt = CuffSkirt(
            tag, 
            design, 
            length=design['cuff']['cuff_len']['v'] * design['cuff']['skirt_fraction']['v']
        )

        # Align
        self.skirt.place_below(self.cuff)

        self.stitching_rules = pyg.Stitches(
            (self.cuff.interfaces['bottom'], self.skirt.interfaces['top']),
        )

        self.interfaces = {
            'top': self.cuff.interfaces['top'],
            'top_front': self.cuff.interfaces['top_front'],
            'top_back': self.cuff.interfaces['top_back'],
            'bottom': self.skirt.interfaces['bottom']
        }

    def length(self):
        return self.cuff.length() + self.skirt.length()