# Just for initialization.
default rule_page = 1

# After removing the header of the page, how much size does it remain for our rules.
define max_y_rules = {"corporal":600,"public":580,"uniform":630,"hm":650,"other":850}

# What are the different points category that can be used for a rule requirement.
define prop_points_accepted = ["influence","discipline","popularity","horniness","grades"]

init python:

    """
        █████████████████████████████████████████████████████████████████████████████
        ██                                                                         ██
        ██  ███████╗ ██╗   ██╗ ███╗   ███╗ ███╗   ███╗  █████╗  ██████╗  ██╗   ██╗ ██
        ██  ██╔════╝ ██║   ██║ ████╗ ████║ ████╗ ████║ ██╔══██╗ ██╔══██╗ ╚██╗ ██╔╝ ██
        ██  ███████╗ ██║   ██║ ██╔████╔██║ ██╔████╔██║ ███████║ ██████╔╝  ╚████╔╝  ██
        ██  ╚════██║ ██║   ██║ ██║╚██╔╝██║ ██║╚██╔╝██║ ██╔══██║ ██╔══██╗   ╚██╔╝   ██
        ██  ███████║ ╚██████╔╝ ██║ ╚═╝ ██║ ██║ ╚═╝ ██║ ██║  ██║ ██║  ██║    ██║    ██
        ██  ╚══════╝  ╚═════╝  ╚═╝     ╚═╝ ╚═╝     ╚═╝ ╚═╝  ╚═╝ ╚═╝  ╚═╝    ╚═╝    ██
        ██                                                                         ██
        █████████████████████████████████████████████████████████████████████████████

    ###########################

    Rules declaration:

        - uniform1
        - uniform2
        - pp_modest
        - pp_underwear
        - pp_minimal
        - dress1
        - dress2
        - mens_proposed
        - men_cp
        - topless_punish
        - body_search
        - locker_room_unlocked
        - maxine_fundraiser_start
        - lake_acc
        - lake_acc
        - nudist_beach_open

    ###########################

    Classes :

        - create_rule_variables()  function
        - search_rule(flag)        function
        - new_rule                 class

    ###########################

    Screens :

        - screen_page_rule(pages)
        - display_rule(rule)
        - to_rule_them_all(cat, rules_to_show = [], rules_to_show_per_page = [0])
        - screen_rule()

    ###########################

    Composites :

        - prop_footer_all(rule)
        - prop_footer_spe(**points)
        - prop_footer(rule,first_color = "#000", second_color = "#fff", style = "board_prop")
        - prop_footer_hover(rule)
        - prop_footer_disabled(rule)
        - prop_imagebutton(rule)

    ###########################

    Functions :

        - size_rules_to_show(cat)
        - nb_rules_to_show(r_size,cat)
        - get_all_rule_size()


    """

###################################################################################################################################################
#                                                                                                                                                 #
#  ██████╗ ██╗   ██╗██╗     ███████╗███████╗    ██████╗ ███████╗ ██████╗██╗      █████╗ ██████╗  █████╗ ████████╗██╗ ██████╗ ███╗   ██╗███████╗   #
#  ██╔══██╗██║   ██║██║     ██╔════╝██╔════╝    ██╔══██╗██╔════╝██╔════╝██║     ██╔══██╗██╔══██╗██╔══██╗╚══██╔══╝██║██╔═══██╗████╗  ██║██╔════╝   #
#  ██████╔╝██║   ██║██║     █████╗  ███████╗    ██║  ██║█████╗  ██║     ██║     ███████║██████╔╝███████║   ██║   ██║██║   ██║██╔██╗ ██║███████╗   #
#  ██╔══██╗██║   ██║██║     ██╔══╝  ╚════██║    ██║  ██║██╔══╝  ██║     ██║     ██╔══██║██╔══██╗██╔══██║   ██║   ██║██║   ██║██║╚██╗██║╚════██║   #
#  ██║  ██║╚██████╔╝███████╗███████╗███████║    ██████╔╝███████╗╚██████╗███████╗██║  ██║██║  ██║██║  ██║   ██║   ██║╚██████╔╝██║ ╚████║███████║   #
#  ╚═╝  ╚═╝ ╚═════╝ ╚══════╝╚══════╝╚══════╝    ╚═════╝ ╚══════╝ ╚═════╝╚══════╝╚═╝  ╚═╝╚═╝  ╚═╝╚═╝  ╚═╝   ╚═╝   ╚═╝ ╚═════╝ ╚═╝  ╚═══╝╚══════╝   #
###################################################################################################################################################

