#!/usr/bin/env python

"""Launch a system to interactively create a character."""

import logging
import math
import os
from random import randint
import subprocess

import npyscreen

from dungeonsheets import character, race, dice, background, classes, weapons, armor

log = logging.getLogger(__name__)


def read_version():
    version = open(os.path.join(os.path.dirname(__file__), "../VERSION")).read()
    version = version.replace("\n", "")
    return version


char_classes = {c.name: c for c in classes.available_classes}

races = {r.name: r for r in race.available_races}

backgrounds = {b.name: b for b in background.available_backgrounds}

all_weapons = (
    weapons.simple_melee_weapons
    + weapons.martial_melee_weapons
    + weapons.simple_ranged_weapons
    + weapons.martial_ranged_weapons
)


class LinkedListForm(npyscreen.ActionForm):
    prev_page = None
    this_page = None
    next_page = None

    def __init__(self, formid, *args, **kwargs):
        self.this_page = formid
        super().__init__(*args, **kwargs)

    def to_next(self):
        self.parentApp.setNextForm(self.next_page)

    def to_prev(self):
        self.parentApp.setNextForm(self.prev_page)

    def add_next(self, next_name):
        new_next = self.parentApp.getForm(next_name)
        if self.next_page:
            current_next = self.parentApp.getForm(self.next_page)
            current_next.prev_page = next_name
        new_next.next_page = self.next_page
        new_next.prev_page = self.this_page
        self.next_page = next_name

    def add_prev(self, prev_name):
        new_prev = self.parentApp.getForm(prev_name)
        if self.prev_page:
            current_prev = self.parentApp.getForm(self.prev_page)
            current_prev.next_page = prev_name
        new_prev.prev_page = self.prev_page
        new_prev.next_page = self.this_page
        self.prev_page = prev_name

    def prune(self):
        if self.next_page:
            next_form = self.parentApp.getForm(self.next_page)
            next_form.prev_page = self.prev_page
        if self.prev_page:
            prev_form = self.parentApp.getForm(self.prev_page)
            prev_form.next_page = self.next_page
        self.parentApp.removeForm(self.this_page)


class App(npyscreen.NPSAppManaged):
    # STARTING_FORM = 'SKILLS'
    character = None
    n_classes = 1

    def save_character(self):
        # Save the file
        filename = self.getForm("SAVE").filename.value
        self.character.save(filename, template_file="empty_template.txt")
        # Create the PDF character sheet
        if self.getForm("SAVE").make_pdf.value:
            log.debug("Creating PDF")
            self.character.to_pdf(filename)
            subprocess.call(["makesheets", filename])

    def update_max_hp_roll(self):
        abil = self.getForm("ABILITIES")
        # Update max HP based on the class
        hit_dice = [dice.read_dice_str(d) for d in self.character.hit_dice.split(" + ")]
        const = int((int(abil.constitution.value) - 10) / 2)
        hp_max = f"{hit_dice[0].faces + self.character.level*const}"
        hds = {}
        for i, hd in enumerate(hit_dice):
            num = hd.num
            if i == 0:
                num -= 1
            if hd.faces not in hds:
                hds[hd.faces] = 0
            hds[hd.faces] += num
        for faces, num in hds.items():
            hp_max += f" + {num}d{faces}"
        abil.hp_roll_text.value = "Enter (or roll) your Max HP: " + hp_max
        abil.display()

    def reroll_max_hp(self):
        abil = self.getForm("ABILITIES")
        # Update max HP based on the class
        hit_dice = [dice.read_dice_str(d) for d in self.character.hit_dice.split(" + ")]
        const = int((int(abil.constitution.value) - 10) / 2)
        # Assume first hd given is from primary class
        hp_max = hit_dice[0].faces + const
        for i, hd in enumerate(hit_dice):
            num = hd.num
            if i == 0:
                num -= 1
            for d in range(num):
                hp_max += randint(1, hd.faces) + const
        abil.hp_max.value = str(hp_max)
        abil.display()

    def set_default_hp_max(self):
        abil = self.getForm("ABILITIES")
        # Update max HP based on the class
        hit_dice = [dice.read_dice_str(d) for d in self.character.hit_dice.split(" + ")]
        const = int((int(abil.constitution.value) - 10) / 2)
        # Assume first hd given is from primary class
        hp_max = hit_dice[0].faces + const
        for i, hd in enumerate(hit_dice):
            num = hd.num
            if i == 0:
                num -= 1
            for d in range(num):
                hp_max += math.ceil(hd.faces / 2) + const
        log.debug("Updating max hp: %d", hp_max)
        abil.hp_max.value = str(hp_max)
        abil.display()

    def onStart(self):
        self.character = character.Character()
        self.character.class_list = []
        self.addForm("MAIN", BasicInfoForm, name="Basic Info:", formid="MAIN")
        self.addForm(
            "RACE", RaceForm, name="Select your character's race:", formid="RACE"
        )
        self.addForm(
            "CLASS1",
            CharacterClassForm,
            name="Select your character's primary class:",
            formid="CLASS1",
        )
        self.addForm(
            "BACKGROUND", BackgroundForm, name="Choose background:", formid="BACKGROUND"
        )
        self.addForm(
            "ALIGNMENT",
            AlignmentForm,
            name="Select your character's alignment:",
            formid="ALIGNMENT",
        )
        self.addForm(
            "ABILITIES",
            AbilityScoreForm,
            name="Choose ability scores:",
            formid="ABILITIES",
        )
        self.addForm(
            "SKILLS", SkillForm, name="Choose skill proficiencies", formid="SKILLS"
        )
        self.addForm("WEAPONS", WeaponForm, name="Choose weapons", formid="WEAPONS")
        self.addForm("ARMOR", ArmorForm, name="Choose armor", formid="ARMOR")
        self.addForm(
            "PERSONALITY",
            PersonalityForm,
            name="Describe your character",
            formid="PERSONALITY",
        )
        self.addForm("SAVE", SaveForm, name="Save character:", formid="SAVE")

        # Initialized the DoublyLinkedList
        forms = [
            "MAIN",
            "RACE",
            "CLASS1",
            "BACKGROUND",
            "ALIGNMENT",
            "ABILITIES",
            "SKILLS",
            "WEAPONS",
            "ARMOR",
            "PERSONALITY",
            "SAVE",
        ]
        for i in range(len(forms) - 1):
            form = self.getForm(forms[i])
            form.add_next(forms[i + 1])