init:

    $ rules = []

#####################################

    rule "uniform1":

        type "uniform"

        points:
            influence 4
            discipline 18

        name "Uniform Inspections"

        text "Strict Uniform Policy - Teachers are permitted to request a full uniform inspection at any time. Students must raise their skirts when told to prove they are wearing regulation underwear.{#board_agenda}"
        text2  "Students in breach of the rules should be given an opportunity to go and change.{#board_agenda}"
        action "uniform_proposal1"

#####################################

    rule "uniform2":

        type "uniform"

        points:
            influence 6
            discipline 30

        preconditions:
            uniform2_unlocked

        name "Can Confiscate Non-regulation clothing"

        text "Very Strict Uniform Policy - Teachers are permitted to request a full uniform inspection at any time. Students must raise their skirts when told to prove they are wearing regulation underwear.{#board_agenda}"
        text2 "Any articles of clothing in breach of the uniform policy may be immediately confiscated by a teacher or prefect.{#board_agenda}"
        action "uniform_proposal2"

#####################################

    rule "pp_modest":

        type "public"

        points:
            influence 4
            discipline 25

        name "Girls must clean the school grounds in a punishment outfit"

        text "Students cleaning the school grounds should be made to wear a punishment outfit so that they are more easily identifiable."
        action "pp_proposal1"

#####################################

    rule "pp_underwear":

        type "public"

        points:
            influence 10
            discipline 55

        preconditions:
            chapter2

        extra:
            conditions:
                men_cp
            text "{i}n.b.{i} Discipline is capped at 50 until you can punish the girls yourself."

        name "Girls must clean the school grounds in their underwear"

        text "Students may be ordered to strip down to their underwear for public punishment, and will have the school's initials written on their chest with non-permanent marker.{#board_agenda}"
        action "pp_proposal2"
  
#####################################

    rule "pp_minimal":  # this rule doesn't have an agenda entry, it is passed in fundraiser.rpy
        
        type "public"

        points:
            influence 12
            discipline 85

        preconditions:
            maxine_fundraiser_seen

        name "Girls must clean the school grounds in their underwear or the minimal uniform"

        text "At the headmaster's discretion for public punishment, students may be ordered to wear the minimal uniform, or to strip down to their underwear or to wear the minimal uniform and have the school's initials written on their chest with non-permanent marker.{#board_agenda}"
        action "pp_proposal2"      

#####################################

    rule "dress1":

        type "corporal"

        points:
            influence 4
            discipline 25

        preconditions:
            sally_quest_started
            undress_rule == 0

        undress_rule 1

        name "Remove skirts for punishment"

        text "Students may be ordered to remove shoes, ties and cardigans. In addition, skirts may be removed if considered an obstruction."
        action "skirts_removal"

#####################################

    rule "dress2":

        type "corporal"

        points:
            influence 10
            discipline 55

        preconditions:
            undress_rule3_available
            undress_rule == 1

        extra:
            conditions:
                men_cp
            text "{i}n.b.{i} Discipline is capped at 50 until you can punish the girls yourself."

        undress_rule 2

        name "Remove shirts for punishment"

        text "Students may be ordered to strip down to their underwear for corporal punishment."
        action "shirts_removal"

#####################################

    rule "mens_proposed":

        type "corporal"

        points:
            influence ?
            discipline ?

        preconditions:
            board3_done

        name "Men can perform coporal punishment"

        text "Corporal punishments may be carried out on students by any teacher, regardless of gender.{#board_agenda}"
        action "men1_proposal"

#####################################

    rule "men_cp":

        type "corporal"

        points:
            influence 9
            discipline 40

        preconditions:
            mens_proposed

        extra:
            text "{i}n.b.{i} You must complete Sally's and Ruth's quests, otherwise they will block this proposal."
            conditions:
                sally_feels and ruth_ba2

        name "Men can perform coporal punishment"

        text "Corporal punishments may be carried out on students by any teacher, regardless of gender.{#board_agenda}"
        text2 "Increases maximum Grades and Discipline to 100."
        action "mc_unlocked"

#####################################

    rule "topless_punish":

        type "public"

        points:
            influence 11
            discipline 75

        preconditions:
            chapter2_class_intro

        name "Topless in class punishment"

        text "Students misbehaving during class may be ordered to remove all clothing above the waist for the remainder of the lesson."
        action "board_class_topless"

#####################################

    rule "body_search":

        type "hm"

        points:
            influence 11
            discipline 80

        preconditions:
            board_weed_discussed

        name "Body search rule"

        text "The headmaster has the right to perform a body search of anyone on campus. Students must raise their skirts and open their blouses to allow for easy access to their underwear.{#board_agenda}"
        action "board_body_search"

#####################################

    rule "locker_room_unlocked":

        type "hm"

        points:
            influence 12
            discipline 85

        preconditions:
            locker_incident_discussed

        name "Girls' Locker Room Access"

        text "The headmaster will be permitted to patrol the female sports locker room area at any time.{#board_agenda}"
        action "locker_room_unlock"


#####################################

    rule "maxine_fundraiser_start":

        type "uniform"

        points:
            horniness 14
            influence 12
            discipline 85

        preconditions:
            maxine_fundraiser_board_meeting

        name "Charity Exemptions"

        text "Charity Exemptions - Girls will be permitted to wear clothing other than their regular uniforms during school hours, as part of an approved charity fundraiser.{#board_agenda}"
        text2 "{i}Enacting this rule will start Maxine's fundraiser on the next Monday morning{/i}.{#board_agenda}"

        action "maxine_fundraiser_board_unlock"

#####################################

    rule "lake_acc":

        type "other"

        name "Lake Access"

        title "Lake Access"

        toggle False

        text "Access to the lake is forbidden."

        button "Open the Lake"

        action "lake_access"

#####################################

    rule "lake_acc":

        type "other"

        name "Lake Access"

        title "Lake Access"

        toggle True

        text "Access to the lake is permitted. Students swim in the lake at their own risk."

        button "Close the Lake"

        action "lake_access"

#####################################

    rule "nudist_beach_open":

        type "other"

        preconditions:
            sally_emily2

        name "Open Nudist Beach"

        text "In support of the nudism lifestyle, a clothing-optional area of the beach will be designated.{#board_agenda}"

        action "nudist_rule"



##############################################################
#                                                            #
#   ██████╗██╗      █████╗ ███████╗███████╗███████╗███████╗  #
#  ██╔════╝██║     ██╔══██╗██╔════╝██╔════╝██╔════╝██╔════╝  #
#  ██║     ██║     ███████║███████╗███████╗█████╗  ███████╗  #
#  ██║     ██║     ██╔══██║╚════██║╚════██║██╔══╝  ╚════██║  #
#  ╚██████╗███████╗██║  ██║███████║███████║███████╗███████║  #
#   ╚═════╝╚══════╝╚═╝  ╚═╝╚══════╝╚══════╝╚══════╝╚══════╝  #
##############################################################