class BasicInfoForm(LinkedListForm):
    def create(self):
        self.name = self.add(
            npyscreen.TitleText, name="Character Name:", use_two_lines=False
        )
        self.player_name = self.add(
            npyscreen.TitleText, name="Player Name:", use_two_lines=False
        )

    def on_ok(self):
        # Update the default filename
        name = self.name.value or "New Character"
        if name == "":
            filename = "new_character.py"
        else:
            filename = f'{name.split(" ")[0].lower()}.py'
        save_form = self.parentApp.getForm("SAVE")
        save_form.filename.value = filename
        self.parentApp.character.name = self.name.value
        self.parentApp.character.player_name = self.player_name.value
        super().to_next()

    def on_cancel(self):
        raise KeyboardInterrupt


class RaceForm(LinkedListForm):
    def create(self):
        self.race = self.add(
            npyscreen.TitleSelectOne, name="Race:", values=tuple(races.keys())
        )

    def on_ok(self):
        if len(self.race.get_selected_objects()) >= 1:
            selected_race = self.race.get_selected_objects()[0]
            SelectedRace = races[selected_race]
            log.debug("Selected character race: %s", SelectedRace.name)
            self.parentApp.character.race = SelectedRace
            super().to_next()

    def on_cancel(self):
        super().to_prev()


class CharacterClassForm(LinkedListForm):
    class_num = 1

    def __init__(self, num=1, **kwargs):
        self.class_num = num
        self.class_options = list(char_classes.keys())
        super().__init__(**kwargs)

    @property
    def subclass_page(self):
        key = "SUBCLASS{:d}".format(self.class_num)
        if key in self.parentApp._Forms:
            return self.parentApp.getForm(key)
        else:
            return None

    @property
    def next_multiclass_page(self):
        key = "CLASS{:d}".format(self.class_num + 1)
        if key in self.parentApp._Forms:
            return self.parentApp.getForm(key)
        else:
            return None

    def update_options(self):
        if len(self.parentApp.character.class_list) == 0:
            return
        else:
            self.class_options = list(char_classes.keys())
            for c in self.parentApp.character.class_list[: self.class_num - 1]:
                self.class_options.remove(c.name)
            self.character_class.values = sorted(tuple(self.class_options))
            self.character_class.update()

    def create(self):
        if self.class_num > 1:
            self.add(
                npyscreen.FixedText,
                editable=False,
                value="Current Classes: {}".format(self.parentApp.character.name),
            )
        if self.class_num == 1:
            t = "Primary Class:"
        else:
            t = "Class #{:d}:".format(self.class_num)
        for c in self.parentApp.character.class_list:
            self.class_options.remove(c.name)
        if self.class_num == 1:
            self.multiclass = self.add(
                npyscreen.Checkbox,
                name="Add Multiclass?",
                value=False,
            )
        else:
            self.multiclass = self.add(
                npyscreen.Checkbox,
                name="Add Class #{:d}?".format(self.class_num + 1),
                value=False,
            )
        self.level = self.add(
            npyscreen.TitleText, name="Level:", value="1", use_two_lines=False
        )
        self.character_class = self.add(
            npyscreen.TitleSelectOne, name=t, values=tuple(self.class_options)
        )

    def add_multiclass_page(self):
        new_name = "CLASS{:d}".format(self.class_num + 1)
        new_form = self.parentApp.addForm(
            new_name,
            CharacterClassForm,
            name="Select your character's Class #{:d}:".format(self.class_num + 1),
            num=self.class_num + 1,
            formid=new_name,
        )
        self.add_next(new_name)
        return new_form

    def add_subclass_page(self, newclass, level):
        new_name = "SUBCLASS{:d}".format(self.class_num)
        new_form = self.parentApp.addForm(
            new_name,
            SubclassForm,
            name="Select your {:s} Subclass".format(newclass.name),
            newclass=newclass,
            level=level,
            num=self.class_num,
            formid=new_name,
        )
        self.add_next(new_name)
        return new_form

    def on_ok(self):
        if len(self.character_class.get_selected_objects()) >= 1:
            selected_class = self.character_class.get_selected_objects()[0]
            selected_class = char_classes[selected_class]
            log.debug("Selected character class %s", selected_class.name)
            # replace later classes if we've backed up
            self.parentApp.character.class_list = self.parentApp.character.class_list[
                : self.class_num - 1
            ]
            self.parentApp.character.add_class(
                cls=selected_class, level=int(self.level.value), subclass=None
            )
            # add multiclass page if not exists yet
            if self.multiclass.value:
                if self.next_multiclass_page is None:
                    self.add_multiclass_page()
                else:
                    self.next_multiclass_page.update_options()
            else:
                # in case returned a page, prune any future multiclasses
                while self.next_page != "BACKGROUND":
                    f = self.parentApp.getForm(self.next_page)
                    f.prune()
            if int(self.level.value) >= selected_class.subclass_select_level:
                if not self.subclass_page:
                    self.add_subclass_page(
                        newclass=selected_class, level=int(self.level.value)
                    )
            else:
                if self.subclass_page is not None:
                    f = self.parentApp.getForm(self.next_page)
                    f.prune()
            super().to_next()

    def on_cancel(self):
        super().to_prev()


class SubclassForm(LinkedListForm):
    def __init__(self, newclass, level, num=1, **kwargs):
        self.class_num = num
        self.parent_class = newclass
        if len(newclass.subclasses_available) > 0:
            self.subclass_options = [sc.name for sc in newclass.subclasses_available]
        else:
            self.subclass_options = ("None",)
        self.level = level
        super().__init__(**kwargs)

    def create(self):
        self.subclass = self.add(
            npyscreen.TitleSelectOne,
            name="Subclass:",
            values=tuple(self.subclass_options),
        )

    def on_ok(self):
        if len(self.subclass.get_selected_objects()) >= 1:
            sc = self.subclass.get_selected_objects()[0]
            if sc in [None, "", "None"]:
                sc = None
            self.parentApp.character.class_list = self.parentApp.character.class_list[
                : self.class_num - 1
            ]
            self.parentApp.character.add_class(
                cls=self.parent_class, level=self.level, subclass=sc
            )
            super().to_next()

    def on_cancel(self):
        super().to_prev()


class BackgroundForm(LinkedListForm):
    def create(self):
        self.background = self.add(
            npyscreen.TitleSelectOne,
            name="Background:",
            values=tuple(backgrounds.keys()),
        )

    def on_ok(self):
        if len(self.background.get_selected_objects()) >= 1:
            selected_bg = self.background.get_selected_objects()[0]
            Background = backgrounds[selected_bg]
            self.parentApp.character.background = Background()
            # Update the languages based on background and race
            race_languages = self.parentApp.character.race.languages
            languages = Background.languages + race_languages
            self.parentApp.character.languages = ", ".join(languages)
            log.debug("Selected character background: %s", Background.name)
            super().to_next()

    def on_cancel(self):
        super().to_prev()