init -100 python:

    def create_rule_variables():
        for rule in rules:
            if not hasattr(store,rule.flag):
                setattr(store,rule.flag,False)

    # To find a rule. Give the flag you want to search as a string.
    def search_rule(flag):
        for rule in rules:
            if rule.flag == flag:
                return rule
        return False


    # Our rule class (Yes I named it new_rule since I hadn't deleted the class rule while testing it and now I'm too lazy to modify it.)
    class new_rule():

        def __init__(self, rule_type, rule_flag, rule_action, rule_name, rule_text, rule_points, rule_text2="", rule_extra="",rule_preconditions = [], rule_undress_rule = False, rule_button="VOTE", rule_toggle = None, rule_title = ""):

            self.type     = rule_type
            self.flag     = rule_flag
            self.name     = rule_name
            self.action   = rule_action
            self.text     = rule_text
            self.text2    = rule_text2
            self.button   = rule_button
            self.toggle   = rule_toggle
            self.title    = rule_title

            for i in rule_points:
                if rule_points[i]!="?":
                    rule_points[i] = int(rule_points[i])

            self.points        = rule_points
            self.preconditions = rule_preconditions
            self.extra         = rule_extra
            self.undress_rule  = rule_undress_rule

            return

        # Are all the preconditions True and is the rule not already passed ? If yes, then the rule can be shown in the school board
        @property
        def ready_to_discuss(self):
            return self.preconditions_ok and not self.is_passed

        # This one is simple to comprehend, just read its name.
        @property
        def preconditions_ok(self):
            for i in self.preconditions:
                try:
                    if not eval(i):
                        return False
                except (SyntaxError, NameError, TypeError, ZeroDivisionError): return False
            return True

        # Same here.
        @property
        def extra_cond_ok(self):
            if self.extra:
                for i in self.extra["conditions"]:
                    try:
                        if not eval(i):
                            return False
                    except (SyntaxError, NameError, TypeError, ZeroDivisionError): return False
            return True

        # Same here. Note that a "?" point type is automatically True.
        @property
        def points_ok(self):
            for i in self.points:
                if self.points[i] != "?" and globals()[i] < self.points[i]:
                    return False
            return True

        # Is this rule already have been voted and passed ?
        @property
        def is_passed(self):
            global undress_rule
            if self.undress_rule:
                return self.undress_rule <= undress_rule
            if hasattr(renpy.store,self.flag):
                return globals()[self.flag] != self.toggle
            return False

        # Checks if the rule can be voted. If the extra conditions and the points are ok, then yes.
        @property
        def all_requirements(self):
            return self.points_ok and self.extra_cond_ok

        # Checks if the rule has conditions. Useful only to know if the rule has to displayed "Requirements:". (For now it just checks if the rules requires points)
        # Maybe checks for extra and shows the extra text below "requirements:" ?
        @property
        def has_requirements(self):
            for i in self.points:
                if self.points[i]:
                    return True
            return False



################################################################
#                                                              #
#  ███████╗ ██████╗██████╗ ███████╗███████╗███╗   ██╗███████╗  #
#  ██╔════╝██╔════╝██╔══██╗██╔════╝██╔════╝████╗  ██║██╔════╝  #
#  ███████╗██║     ██████╔╝█████╗  █████╗  ██╔██╗ ██║███████╗  #
#  ╚════██║██║     ██╔══██╗██╔══╝  ██╔══╝  ██║╚██╗██║╚════██║  #
#  ███████║╚██████╗██║  ██║███████╗███████╗██║ ╚████║███████║  #
#  ╚══════╝ ╚═════╝╚═╝  ╚═╝╚══════╝╚══════╝╚═╝  ╚═══╝╚══════╝  #
################################################################



# This screen displays the number of pages for a category in the school board.
screen screen_page_rule(pages):
    if rule_page - 1:
        textbutton "{b}<=={/b}" style "hand_nav" xpos 970 ypos 970 action [SetVariable("rule_page",rule_page-1)]
    textbutton "{b}" + str(rule_page) + " of " + str(pages) + "{/b}" xcenter 1280 ypos 970 style "hand_nav"
    if rule_page - 1 != pages - 1:
        textbutton "{b}==>{/b}" style "hand_nav" xpos 1520 ypos 970 action [SetVariable("rule_page",rule_page+1)]


# This screen, like its name indicates, displays a rule on the screen.
screen display_rule(rule):
    vbox:
        xmaximum 640
        spacing 10

        if rule.title:
            text __(rule.title) style "board_header"
        text "Proposal" style "board_header"
        text __(rule.text) style "prop_text"

        if rule.text2:
            text __(rule.text2) style "prop_text"

        if rule.extra and not rule.extra_cond_ok:
            text __(rule.extra["text"]) style "prop_text"

        if rule.has_requirements:
            text "Requirements" style "board_header"

        hbox:
            xfill True
            add prop_footer_all(rule) xalign 0.0

            $ prop_button = prop_imagebutton(rule)

            if prop_button["idle"]:
                imagebutton:
                    xalign 1.0
                    xoffset -30
                    idle (prop_button["idle"])
                    if prop_button["active"] == True:
                       hover (prop_button["hover"])
                       action Jump(rule.action)
        add "screens/divider5.png"


# This screen displays n rules on the screen, n being the number of rules that can be displayed at the same time.
# Before calling it, you have to calculate these numbers by calling size_rules_to_show(cat) and giving the two values returned as arguments of this screens.
screen to_rule_them_all(rules_to_show = [], rules_to_show_per_page = [0]):

    for i in range(rules_to_show_per_page[rule_page-1]):
        $ rule = rules_to_show[i+sum(rules_to_show_per_page[0:rule_page-1])]
        use display_rule(rule)


# This screen is only useful to calculate the y size of all rules (used in get_all_rule_size() function).
screen screen_rule():
    for rule in rules:
        use display_rule(rule)



#######################################################################################
#                                                                                     #
#   ██████╗ ██████╗ ███╗   ███╗██████╗  ██████╗ ███████╗██╗████████╗███████╗███████╗  #
#  ██╔════╝██╔═══██╗████╗ ████║██╔══██╗██╔═══██╗██╔════╝██║╚══██╔══╝██╔════╝██╔════╝  #
#  ██║     ██║   ██║██╔████╔██║██████╔╝██║   ██║███████╗██║   ██║   █████╗  ███████╗  #
#  ██║     ██║   ██║██║╚██╔╝██║██╔═══╝ ██║   ██║╚════██║██║   ██║   ██╔══╝  ╚════██║  #
#  ╚██████╗╚██████╔╝██║ ╚═╝ ██║██║     ╚██████╔╝███████║██║   ██║   ███████╗███████║  #
#   ╚═════╝ ╚═════╝ ╚═╝     ╚═╝╚═╝      ╚═════╝ ╚══════╝╚═╝   ╚═╝   ╚══════╝╚══════╝  #
#######################################################################################

init -3 python:

    # Returns a composite that contains all the points requirements for the rule.
    def prop_footer_all(rule):
        size_c = (0,70)
        img = Composite(size_c)
        j = 0
        for i in prop_points_accepted:
            if rule.points[i]:
                size_c = (size_c[0] + 136,size_c[1])
                p = Text(str(rule.points[i]),style="board_prop")
                img = Composite(size_c,(0,0),img,(j,0),"screens/prop_"+i+".png",(j+92-int(p.size()[0]/2),12),p)
                j+=136
        return img


    # Create a temporary rule that needs the points you gave as argument to return the composite of the points (see above)
    def prop_footer_spe(**points): # Takes for arguments elements of prop_points_accepted constant above.
        return prop_footer_all(new_rule("","","","","",{x:(points[x] if x in points else 0) for x in prop_points_accepted}))


    # Return the "VOTE" button composite (of course it's not "vote" if you write another value in the rule declaration).
    def prop_footer(rule,first_color = "#000", second_color = "#fff", style = "board_prop"):
        size_c = (600,70)
        my_button = center_text_composite( ("+10",37), Solid(first_color), __(rule.button), "center", "center", style=style)
        sizes = (get_size(my_button)[0]+18,get_size(my_button)[1]+18)
        return Composite( sizes, (0,0), Solid(second_color),
                                 (3,3), Solid(first_color,xsize=sizes[0]-6,ysize=sizes[1]-6),
                                 (6,6), Solid(second_color,xsize=sizes[0]-12,ysize=sizes[1]-12),
                                 (9,9),my_button)


    # The inverted color "VOTE" button (it just calls the function above with different colors)
    def prop_footer_hover(rule):
        return prop_footer(rule,first_color = "#fff", second_color = "#000", style = "board_prop_hover")


    # no vote button (Is it really necessary to have this function ? No, But once more I'm too lazy to remove it.)
    def prop_footer_disabled(rule):
        return prop_footer_all(rule)


    # Returns the values for the imagebutton of the rule. (I don't think this is necessary anymore. Maybe I'll made the modifications later.)
    def prop_imagebutton(rule):

        if not rule.extra_cond_ok:
            return { "idle" : False,
                     "active" : False }

        if not rule.points_ok:
        # not enough influence or discipline to vote, or some other condition
            return { "idle" : prop_footer(rule),
                    "active" : False}

        # ready to vote
        return {"idle" : prop_footer(rule),
                "hover" : prop_footer_hover(rule),
                "active" : True
                }