class AlignmentForm(LinkedListForm):
    """Choose your character's alignment."""

    alignments = (
        "Lawful good",
        "Neutral good",
        "Chaotic good",
        "Lawful neutral",
        "True neutral",
        "Chaotic neutral",
        "Lawful evil",
        "Neutral evil",
        "Chaotic evil",
    )

    def create(self):
        self.alignment = self.add(
            npyscreen.TitleSelectOne, name="Alignment:", values=self.alignments
        )

    def on_ok(self):
        if len(self.alignment.get_selected_objects()) >= 1:
            selected_alignment = self.alignment.get_selected_objects()[
                0
            ]  # values[self.alignment.value]
            log.debug("Selected character alignment %s", selected_alignment)
            self.parentApp.character.alignment = selected_alignment
            # prep additions to abilities page
            self.parentApp.getForm("ABILITIES").prep()
            super().to_next()

    def on_cancel(self):
        super().to_prev()


class AbilityScoreForm(LinkedListForm):
    num_rolls = 0

    def roll_dice(self):
        """Get six ability scores that can then be assigned to abilities."""

        def roll_score():
            # Roll 4 dice and add the 3 highest
            rolls = (randint(1, 6) for i in range(4))
            score = sum(sorted(rolls)[-3:])
            return score

        scores = (roll_score() for i in range(6))
        return tuple(sorted(scores, reverse=True))

    def default_array(self):
        return (15, 14, 13, 12, 10, 8)

    def reroll(self, widget=None):
        self.num_rolls += 1
        new_scores = self.roll_dice()
        self.score_options.value = str(new_scores)[1:-1]
        self.score_options.update()
        self.reroll_button.value = False
        self.reroll_button.name = "Reroll"
        self.reroll_button.update()
        self.default_button.value = False
        self.default_button.update()

    def set_default(self, widget=None):
        new_scores = self.default_array()
        self.score_options.value = str(new_scores)[1:-1]
        self.score_options.update()
        self.default_button.value = True
        self.default_button.update()

    def reroll_hp(self, widget=None):
        self.parentApp.reroll_max_hp()
        self.parentApp.update_max_hp_roll()

    def create(self):
        self.roll_text = self.add(
            npyscreen.FixedText,
            editable=False,
            value="Take the six rolls below and assign each one to an ability.",
        )
        self.score_options = self.add(
            npyscreen.TitleFixedText,
            name="Rolls:",
            editable=False,
            value=str(self.default_array())[1:-1],
        )
        self.default_button = self.add(
            npyscreen.MiniButtonPress,
            name="Use Default Rolls",
            when_pressed_function=self.set_default,
        )
        self.reroll_button = self.add(
            npyscreen.MiniButtonPress, name="Reroll", when_pressed_function=self.reroll
        )

    def prep(self):
        attrs = (
            "strength",
            "dexterity",
            "constitution",
            "intelligence",
            "wisdom",
            "charisma",
        )
        self.class_text = self.add(
            npyscreen.FixedText,
            editable=False,
            value="Key stats for your primary class {:s} are listed with **".format(
                self.parentApp.character.primary_class.name
            ),
        )
        self.race_text = self.add(
            npyscreen.FixedText,
            editable=False,
            value="Do not add racial bonuses, they will be added for you as listed.",
        )
        for attr in attrs:
            if attr in self.parentApp.character.primary_class.primary_abilities:
                name = "**" + attr
            else:
                name = "" + attr
            race_bonus = getattr(self.parentApp.character.race, f"{attr}_bonus")
            if race_bonus != 0:
                name += "({:+d})".format(race_bonus)
            name += ":"
            new_fld = self.add(
                npyscreen.TitleText, name=name, begin_entry_at=24, value="10"
            )
            setattr(self, attr, new_fld)
        self.hp_roll_text = self.add(npyscreen.FixedText, editable=False, value="")
        self.hp_reroll_buttom = self.add(
            npyscreen.MiniButtonPress,
            name="Reroll Max HP",
            when_pressed_function=self.reroll_hp,
        )
        self.hp_max = self.add(npyscreen.TitleText, name="Max HP:")
        self.parentApp.update_max_hp_roll()
        self.parentApp.set_default_hp_max()

    def on_ok(self):
        attrs = (
            "strength",
            "dexterity",
            "constitution",
            "intelligence",
            "wisdom",
            "charisma",
            "hp_max",
        )
        for attr in attrs:
            fld = getattr(self, attr)
            race_bonus = getattr(self.parentApp.character.race, f"{attr}_bonus", 0)
            try:
                val = int(float(fld.value))
            except ValueError:
                # Not an integer, so clear the field
                val = 10
            val += race_bonus
            log.debug("Setting %s to %s", attr, str(val))
            # Update the "character" with new values
            setattr(self.parentApp.character, attr, val)
        super().to_next()

    def on_cancel(self):
        super().to_prev()


class SkillForm(LinkedListForm):
    def while_editing(self):
        # Update the static skills for race and background
        bg_skills = self.parentApp.character.background.skill_proficiencies
        self.bg_skills.value = str(bg_skills)[1:-1].replace("'", "")
        race_skills = self.parentApp.character.race.skill_proficiencies
        self.race_skills.value = str(race_skills)[1:-1].replace("'", "")
        # Now set the available discretionary choices
        choices = (
            self.parentApp.character.primary_class.class_skill_choices
            + self.parentApp.character.race.skill_choices
            + self.parentApp.character.background.skill_choices
        )
        static_skills = bg_skills + race_skills
        choices = set([c for c in choices if c.lower() not in static_skills])
        self.skill_proficiencies.set_values(sorted(tuple(choices)))
        self.update_remaining()

    def update_remaining(self, widget=None):
        num_choices = (
            self.parentApp.character.primary_class.num_skill_choices
            + self.parentApp.character.race.num_skill_choices
            + self.parentApp.character.background.num_skill_choices
        )
        num_selected = len(self.skill_proficiencies.value)
        remaining = num_choices - num_selected
        log.debug(f"Remaining: {remaining}")
        self.remaining.value = str(remaining)
        self.display()

    def create(self):
        self.bg_skills = self.add(
            npyscreen.TitleText, name="Background:", value="", editable=False
        )
        self.race_skills = self.add(
            npyscreen.TitleText, name="Racial:", value="", editable=False
        )
        self.remaining = self.add(
            npyscreen.TitleText, name="Remaining:", value=0, editable=False
        )
        self.skill_proficiencies = self.add(
            npyscreen.TitleMultiSelect,
            name="Skill Proficiencies:",
            values=(),
            value_changed_callback=self.update_remaining,
        )

    def on_ok(self):
        new_skills = self.skill_proficiencies.get_selected_objects()
        if new_skills is not None:
            new_skills = tuple(s.lower() for s in new_skills)
        else:
            new_skills = ()
        bg_skills = tuple(self.parentApp.character.background.skill_proficiencies)
        race_skills = tuple(self.parentApp.character.race.skill_proficiencies)
        all_skills = new_skills + bg_skills + race_skills
        self.parentApp.character.skill_proficiencies = all_skills
        self.parentApp.getForm("WEAPONS").update_options()
        log.debug(f"Skill proficiencies: {all_skills}")
        super().to_next()

    def on_cancel(self):
        super().to_prev()


class WeaponForm(LinkedListForm):
    def create(self):
        self.instructions = self.add(
            npyscreen.FixedText, editable=False, value="Please select your weapons."
        )
        self.remaining = self.add(
            npyscreen.TitleText, name="Remaining:", value=3, editable=False
        )
        self.weapons = self.add(
            npyscreen.TitleMultiSelect,
            name="Weapons:",
            values=tuple([wpn.name for wpn in all_weapons]),
            value_changed_callback=self.update_remaining,
        )

    def on_ok(self):
        new_weapons = self.weapons.get_selected_objects()
        if new_weapons is not None:
            new_weapons = tuple(s.lower() for s in new_weapons)
        else:
            new_weapons = ()
        for wpn in new_weapons:
            self.parentApp.character.wield_weapon(wpn)
        log.debug(f"Weapons wielded: {new_weapons}")
        super().to_next()

    def update_remaining(self, widget=None):
        num_choices = 3
        num_selected = len(self.weapons.value)
        remaining = num_choices - num_selected
        log.debug(f"Remaining: {remaining}")
        self.remaining.value = str(remaining)
        self.display()

    def update_options(self):
        available_weapons = []
        for wpn in all_weapons:
            if self.parentApp.character.is_proficient(wpn()):
                available_weapons.append(wpn.name)
        self.weapons.values = available_weapons
        self.parentApp.getForm("ARMOR").update_options()
        self.display()

    def on_cancel(self):
        super().to_prev()