################################################################################
#                                                                              #
#  ███████╗██╗   ██╗███╗   ██╗ ██████╗████████╗██╗ ██████╗ ███╗   ██╗███████╗  #
#  ██╔════╝██║   ██║████╗  ██║██╔════╝╚══██╔══╝██║██╔═══██╗████╗  ██║██╔════╝  #
#  █████╗  ██║   ██║██╔██╗ ██║██║        ██║   ██║██║   ██║██╔██╗ ██║███████╗  #
#  ██╔══╝  ██║   ██║██║╚██╗██║██║        ██║   ██║██║   ██║██║╚██╗██║╚════██║  #
#  ██║     ╚██████╔╝██║ ╚████║╚██████╗   ██║   ██║╚██████╔╝██║ ╚████║███████║  #
#  ╚═╝      ╚═════╝ ╚═╝  ╚═══╝ ╚═════╝   ╚═╝   ╚═╝ ╚═════╝ ╚═╝  ╚═══╝╚══════╝  #
################################################################################



    # This function returns all the rules in the "cat" category, and a list of numbers, that are the number of rules that can be displayed on each page.
    def size_rules_to_show(cat):
        r = []
        r_size = []
        sizes = get_all_rule_size()
        for i in range(len(rules)):
            rule = rules[i]
            if not rule.is_passed and rule.preconditions_ok and rule.type == cat:
                r.append(rule)
                r_size.append(sizes[i])
        return r, nb_rules_to_show(r_size,cat)


    # This function calculates how many rules will be displayed on each page, given their sizes. Only useful for size_rules_to_show function.
    def nb_rules_to_show(r_size,cat):
        nb_rules = []
        a = 0

        for i in range(len(r_size)):
            a += r_size[i][1]
            if a > max_y_rules[cat]:
                if not nb_rules:
                    nb_rules.append(i)
                else:
                    nb_rules.append(i-sum(nb_rules))
                a = r_size[i][1]
        if len(r_size):
            if not nb_rules:
                nb_rules.append(i+1)
            elif i+1-sum(nb_rules):
                nb_rules.append(i+1-sum(nb_rules))
        return nb_rules or [0]


    # This function calculate for each rules their y sizes.
    # How it works : We create a screen that will never be displayed but contains all the rules on it.
    #                We update it because just creating it doesn't calculate the size of each displayables
    #                We find the values by navigating in the children of the screen
    def get_all_rule_size():
        sizes = []
        my_rule_screen = renpy.display.screen.ScreenDisplayable(renpy.display.screen.get_screen_variant("screen_rule"),"tag_test","screens")
        my_rule_screen.update()
        for i in my_rule_screen.children[0].children: # <- all vbox
            sizes.append(get_size(i))
        return sizes