class ArmorForm(LinkedListForm):
    def create(self):
        self.instructions = self.add(
            npyscreen.FixedText, editable=False, value="Please select your armor."
        )
        self.shield = self.add(npyscreen.Checkbox, name="Shield? ", value=False)
        self.armor = self.add(
            npyscreen.TitleSelectOne,
            name="Armor:",
            values=tuple([a.name for a in ([armor.NoArmor] + armor.all_armors)]),
        )

    def on_ok(self):
        my_armor = self.armor.get_selected_objects()[0]
        if my_armor.lower() != "no armor":
            self.parentApp.character.wear_armor(my_armor)
        if self.shield.value:
            self.parentApp.character.wield_shield("shield")
        super().to_next()

    def update_options(self):
        available_armors = [armor.NoArmor]
        proficiencies = self.parentApp.character.proficiencies_text.lower()
        if ("light armor" in proficiencies) or ("all armor" in proficiencies):
            available_armors.extend(armor.light_armors)
        if ("medium armor" in proficiencies) or ("all armor" in proficiencies):
            available_armors.extend(armor.medium_armors)
        if ("heavy armor" in proficiencies) or ("all armor" in proficiencies):
            available_armors.extend(armor.heavy_armors)
        self.armor.values = [a.name for a in available_armors]
        self.display()

    def on_cancel(self):
        super().to_prev()


class PersonalityForm(LinkedListForm):
    def create(self):
        self.instructions = self.add(
            npyscreen.FixedText,
            editable=False,
            value="Please describe your character's personality.",
        )
        self.add(npyscreen.FixedText, editable=False, value=" ")
        self.pers_instr = self.add(
            npyscreen.FixedText,
            editable=False,
            value="Describe how your character behaves/interacts with others?",
        )
        self.personality_traits = self.add(
            npyscreen.TitleText, name="Personality Traits: ", begin_entry_at=24
        )
        self.add(npyscreen.FixedText, editable=False, value=" ")
        self.ideal_instr = self.add(
            npyscreen.FixedText,
            editable=False,
            value="Describe what values does your character believes in?",
        )
        self.ideals = self.add(npyscreen.TitleText, name="Ideals: ", begin_entry_at=24)
        self.add(npyscreen.FixedText, editable=False, value=" ")
        self.bond_instr = self.add(
            npyscreen.FixedText,
            editable=False,
            value="Describe your character's commitments or ongoing quests.",
        )
        self.bonds = self.add(npyscreen.TitleText, name="Bonds: ", begin_entry_at=24)
        self.add(npyscreen.FixedText, editable=False, value=" ")
        self.flaw_instr = self.add(
            npyscreen.FixedText,
            editable=False,
            value="Describe your character's interesting flaws.",
        )
        self.flaws = self.add(npyscreen.TitleText, name="Flaws: ", begin_entry_at=24)
        self.add(npyscreen.FixedText, editable=False, value=" ")
        self.feat_instr = self.add(
            npyscreen.FixedText,
            editable=False,
            value="Describe any other notable features or abilities.",
        )
        self.features = self.add(
            npyscreen.TitleText, name="Features: ", begin_entry_at=24
        )

    def on_ok(self):
        if self.personality_traits.value:
            self.parentApp.character.personality_traits = self.personality_traits.value
        if self.ideals.value:
            self.parentApp.character.ideals = self.ideals.value
        if self.bonds.value:
            self.parentApp.character.bonds = self.bonds.value
        if self.flaws.value:
            self.parentApp.character.flaws = self.flaws.value
        if self.features.value:
            self.parentApp.character.features_and_traits = self.features.value
        super().to_next()

    def on_cancel(self):
        super().to_prev()


class SaveForm(LinkedListForm):
    def create(self):
        self.instructions = self.add(
            npyscreen.FixedText,
            editable=False,
            value=(
                "Your character will be saved in the file given below. "
                "After saving, edit this file to finish your personality, "
                "weapons, etc."
            ),
        )
        self.filename = self.add(npyscreen.TitleText, name="Filename:")
        self.make_pdf = self.add(npyscreen.Checkbox, name="Create PDF:", value=True)

    def on_ok(self):
        super().to_next()

    def on_cancel(self):
        super().to_prev()


def main():
    my_app = App()

    try:
        my_app.run()
    except KeyboardInterrupt:
        log.error("Aborted by user request")
    else:
        my_app.save_character()


if __name__ == "__main__":
    main()
