<div x-data="alpineAdversaries()">

    <!-- PAGE DETAILS -->

    <div x-init="initPage()" x-ref="headerAdversaries">
        <h2>Adversary Profiles</h2>
        <p>
            Adversary Profiles are collections of ATT&CK TTPs, designed to create specific effects on a host or network.
            Profiles can be used for offensive or defensive use cases.
        </p>
    </div>
    <hr>

    <!-- ADVERSARY SELECTION -->
    <form autocomplete="off">
        <div id="select-adversary" class="field has-addons">
            <label class="label" for="profile-search">Select a profile &nbsp;&nbsp;&nbsp;</label>
            <div class="control is-expanded auto-complete" x-data="{focusSearchResults: false}" @click.outside="focusSearchResults = false; searchResults = []">
                <input id="profile-search" class="input is-small is-fullwidth" x-model="adversarySearchQuery" placeholder="Search for an adversary profile or tactic..." x-on:keyup="searchForAdversary()" @click="focusSearchResults = true">
                <div class="search-results is-size-7" x-show="adversarySearchResults && focusSearchResults">
                    <template x-for="result of adversarySearchResults" :key="result.adversary_id">
                        <p @click="selectAdversary(result.adversary_id, `${result.name} (${(result.tactics.join(', '))})`); focusSearchResults = false" x-text="`${result.name} (${(result.tactics.join(', '))})`" x-bind:title="result.description"></p>
                    </template>
                </div>
            </div>
            <div class="control">
                <button type="button" class="button is-primary is-small" @click="isCreatingProfile = true">
                    <span class="icon"><em class="fas fa-plus"></em></span>
                    <span>New Profile</span>
                </button>
            </div>
            <div class="control ml-2">
                <button type="button" class="button is-small" @click="showImportModal = true">
                    <span class="icon"><em class="fas fa-file-import"></em></span>
                    <span>Import</span>
                </button>
            </div>
        </div>
    </form>

    <!-- ADVERSARY DETAILS -->

    <template x-if="selectedProfileId && !isCreatingProfile">
        <div class="section" x-init="$watch('selectedProfileAbilities', val => findAbilityDependencies())">
            <div x-show="!isEditingProfile">
                <div class="is-flex is-justify-content-space-between">
                    <div>
                        <h3 x-text="selectedProfileName" class="pointer tooltip has-tooltip-arrow" data-tooltip="Click to edit" @click="isEditingProfile = true"></h3>
                        <p x-text="selectedProfileDescription" class="pointer" @click="isEditingProfile = true"></p> <br>
                    </div>
                    <p>
                        Adversary ID:
                        <span x-text="selectedProfileId"></span>
                    </p>
                </div>
            </div>
            <form x-show="isEditingProfile">
                <div class="field">
                    <div class="control">
                        <input class="input" x-model="selectedProfileName" x-on:change="unsavedChanges = true" placeholder="Adversary Name" x-bind:class="{ 'is-danger': fieldErrorsProfile.includes('name') }">
                        <p x-show="fieldErrorsProfile.includes('name')" class="help is-danger">This field is required.</p>
                    </div>
                </div>
                <div class="field">
                    <div class="control">
                        <input class="input is-small" x-model="selectedProfileDescription" placeholder="Adversary Description" x-on:change="unsavedChanges = true" x-bind:class="{ 'is-danger': fieldErrorsProfile.includes('description') }">
                        <p x-show="fieldErrorsProfile.includes('description')" class="help is-danger">This field is required.</p>
                    </div>
                </div>
                <div class="field">
                    <div class="control">
                        <a class="button is-small is-primary mb-5" @click="isEditingProfile = false">Done</a>
                    </div>
                </div>
            </form>
            <div>
                <div class="is-flex m-0">
                    <button class="button is-small mr-2" @click="selectedAbilityId = ''; showAbilityChoiceModal = true;">
                        <span class="icon"><em class="fas fa-plus"></em></span>
                        <span>Add Ability</span>
                    </button>
                    <button class="button is-primary is-small mr-2" @click="showAddAdversaryModal = true">
                        <span class="icon"><em class="fas fa-plus"></em></span>
                        <span>Add Adversary</span>
                    </button>
                    <button type="button" class="button is-small mr-2" @click="showFactBreakdownModal = true">
                        <span class="icon"><em class="fas fa-unlock-alt"></em></span>
                        <span>Fact Breakdown</span>
                    </button>
                    <div class="vr"></div>
                    <span>Objective: <b x-text="getObjectiveName()"></b>&nbsp;&nbsp;&nbsp;</span>
                    <button type="button" class="button is-small mr-2" @click="showObjectiveModal = true">Change</button>
                    <div class="vr"></div>
                    <button type="button" class="button is-small mr-2" @click="exportProfile()">
                        <span class="icon"><em class="fas fa-file-export"></em></span>
                        <span>Export</span>
                    </button>
                    <button type="button" class="button is-success is-small mr-2" x-bind:disabled="!unsavedChanges" @click="saveProfile()">Save Profile</button>
                    <button type="button" class="button is-danger is-outlined is-small mr-2" @click="deleteProfile()">Delete Profile</button>
                </div>

                <div class="tactic-breakdown pt-4 pb-4" @click="isTacticBreakdownActive = !isTacticBreakdownActive" title="Click to expand/collapse">
                    <template x-for="tactic in getTacticBreakdown" :key="tactic[0]">
                        <span class="tactic-item has-tooltip-bottom" :class="{ 'active': isTacticBreakdownActive }" x-bind:style="`width: ${tactic[1]}%; background-color: ${hashStringToColor(tactic[0])};`" x-text="`${tactic[0]}  ${tactic[1]}%`"></span>
                    </template>
                </div>

                <table x-show="selectedProfileAbilities.length" class="table is-striped is-fullwidth">
                    <thead>
                        <tr class="ability-row">
                            <th></th>
                            <th>Ordering</th>
                            <th>Name</th>
                            <th>Tactic</th>
                            <th>Technique</th>
                            <th>Executors</th>
                            <th>Requires</th>
                            <th>Unlocks</th>
                            <th>Payload</th>
                            <th>Cleanup</th>
                            <th></th>
                        </tr>
                    </thead>
                    <tbody>
                        <template x-for="(ability, index) of selectedProfileAbilities">
                            <tr @click="selectAbility(ability.ability_id)" class="ability-row" 
                                x-bind:class="{ 'orange-row': needsParser.indexOf(ability.name) > -1 ,
                                                'row-hover-above': 
                                                  ability.ability_id === abilityTableDragHoverId
                                                  && abilityTableDragHoverId != undefined
                                                  && abilityTableDragEndIndex < abilityTableDragTargetIndex,
                                                'row-hover-below': 
                                                  ability.ability_id === abilityTableDragHoverId
                                                  && abilityTableDragHoverId != undefined
                                                  && abilityTableDragEndIndex > abilityTableDragTargetIndex,
                                                'red-row-unclickable': undefinedAbilities.indexOf(ability.ability_id) > -1 }"
                                x-on:mouseenter="setAbilityHover(ability.ability_id)" x-on:mouseleave="clearAbilityHover()"> 
                                <td class="has-text-centered drag" 
                                  @click.stop draggable="true" x-on:dragstart="startAbilitySwap" x-on:dragenter="abilityTableDragHoverId = ability.ability_id"  x-on:dragover.prevent="swapAbilitiesHover" x-on:dragend="dragAbility">
                                  &#9776;
                                </td>
                                <td>
                                    <div class="icon-text">
                                        <span x-text="index + 1"></span>
                                        <span class="icon has-text-danger" x-show="!ability.ability_id">
                                            <em class="fas fa-ban"></em>
                                        </span>
                                        <span class="icon has-text-warning" x-show="needsParser.indexOf(ability.name) > -1">
                                            <em class="fas fa-exclamation-triangle"></em>
                                        </span>
                                    </div>
                                </td>
                                <td x-text="ability.ability_id ? ability.name : 'Undefined Ability'"></td>
                                <template x-if="!ability.ability_id">
                                    <td colspan="7" x-text="'ID - ' + abilityIDs[index]"></td>
                                </template>
                                <td x-show="undefinedAbilities.indexOf(ability.ability_id)">
                                    <span x-text="ability.tactic" x-bind:style="`border-bottom: 1px ridge ${hashStringToColor(ability.tactic)}`"></span>
                                </td>
                                <td x-text="ability.technique_name" x-show="undefinedAbilities.indexOf(ability.ability_id)"></td>
                                <td x-show="undefinedAbilities.indexOf(ability.ability_id)">
                                    <template x-for="platform of getExecutorDetail('platforms', ability)">
                                        <span class="has-tooltip-arrow no-underline" x-bind:data-tooltip="platform">
                                            <span class="icon is-small"><em class="fab" x-bind:class="if (platform.includes('windows')) return 'fa-windows'; else if (platform.includes('darwin')) return 'fa-apple'; else if (platform.includes('linux')) return 'fa-linux'"></em></span>
                                        </span>
                                    </template>
                                </td>
                                <td class="has-text-centered" x-show="undefinedAbilities.indexOf(ability.ability_id)" x-bind:class="{ 'unlock': onHoverUnlocks.indexOf(ability.ability_id) > -1 }">
                                    <span class=" has-tooltip-arrow no-underline" x-show="getExecutorDetail('requirements', ability)" x-bind:data-tooltip="`This ability has requirements: (${abilityDependencies[ability.ability_id].requireTypes})`">
                                        <span class="icon is-small"><em class="fas fa-lock"></em></span>
                                    </span>
                                </td>
                                <td class="has-text-centered" x-show="undefinedAbilities.indexOf(ability.ability_id)" x-bind:class="{ 'lock': onHoverLocks.indexOf(ability.ability_id) > -1 }">
                                    <span class="has-tooltip-arrow no-underline" x-show="getExecutorDetail('parser', ability)" x-bind:data-tooltip="`This ability unlocks other abilities: (${abilityDependencies[ability.ability_id].enableTypes})`">
                                        <span class="icon is-small"><em class="fas fa-key"></em></span>
                                    </span>
                                </td>
                                <td class="has-text-centered" x-show="undefinedAbilities.indexOf(ability.ability_id)">
                                    <span class="has-tooltip-arrow no-underline" x-show="getExecutorDetail('payload', ability)" data-tooltip="This ability uses a payload">
                                        <span class="icon is-small"><em class="fas fa-weight-hanging"></em></span>
                                    </span>
                                </td>
                                <td class="has-text-centered" x-show="undefinedAbilities.indexOf(ability.ability_id)">
                                    <span class="has-tooltip-arrow no-underline" x-show="getExecutorDetail('cleanup', ability)" data-tooltip="This ability can clean itself up">
                                        <span class="icon is-small"><em class="fas fa-trash"></em></span>
                                    </span>
                                </td>
                                <td class="has-text-centered"><button class="delete is-danger" @click.stop="removeAbility(index)"></button></td>
                            </tr>
                        </template>
                    </tbody>
                </table>
                <div x-show="!selectedProfileAbilities.length" class="container has-text-centered">
                    <p>This profile has no abilities.</p>
                </div>
                <div class="icon-text" x-show="needsParser.length">
                    <span class="icon has-text-warning">
                        <em class="fas fa-exclamation-triangle"></em>
                    </span>
                    <span>One or more of the abilities have unmet requirements, which may result in a failed operation if ran sequentially.</span>
                </div>
                <div class="icon-text mt-2" x-show="undefinedAbilities.length">
                    <span class="icon has-text-danger">
                        <em class="fas fa-ban"></em>
                    </span>
                    <span>One or more of the referenced abilities are not defined.</span>
                </div>
            </div>
        </div>
    </template>

    <!-- CREATE PROFILE SECTION -->

    <template x-if="isCreatingProfile">
        <div class="section content">
            <h3>Create a profile</h3>
            <form>
                <div class="field">
                    <label class="label is-small">Profile Name</label>
                    <div class="control">
                        <input x-model="createProfileName" class="input is-small" type="text" placeholder="Enter a name..." x-bind:class="{ 'is-danger': fieldErrorsProfile.includes('name') }">
                    </div>
                    <p x-show="fieldErrorsProfile.includes('name')" class="help is-danger">This field is required.</p>
                </div>
                <div class="field">
                    <label class="label is-small">Profile Description</label>
                    <div class="control">
                        <input x-model="createProfileDescription" class="input is-small" type="text" placeholder="Enter a description..." x-bind:class="{ 'is-danger': fieldErrorsProfile.includes('description') }">
                    </div>
                    <p x-show="fieldErrorsProfile.includes('description')" class="help is-danger">This field is required.</p>
                </div>
                <div class="field is-grouped">
                    <div class="control">
                        <a class="button is-primary is-small" @click="createProfile()">Create</a>
                    </div>
                    <div class="control">
                        <a class="button is-small" @click="cancelCreateProfile()">Cancel</a>
                    </div>
                </div>
            </form>
        </div>
    </template>

    <!-- MODALS -->

    <div class="modal" x-bind:class="{ 'is-active': showAddAdversaryModal }">
        <div class="modal-background" @click="showAddAdversaryModal = false; selectedAddAdversary = ''; abilitiesAddAdversary = [];"></div>
        <div class="modal-card">
            <header class="modal-card-head">
                <p class="modal-card-title">Add Ablities from Adversary</p>
            </header>
            <section class="modal-card-body">
                <p>Select an adversary, then select all of the abilities you'd like to append to <b x-text="selectedProfileName"></b>.</p>
                <form>
                    <div class="field">
                        <label class="label">Select a profile</label>
                        <div class="control is-expanded">
                            <div class="select is-small">
                                <select x-on:change="loadProfileAdversary()" x-model="selectedAddAdversary">
                                    <option value="" default disabled selected>Select one...</option>
                                    <template x-for="adversary of adversaries" :key="adversary.adversary_id">
                                        <option x-bind:value="adversary.adversary_id" x-text="adversary.name" x-bind:title="adversary.description"></option>
                                    </template>
                                </select>
                            </div>
                        </div>
                    </div>
                    <div class="field" x-show="selectedAddAdversary">
                        <div class="control">
                            <a @click="abilitiesAddAdversary.forEach(a => a.selected = true)">Select All</a>
                            /
                            <a @click="abilitiesAddAdversary.forEach(a => a.selected = false)">Deselect All</a>
                        </div>
                    </div>
                    <template x-for="ability of abilitiesAddAdversary">
                        <div class="field">
                            <label class="checkbox">
                                <input type="checkbox" x-model="ability.selected">
                                <span>
                                    <b x-text="ability.name"></b> |
                                    <span x-text="ability.tactic"></span> |
                                    <template x-for="platform of getExecutorDetail('platforms', ability)">
                                        <span class="icon is-small"><em class="fab" x-bind:class="if (platform.includes('windows')) return 'fa-windows'; else if (platform.includes('darwin')) return 'fa-apple'; else if (platform.includes('linux')) return 'fa-linux'"></em></span>
                                    </template> |
                                    <span class="icon is-small" x-show="getExecutorDetail('requirements', ability)"><em class="fas fa-lock"></em></span>
                                    <span class="icon is-small" x-show="getExecutorDetail('cleanup', ability)"><em class="fas fa-trash"></em></span>
                                    <span class="icon is-small" x-show="getExecutorDetail('parser', ability)"><em class="fas fa-key"></em></span>
                                    <span class="icon is-small" x-show="getExecutorDetail('payload', ability)"><em class="fas fa-weight-hanging"></em></span>
                                </span>
                            </label>
                        </div>
                    </template>
                </form>
            </section>
            <footer class="modal-card-foot">
                <nav class="level">
                    <div class="level-left">
                        <div class="level-item">
                            <button class="button is-small" @click="showAddAdversaryModal = false; selectedAddAdversary = ''; abilitiesAddAdversary = [];">Close</button>
                        </div>
                    </div>
                    <div class="level-right">
                        <div class="level-item">
                            <button class="button is-primary is-small" x-bind:disabled="!abilitiesAddAdversary.find(a => a.selected)" @click="addAbilitiesFromAdversary()">Add Selected Abilities</button>
                        </div>
                    </div>
                </nav>
            </footer>
        </div>
    </div>

    <div class="modal" x-bind:class="{ 'is-active': showObjectiveModal }">
        <div class="modal-background" @click="showObjectiveModal = false"></div>
        <div class="modal-card">
            <header class="modal-card-head">
                <p class="modal-card-title">Link Objective</p>
            </header>
            <section class="modal-card-body">
                <p>Specify an Objective for <b x-text="selectedProfileName"></b>.</p>
                <form>
                    <div class="field">
                        <label class="label">Select an objective</label>
                        <div class="control is-expanded">
                            <div class="select is-small">
                                <select x-model="selectedObjectiveId">
                                    <option value="" default disabled selected>Select one...</option>
                                    <template x-for="objective of objectives" :key="objective.id">
                                        <option x-bind:value="objective.id" x-text="objective.name" x-bind:title="objective.description"></option>
                                    </template>
                                </select>
                            </div>
                        </div>
                    </div>
                </form>
            </section>
            <footer class="modal-card-foot">
                <nav class="level">
                    <div class="level-left">
                        <div class="level-item">
                            <button class="button is-small" @click="showObjectiveModal = false">Close</button>
                        </div>
                    </div>
                    <div class="level-right">
                        <div class="level-item">
                            <button class="button is-primary is-small" @click="linkObjective()">Link Objective</button>
                        </div>
                    </div>
                </nav>
            </footer>
        </div>
    </div>

    <div class="modal" x-bind:class="{ 'is-active': showAbilityChoiceModal }">
        <div class="modal-background" @click="showAbilityChoiceModal = false"></div>
        <div class="modal-card wide">
            <header class="modal-card-head">
                <p class="modal-card-title">Add an Ability to Adversary</p>
            </header>
            <section class="modal-card-body">
                <p class="has-text-centered">Select an Ability</p>
                <form>
                    <div class="field is-horizontal">
                        <div class="field-label is-small">
                            <label class="label"><span class="icon is-small"><em class="fas fa-search"></em></span></label>
                        </div>
                        <div class="field-body">
                            <div class="field">
                                <div class="control auto-complete mb-3" x-data="{focusSearchResults: true}" @click.outside="focusSearchResults = false; searchResults = []">
                                    <input class="input is-small" x-model="abilitySearchQuery" placeholder="Search for an ability..." x-on:keyup="searchForAbility()" @click="focusSearchResults = true">
                                    <div class="search-results is-size-7" x-show="abilitySearchResults && focusSearchResults">
                                        <template x-for="result of abilitySearchResults" :key="result.ability_id">
                                            <p @click="selectAbility(result.ability_id)" x-text="result.name"></p>
                                        </template>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </form>
                <form>
                    <div class="field is-horizontal">
                        <div class="field-label is-small">
                            <label class="label">Tactic</label>
                        </div>
                        <div class="field-body">
                            <div class="field">
                                <div class="control">
                                    <div class="select is-small is-fullwidth">
                                        <select x-model="selectedTactic" x-on:change="selectedAbilityId = ''">
                                            <option default>Choose a tactic</option>
                                            <template x-for="tactic of Array.from(new Set(abilities.map((e) => e.tactic))).sort()" :key="tactic">
                                                <option x-bind:value="tactic" x-text="tactic"></option>
                                            </template>
                                        </select>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="field is-horizontal">
                        <div class="field-label is-small">
                            <label class="label">Technique</label>
                        </div>
                        <div class="field-body">
                            <div class="field">
                                <div class="control">
                                    <div class="select is-small is-fullwidth">
                                        <select x-model="selectedTechnique" x-bind:disabled="!selectedTactic" x-on:change="selectedAbilityId = ''">
                                            <option default>Choose a technique</option>
                                            <template :key="exploit.technique_id" x-for="exploit of ([...new Set(abilities.filter((e) => selectedTactic === e.tactic).map((e) => e.technique_id))].map((t) => abilities.find((e) => e.technique_id === t))).sort((a,b) => { return a.technique_name === b.technique_name ? 0 : (a.technique_name > b.technique_name ? 1 : -1) })">
                                                <option x-bind:value="exploit.technique_id" x-text="`${exploit.technique_id} | ${exploit.technique_name}`"></option>
                                            </template>
                                        </select>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="field is-horizontal is-fullwidth">
                        <div class="field-label is-small">
                            <label class="label">Ability</label>
                        </div>
                        <div class="field-body">
                            <div class="field">
                                <div class="control">
                                    <div class="select is-small is-fullwidth">
                                        <select x-model="selectedAbilityId" x-bind:disabled="!selectedTechnique" x-on:change="selectAbility(selectedAbilityId)">
                                            <option default>Choose an ability</option>
                                            <template :key="ability.ability_id" x-for="ability of abilities.filter((e) => selectedTactic === e.tactic && selectedTechnique === e.technique_id)">
                                                <option x-bind:value="ability.ability_id" x-text="ability.name"></option>
                                            </template>
                                        </select>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </form>
                <template x-if="selectedAbilityId">
                    <div class="content">
                        <hr>
                        <p class="has-text-centered">Ability Details</p>
                        <form>
                            <div class="field is-horizontal">
                                <div class="field-label is-small">
                                    <label class="label">ID</label>
                                </div>
                                <div class="field-body">
                                    <div class="field has-addons">
                                        <div class="control is-expanded">
                                            <input class="input is-small" x-model="selectedAbility.ability_id" disabled>
                                        </div>
                                        <div class="control">
                                            <a class="button is-small has-tooltip-left has-tooltip-arrow" data-tooltip="Generate New ID" @click="selectedAbility.ability_id = uuidv4()">
                                                <span class="icon is-small"><em class="fas fa-sync"></em></span>
                                            </a>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="field is-horizontal">
                                <div class="field-label is-small">
                                    <label class="label">Name</label>
                                </div>
                                <div class="field-body">
                                    <div class="field">
                                        <div class="control">
                                            <input class="input is-small" x-bind:class="{ 'is-danger': fieldErrorsAbility.includes('name') }" x-model="selectedAbility.name">
                                            <p x-show="fieldErrorsAbility.includes('name')" class="help is-danger">This field is required.</p>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="field is-horizontal">
                                <div class="field-label is-small">
                                    <label class="label">Description</label>
                                </div>
                                <div class="field-body">
                                    <div class="field">
                                        <div class="control">
                                            <input class="input is-small" x-bind:class="{ 'is-danger': fieldErrorsAbility.includes('description') }" x-model="selectedAbility.description">
                                            <p x-show="fieldErrorsAbility.includes('description')" class="help is-danger">This field is required.</p>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="field is-horizontal">
                                <div class="field-label is-small">
                                    <label for="tactic-auto-fill" class="label">Tactic</label>
                                </div>
                                <div class="field-body">
                                    <div class="field">
                                        <div class="control auto-complete" x-data="{focusSearchResults: true}" @click.outside="focusSearchResults = false; searchResults = []">
                                            <input id="tactic-auto-fill" class="input is-small" x-bind:class="{ 'is-danger': fieldErrorsAbility.includes('tactic') }" x-model="selectedAbility.tactic" x-on:keyup="searchForAutoFill('tactic')" @click="focusSearchResults = true">
                                            <div class="search-results is-size-7" x-show="searchResults && focusSearchResults">
                                                <template x-for="result of searchResults" :key="result">
                                                    <p x-show="result !== selectedAbility.tactic" @click="selectedAbility.tactic = result; searchResults = []" x-text="result"></p>
                                                </template>
                                            </div>
                                            <p x-show="fieldErrorsAbility.includes('tactic')" class="help is-danger">This field is required.</p>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="field is-horizontal">
                                <div class="field-label is-small">
                                    <label class="label is-small">Technique ID</label>
                                </div>
                                <div class="field-body">
                                    <div class="field">
                                        <div class="control auto-complete" x-data="{focusSearchResults: true}" @click.outside="focusSearchResults = false; searchResults = []">
                                            <input class="input is-small" x-bind:class="{ 'is-danger': fieldErrorsAbility.includes('technique_id') }" x-model="selectedAbility.technique_id" x-on:keyup="searchForAutoFill('technique_id')" @click="focusSearchResults = true">
                                            <div class="search-results is-size-7" x-show="searchResults && focusSearchResults">
                                                <template x-for="result of searchResults" :key="result">
                                                    <p x-show="result !== selectedAbility.technique_id" @click="selectedAbility.technique_id = result; searchResults = []" x-text="result"></p>
                                                </template>
                                            </div>
                                            <p x-show="fieldErrorsAbility.includes('technique_id')" class="help is-danger">This field is required.</p>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="field is-horizontal">
                                <div class="field-label is-small">
                                    <label class="label">Technique Name</label>
                                </div>
                                <div class="field-body">
                                    <div class="field">
                                        <div class="control auto-complete" x-data="{focusSearchResults: true}" @click.outside="focusSearchResults = false; searchResults = []">
                                            <input class="input is-small" x-bind:class="{ 'is-danger': fieldErrorsAbility.includes('technique_name') }" x-model="selectedAbility.technique_name" x-on:keyup="searchForAutoFill('technique_name')" @click="focusSearchResults = true">
                                            <div class="search-results is-size-7" x-show="searchResults && focusSearchResults">
                                                <template x-for="result of searchResults" :key="result">
                                                    <p x-show="result !== selectedAbility.technique_name" @click="selectedAbility.technique_name = result; searchResults = []" x-text="result"></p>
                                                </template>
                                            </div>
                                            <p x-show="fieldErrorsAbility.includes('technique_name')" class="help is-danger">This field is required.</p>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="field is-horizontal">
                                <div class="field-label is-small">
                                    <label class="label">Singleton</label>
                                </div>
                                <div class="field-body">
                                    <div class="field">
                                        <div class="control mt-2">
                                            <input type="checkbox" x-model="selectedAbility.singleton">
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="field is-horizontal">
                                <div class="field-label is-small">
                                    <label class="label">Repeatable</label>
                                </div>
                                <div class="field-body">
                                    <div class="field">
                                        <div class="control mt-2">
                                            <input type="checkbox" x-model="selectedAbility.repeatable">
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="field is-horizontal">
                                <div class="field-label is-small">
                                    <label class="label">Delete payload</label>
                                </div>
                                <div class="field-body">
                                    <div class="field">
                                        <div class="control mt-2">
                                            <input type="checkbox" x-model="selectedAbility.delete_payload">
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </form>
                        <p class="has-text-centered">Executors</p>
                        <p x-show="fieldErrorsAbility.includes('executors')" class="help is-danger">At least one executor is required.</p>
                        <div class="has-text-centered">
                            <button class="button is-small is-primary" @click="addExecutorToAbility('before')">+ Add Executor</button>
                        </div>
                        <br>
                        <template x-for="(executor, index) of getAbilityExecutors()" :key="index">
                            <div class="box">
                                <div class="has-text-right">
                                    <button class="delete" @click="selectedAbility.executors.splice(index, 1)"></button>
                                </div>
                                <form>
                                    <div class="field is-horizontal">
                                        <div class="field-label is-small">
                                            <label class="label">platform</label>
                                        </div>
                                        <div class="field-body">
                                            <div class="field ">
                                                <div class="control">
                                                    <div class="select is-small">
                                                        <select x-model="executor.platform">
                                                            <template x-for="plat of getPlatforms(executor.platform)" :key="plat">
                                                                <option x-bind:value="plat" x-text="plat"></option>
                                                            </template>
                                                        </select>
                                                    </div>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="field is-horizontal">
                                        <div class="field-label is-small">
                                            <label class="label">executor</label>
                                        </div>
                                        <div class="field-body">
                                            <div class="field ">
                                                <div class="control">
                                                    <div class="select is-small">
                                                        <select x-model="executor.name">
                                                            <option default disabled>Select an executor...</option>
                                                            <template x-for="exec of getExecutors(executor.platform, executor.name)" :key="exec">
                                                                <option x-bind:value="exec" x-text="exec""></option>
                                                            </template>
                                                        </select>
                                                    </div>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="field is-horizontal">
                                        <div class="field-label is-small">
                                            <label class="label">payloads</label>
                                        </div>
                                        <div class="field-body">
                                            <div class="field is-grouped is-grouped-multiline">
                                                <p x-show="executor.payloads.length === 0" class="help">No payloads selected</p>
                                                <template x-for="(payload, index) of executor.payloads">
                                                    <div class="control">
                                                        <div class="tags has-addons">
                                                            <span class="tag is-small is-link" x-text="payload"></span>
                                                            <a class="tag is-delete" x-on:click="executor.payloads.splice(index, 1)"></a>
                                                        </div>
                                                    </div>
                                                </template>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="field is-horizontal">
                                        <div class="field-label is-small">
                                            <label class="label"></label>
                                        </div>
                                        <div class="field-body">
                                            <div class="field">
                                                <div class="control">
                                                    <div class="select is-small is-multiple is-fullwidth">
                                                        <select class="select is-multiple" multiple size="6">
                                                            <template x-for="payload of payloads">
                                                                <option x-show="executor.payloads.indexOf(payload) === -1" x-on:click="executor.payloads.push(payload)" x-text="payload"></option>
                                                            </template>
                                                        </select>
                                                    </div>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="field is-horizontal">
                                        <div class="field-label is-small">
                                            <label class="label">command</label>
                                        </div>
                                        <div class="field-body">
                                            <div class="field ">
                                                <div class="control">
                                                    <textarea class="textarea is-small code" x-model="executor.command"></textarea>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="field is-horizontal">
                                        <div class="field-label is-small">
                                            <label class="label">timeout</label>
                                        </div>
                                        <div class="field-body">
                                            <div class="field">
                                                <div class="control">
                                                    <input class="input is-small" type="number" x-model="executor.timeout">
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                    <template x-for="(cleanup, index) of executor.cleanup">
                                        <div class="field is-horizontal">
                                            <div class="field-label is-small">
                                                <label class="label" x-text="index === 0 ? 'cleanup': ' '"></label>
                                            </div>
                                            <div class="field-body">
                                                <div class="field has-addons">
                                                    <div class="control is-expanded">
                                                        <input class="input is-small code" x-model="executor.cleanup[index]"></input>
                                                    </div>
                                                    <div class="control">
                                                        <a class="button is-small has-tooltip-bottom has-tooltip-arrow" data-tooltip="Remove cleanup command" @click="executor.cleanup.splice(index, 1)">
                                                            <span class="icon is-small"><em class="fas fa-minus-square"></em></span>
                                                        </a>
                                                    </div>
                                                </div>
                                            </div>
                                        </div>
                                    </template>
                                    <div class="field is-horizontal">
                                        <div class="field-label is-small" x-show="!executor.cleanup.length">
                                            <label class="label">cleanup</label>
                                        </div>
                                        <div class="field-body">
                                            <div class="field">
                                                <div class="control has-text-right">
                                                    <button type="button" class="button is-small is-primary" @click.stop="executor.cleanup.push('')">+ Add Cleanup Command</button>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                </form>
                            </div>
                        </template>
                        <template x-if="selectedAbility.executors && selectedAbility.executors.length > 0">
                            <div class="has-text-centered">
                                <button class="button is-small is-primary" @click="addExecutorToAbility('after')">+ Add Executor</button>
                            </div>
                        </template>
                    </div>
                </template>
            </section>
            <footer class="modal-card-foot">
                <nav class="level">
                    <div class="level-left">
                        <div class="level-item" x-show="selectedAbility">
                            <button class="button is-small" @click="saveAbility(false)" x-bind:disabled="!selectedAbilityId">
                                <span class="icon"><em class="fas fa-save"></em></span>
                                <span>Save</span>
                            </button>
                        </div>
                    </div>
                    <div class="level-right">
                        <div class="level-item">
                            <button class="button is-small" @click="showAbilityChoiceModal = false">Close</button>
                        </divp>
                        <div class="level-item" x-show="selectedAbility">
                            <button class="button is-primary is-small" @click="saveAbility(true)" x-bind:disabled="!selectedAbilityId">
                                <span class="icon"><em class="fas fa-plus"></em></span>
                                <span>Save & Add</span>
                            </button>
                        </div>
                    </div>
                </nav>
            </footer>
        </div>
    </div>

    <div class="modal" x-bind:class="{ 'is-active': showImportModal }">
        <div class="modal-background" @click="showImportModal = false; adversaryImportFile = undefined"></div>
        <div class="modal-card">
            <header class="modal-card-head">
                <p class="modal-card-title">Import Adversary</p>
            </header>
            <section class="modal-card-body">
                <div class="file is-small has-name is-fullwidth">
                    <label class="file-label">
                        <input class="file-input" accept=".yml,.yaml" type="file" @change="uploadAdversaryFile($el)">
                        <span class="file-cta">
                            <span class="file-icon"><em class="fas fa-upload"></em></span>
                            <span class="file-label">Choose a file…</span>
                        </span>
                        <span class="file-name" x-text="adversaryImportFile ? adversaryImportFile.name : ''"></span>
                    </label>
                </div>
            </section>
            <footer class="modal-card-foot">
                <nav class="level">
                    <div class="level-left">
                        <div class="level-item">
                            <button class="button is-small" @click="showImportModal = false; adversaryImportFile = undefined">Close</button>
                        </div>
                    </div>
                    <div class="level-right">
                        <div class="level-item">
                            <button class="button is-primary is-small" @click="importProfile()" :disabled="!adversaryImportFile">Import Adversary</button>
                        </div>
                    </div>
                </nav>
            </footer>
        </div>
    </div>

    <div class="modal" x-bind:class="{ 'is-active': showFactBreakdownModal }">
        <div class="modal-background" @click="showFactBreakdownModal = false"></div>
        <div class="modal-card">
            <header class="modal-card-head">
                <p class="modal-card-title">Fact Breakdown</p>
            </header>
            <section class="modal-card-body">
                <p class="help">
                    <span class="tag is-small is-success">&nbsp;</span> Required and Collected
                    <span class="tag is-small is-warning">&nbsp;</span> Required and not Collected
                    <span class="tag is-small is-dark">&nbsp;</span> Collected but not Required
                </p>
                <div class="tags" x-show="factBreakdown.length">
                    <template x-for="(fact, index) of factBreakdown.sort()" :key="index">
                        <span class="tag is-small no-pointer" :class="{ 'is-warning': fact.type === 'unmet', 'is-success': fact.type === 'met' }">
                            <span class="icon"><em class="fas" :class="{ 'fa-exclamation-triangle': fact.type === 'unmet', 'fa-check': fact.type === 'met', 'fa-minus': fact.type === 'extra' }"></em></span>
                            <span x-text="fact.fact"></span>
                        </span>
                    </template>
                </div>
                <p x-show="!factBreakdown.length">No facts to show</p>
            </section>
            <footer class="modal-card-foot">
                <nav class="level">
                    <div class="level-left"></div>
                    <div class="level-right">
                        <div class="level-item">
                            <button class="button is-small" @click="showFactBreakdownModal = false">Close</button>
                        </div>
                    </div>
                </nav>
            </footer>
        </div>
    </div>

</div>

<script>
    function alpineAdversaries() {
        return {
            // Global page variables
            adversaries: [],
            abilities: [],
  	        abilityIDs: [],
            objectives: [],
            platforms: JSON.parse('{{ platforms | tojson }}'),
            payloads: JSON.parse('{{ payloads | tojson }}').sort(),

            selectedProfileId: '',
            selectedProfileName: undefined,
            selectedProfileDescription: undefined,
            selectedProfileAbilities: [],
            unsavedChanges: false,

            // Ability dependencies & parsers
            abilityDependencies: {},
            needsParser: [],
            undefinedAbilities: [],
            onHoverUnlocks: [],
            onHoverLocks: [],
            isTacticBreakdownActive: false,

            // Create a profile
            isEditingProfile: false,
            isCreatingProfile: false,
            createProfileName: '',
            createProfileDescription: '',

            // Table on drag and drop
            abilityTableDragTarget: undefined,
            abilityTableDragTargetIndex: undefined,
            abilityTableDragEndIndex: undefined,
            abilityTableDragHoverId: undefined,

            // Add adversary modal
            showAddAdversaryModal: false,
            selectedAddAdversary: '',
            abilitiesAddAdversary: [],

            // Objective modal
            showObjectiveModal: false,
            selectedObjectiveId: '',

            // Ability modal
            showAbilityChoiceModal: false,
            selectedTactic: '',
            selectedTechnique: '',
            selectedAbilityId: '',
            adversarySearchQuery: '',
            abilitySearchQuery: '',
            searchResults: [],
            abilitySearchResults: [],
            adversarySearchResults: [],
            selectedAbility: {},
            selectedPlatform: '',
            selectedExecutor: '',

            // Import modal
            showImportModal: false,
            adversaryImportFile: undefined,
            adversaryImportFileContent: undefined,

            // Fact breakdown modal
            showFactBreakdownModal: false,
            factBreakdown: [],

            // Input validation
            requiredFieldsProfile: ['name', 'description'],
            fieldErrorsProfile: [],
            requiredFieldsAbility: ['name', 'description', 'tactic', 'technique_id', 'technique_name', 'executors'],
            fieldErrorsAbility: [],

            initPage() {
                apiV2('GET', '/api/v2/adversaries').then((adversaries) => {
                    this.adversaries = adversaries;
                    return apiV2('GET', '/api/v2/abilities');
                }).then((abilities) => {
                    this.abilities = abilities;
                    this.getAdversaryTactics();
                    return apiV2('GET', '/api/v2/objectives');
                }).then(async (objectives) => {
                    this.objectives = objectives;

                    while (this.$refs.headerAdversaries) {
                        await sleep(3000);
                        this.abilities = await apiV2('GET', '/api/v2/abilities');
                        this.getAdversaryTactics();
                    }
                }).catch((error) => {
                    toast('Error initializing page', false);
                    console.error(`Error initializing page: ${error}`);
                });
            },

            loadProfile() {
                if (!this.selectedProfileId) return;

                this.selectedProfileAbilities = [];
                this.isCreatingProfile = false;
                this.fieldErrorsProfile = [];

                const selectedAdversary = this.adversaries.find((adversary) => adversary.adversary_id === this.selectedProfileId);
                this.selectedProfileName = selectedAdversary.name;
                this.selectedProfileDescription = selectedAdversary.description;
                this.selectedObjectiveId = this.objectives.find((objective) => objective.id === selectedAdversary.objective).id;
                this.selectedProfileAbilities = selectedAdversary.atomic_ordering.map((ability_id) => ({ ...this.abilities.find((ability) => ability.ability_id === ability_id) }));
                this.abilityIDs = selectedAdversary.atomic_ordering;
                this.adversarySearchQuery = selectedAdversary.name;
                this.findAbilityDependencies();
            },

            saveProfile() {
                this.fieldErrorsProfile = validateInputs({ name: this.selectedProfileName, description: this.selectedProfileDescription }, this.requiredFieldsProfile);
                if (this.fieldErrorsProfile.length) {
                    this.isEditingProfile = true;
                    return;
                }

                const requestBody = {
                    name: this.selectedProfileName,
                    description: this.selectedProfileDescription,
                    objective: this.selectedObjectiveId,
                    atomic_ordering: this.selectedProfileAbilities.map((ability) => ability.ability_id),
                };

                apiV2('PATCH', `/api/v2/adversaries/${this.selectedProfileId}`, requestBody).then((data) => {
                    this.unsavedChanges = false;
                    this.isEditingProfile = false;
                    this.adversaries[this.adversaries.findIndex((profile) => profile.adversary_id === this.selectedProfileId)] = data;
                    this.getAdversaryTactics();
                    toast('Saved profile!', true);
                }).catch((error) => {
                    toast('Error saving profile', false);
                    console.error(error);
                });
            },

            deleteProfile() {
                if (confirm('Are you sure you want to remove this adversary? This cannot be undone.')) {
                    apiV2('DELETE', `/api/v2/adversaries/${this.selectedProfileId}`).then((response) => {
                        this.adversaries.splice(this.adversaries.findIndex((a) => a.adversary_id === this.selectedProfileId), 1);
                        this.selectedProfileId = '';
                        this.getAdversaryTactics();
                        this.adversarySearchQuery = '';
                        toast('Adversary profile deleted.', true);
                    }).catch((error) => {
                        toast('Error deleting profile', false);
                        console.error(error);
                    });
                }
            },

            createProfile() {
                this.fieldErrorsProfile = validateInputs({ name: this.createProfileName, description: this.createProfileDescription }, this.requiredFieldsProfile);
                if (this.fieldErrorsProfile.length) return;

                const newId = uuidv4();
                const requestBody = {
                    adversary_id: newId,
                    name: this.createProfileName,
                    description: this.createProfileDescription,
                    atomic_ordering: [],
                    objective: this.objectives.find((o) => o.name === 'default').id,
                    tags: [],
                };

                apiV2('POST', '/api/v2/adversaries', requestBody).then((response) => {
                    this.adversaries.push(requestBody);
                    this.adversaries = this.adversaries.sort((a, b) => a.name > b.name);
                    this.selectedProfileId = newId;
                    this.getAdversaryTactics();
                    this.loadProfile();
                    this.isCreatingProfile = false;
                    toast('Created profile!', true);
                }).catch((error) => {
                    toast('Error creating profile', false);
                    console.error(error);
                });
            },

            cancelCreateProfile() {
                this.createProfileName = '';
                this.createProfileDescription = '';
                this.isCreatingProfile = false;
            },

            uploadAdversaryFile(el) {
                if (!el.files || !el.files.length) return;
                this.adversaryImportFile = el.files[0];
                const reader = new FileReader();
                reader.onload = (event) => this.adversaryImportFileContent = event.target.result;
                reader.readAsText(this.adversaryImportFile);
            },

            importProfile() {
                let keyValSplit;
                let lastKey;
                let profile = {};
                const lines = this.adversaryImportFileContent.split('\n');
                lines.forEach((line) => {
                    // Remove comments
                    line = line.split('#')[0];
                    // Line has a key-value pair
                    keyValSplit = line.split(':');
                    if (keyValSplit.length >= 2) {
                        if (keyValSplit[1]) {
                            profile[keyValSplit[0]] = keyValSplit[1].trim();
                        } else {
                            lastKey = keyValSplit[0];
                            profile[lastKey] = [];
                        }
                    }
                    // Line is a list item
                    if (line.trim()[0] === '-' && line.trim() !== '---') {
                        profile[lastKey].push(line.replace('-', '').trim());
                    }
                });
               
                apiV2('POST', '/api/v2/adversaries', profile).then((response) => {
                    this.adversaries.push(response);
                    this.adversaries = this.adversaries.sort((a, b) => a.name > b.name);
                    this.selectedProfileId = response.adversary_id;
                    this.getAdversaryTactics();
                    this.loadProfile();
                    this.showImportModal = false;
                    toast('Profile imported!', true);
                }).catch((error) => {
                    toast('Error importing profile, please ensure YAML file is in correct format.', false);
                    console.error(error);
                });
            },

            exportProfile() {
                let yaml = `id: ${this.selectedProfileId}\n`;
                yaml += `name: ${this.selectedProfileName}\n`;
                yaml += `description: ${this.selectedProfileDescription}\n`;
                yaml += `objective: ${this.selectedObjectiveId}\n`;
                yaml += `atomic_ordering:\n`;
                this.selectedProfileAbilities.forEach((ability, index) => 
                    ability.ability_id ? yaml += `- ${ability.ability_id}\n` : yaml += `- ${this.abilityIDs[index]}\n`);
                const blob = new Blob([yaml], { type: 'application/x-yaml' })
                const url = window.URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.style.display = 'none';
                a.href = url;
                a.download = `${this.selectedProfileName}.yaml`;
                document.body.appendChild(a);
                a.click();
                window.URL.revokeObjectURL(url);
            },


            getAdversaryTactics() {
                this.adversaries.forEach((adversary) => {
                    let tactics = adversary.atomic_ordering.map((ability_id) => {
                        let match = this.abilities.find((ability) => ability.ability_id === ability_id);
                        return match ? match.tactic : null;
                    });
                    adversary.tactics = [...new Set(tactics)];
                });
                this.adversarySearchResults = this.adversaries;
                this.searchForAdversary()
            },

            linkObjective() {
                apiV2('PATCH', `/api/v2/adversaries/${this.selectedProfileId}`, { objective: this.selectedObjectiveId }).then((data) => {
                    toast('New objective linked', true);
                    this.showObjectiveModal = false;
                }).catch((error) => {
                    toast('Error saving profile', false);
                    console.error(error);
                });
            },

            getExecutorDetail(detail, ability) {
                const executorNameMap = new Map([
                    ['psh', 'powershell'],
                    ['pwsh', 'powershell core'],
                    ['sh', 'shell'],
                    ['cmd', 'commandline'],
                ]);
                const plats = [];
                let hasCleanup = false;
                let hasPayload = false;
                let hasParser = false;

                if(ability.executors)
                {
                    ability.executors.forEach((executor) => {
                        if (executor.cleanup.length > 0) hasCleanup = true;
                        if (executor.parsers.length > 0) hasParser = true;
                        if (executor.payloads.length > 0) hasPayload = true;
                        plats.push(`${executor.platform} (${executorNameMap.get(executor.name) || executor.name})`);
                    });
                }

                switch (detail) {
                case 'cleanup':
                    return hasCleanup;
                case 'parser':
                    return hasParser;
                case 'payload':
                    return hasPayload;
                case 'requirements':
                    if(ability.requirements){
                        return ability.requirements.length > 0;
                    }
                case 'platforms':
                    return plats;
                default:
                    return false;
                }
            },

            findAbilityDependencies() {
                const types = {};
                let factsCollected = [];
                let factsRequired = [];
                this.undefinedAbilities = [];

                this.selectedProfileAbilities.forEach((ability, index) => {	
                    let requireTypes = [];
                    let enableTypes = [];

                    //skip building out enable types and require types if ability is unknown
                    if(ability.ability_id != undefined) {    

                        // Get all parser types from executors
                        ability.executors.forEach((executor) => {
                            executor.parsers.forEach((parser) => {
                                enableTypes = enableTypes.concat(parser.parserconfigs.map((rel) => rel.source));
                            });
                        });

                        // Get all requirement types
                        ability.requirements.forEach((requirement) => {
                            requireTypes = requireTypes.concat(requirement.relationship_match.map((match) => match.source));
                        });
                    
                    } else {
                        this.undefinedAbilities.push(ability.ability_id);
                    }

                    types[ability.ability_id] = {
                        enableTypes: [...new Set(enableTypes)],
                        requireTypes: [...new Set(requireTypes)]
                    };
                });

                this.selectedProfileAbilities.forEach((ability, index) => {
                    const enablesAbilityIds = [];
                    const requiresAbilityIds = [];
                    const requireTypesMet = [];

                    // For each parser, look at and forward for any ability it unlocks
                    types[ability.ability_id].enableTypes.forEach((key) => {
                        if(this.selectedProfileAbilities) {
                            for (let i = index; i < this.selectedProfileAbilities.length; i++) {
                                if (types[this.selectedProfileAbilities[i].ability_id].requireTypes.indexOf(key) > -1) {
                                    enablesAbilityIds.push(this.selectedProfileAbilities[i].ability_id);
                                }
                            }
                        }
                    });

                    // For each requirement, look at and before for any ability to unlock it
                    types[ability.ability_id].requireTypes.forEach((requirement) => {
                        let requirementMet = false;
                        for (let i = index; i >= 0; i--) {
                            if (types[this.selectedProfileAbilities[i].ability_id].enableTypes.indexOf(requirement) > -1) {
                                requiresAbilityIds.push(this.selectedProfileAbilities[i].ability_id);
                                requirementMet = true;
                            }
                        }
                        requireTypesMet.push(requirementMet);
                    });

                    this.abilityDependencies[ability.ability_id] = {
                        // The ability IDs that this ability will enable
                        enablesAbilityIds: [...new Set(enablesAbilityIds)],
                        // The ability IDs that this ability is dependent on
                        requiresAbilityIds: [...new Set(requiresAbilityIds)],
                        // The names of the parser requirements this ability enables
                        enableTypes: types[ability.ability_id].enableTypes,
                        // The names of the requirements this ability needs from a parser
                        requireTypes: types[ability.ability_id].requireTypes,
                        // Same dimension as requireTypes, but true/false if requirement has been met
                        requireTypesMet: requireTypesMet,
                    };

                    // Update fact totals for fact breakdown
                    factsCollected = factsCollected.concat(types[ability.ability_id].enableTypes);
                    factsRequired = factsRequired.concat(types[ability.ability_id].requireTypes);
                });

                this.factBreakdown = [];
                factsCollected = [...new Set(factsCollected)];
                factsRequired = [...new Set(factsRequired)];
                factsRequired.forEach((fact) => {
                    this.factBreakdown.push({ fact: fact, type: factsCollected.includes(fact) ? 'met' : 'unmet' });
                });
                factsCollected.filter(x => !factsRequired.includes(x)).forEach((fact) => {
                    this.factBreakdown.push({ fact: fact, type: 'extra' });
                });

                this.hasMetAbilityDependencies();
            },

            hasMetAbilityDependencies() {
                const keys = [];
                let isMet = true;
                this.needsParser = [];

                Object.keys(this.abilityDependencies).forEach((abilityId) => {
                    if (!this.abilityDependencies[abilityId].requireTypesMet.every(((requirement) => requirement))) {
                        isMet = false;
                        try {
                            this.needsParser.push(this.selectedProfileAbilities.find((ability) => ability.ability_id === abilityId).name);
                        } catch {
                            this.needsParser.push();
                        }
                    }
                });

                return isMet;
            },

            setAbilityHover(abilityId) {
                this.onHoverLocks = this.abilityDependencies[abilityId].requiresAbilityIds;
                this.onHoverUnlocks = this.abilityDependencies[abilityId].enablesAbilityIds;
                if (this.abilityDependencies[abilityId].requireTypes.length) this.onHoverUnlocks.push(abilityId);
                if (this.abilityDependencies[abilityId].enableTypes.length) this.onHoverLocks.push(abilityId);
            },

            clearAbilityHover() {
                this.onHoverLocks = [];
                this.onHoverUnlocks = [];
            },

            getObjectiveName() {
                let obj = this.objectives.find((o) => o.id === this.selectedObjectiveId);
                return obj ? obj.name : '';
            },

            getAbilityExecutors() {
                return this.selectedAbility.executors || [];
            },

            loadProfileAdversary() {
                if (!this.selectedAddAdversary) return;

                this.abilitiesAddAdversary = [];

                apiV2('GET', `/api/v2/adversaries/${this.selectedAddAdversary}`).then((adversary) => {
                    this.abilitiesAddAdversary = adversary.atomic_ordering.map((ability_id) => ({
                        ...this.abilities.find((ability) => ability.ability_id === ability_id),
                        selected: true
                    }));
                }).catch((error) => {
                    toast('Error loading adversary profile', false);
                    console.error(error);
                });
            },

            addAbilitiesFromAdversary() {
                const selectedAbilities = this.abilitiesAddAdversary.filter((a) => a.selected);
                this.selectedProfileAbilities = this.selectedProfileAbilities.concat(selectedAbilities);
                this.showAddAdversaryModal = false;
                this.selectedAddAdversary = '';
                this.abilitiesAddAdversary = [];
                this.unsavedChanges = true;
            },

            addExecutorToAbility(bOrA) {
                const template = {
                    payloads: [],
                    parsers: [],
                    cleanup: [],
                    platform: 'linux'
                };

                if (bOrA === 'after') {
                    this.selectedAbility.executors.push(template);
                } else if (bOrA === 'before') {
                    this.selectedAbility.executors.unshift(template);
                }
            },

            searchForAutoFill(field = 'tactic') {
                const results = new Set();
                if (!this.selectedAbility[field]) return;
                this.abilities.forEach((ability) => {
                    if (ability[field].toLowerCase().indexOf(this.selectedAbility[field].toLowerCase()) > -1) {
                        results.add(ability[field]);
                    }
                });
                this.searchResults = Array.from(results);
            },

            searchForAdversary() {
                this.adversarySearchResults = this.adversaries.filter((adversary) => (
                    (adversary.name.toLowerCase().indexOf(this.adversarySearchQuery.toLowerCase()) > -1) ||
                    (adversary.tactics.find((tactic) => {
                        if (!tactic) return false;
                        return tactic.toLowerCase().indexOf(this.adversarySearchQuery.toLowerCase()) > -1;
                    }))
                ));
            },

            selectAdversary(id, name) {
                this.selectedProfileId = id;
                this.loadProfile();
                this.adversarySearchResults = this.adversaries;
            },

            searchForAbility() {
                this.abilitySearchResults = [];
                if (!this.abilitySearchQuery) return;
                this.abilities.forEach((ability) => {
                    if (ability.name.toLowerCase().indexOf(this.abilitySearchQuery.toLowerCase()) > -1) {
                        this.abilitySearchResults.push({
                            ability_id: ability.ability_id,
                            name: ability.name
                        });
                    }
                });
            },

            selectAbility(id) {
                this.abilitySearchQuery = [];
                this.abilitySearchResults = [];
                this.selectedAbility = this.abilities.find((ability) => ability.ability_id === id);
                this.selectedTactic = this.selectedAbility.tactic;
                this.selectedTechnique = this.selectedAbility.technique_id;
                this.selectedAbilityId = id;
                this.showAbilityChoiceModal = true;
            },

            getPlatforms(platform) {
                let plats = Object.keys(this.platforms);
                let index = plats.indexOf(platform);
                if (index !== 0) {
                    plats[index] = plats[0];
                    plats[0] = platform;
                }
                return plats;
            },

            getExecutors(platform, executor) {
                let execs = this.platforms[platform];
                let index = execs.indexOf(executor);
                if (index !== 0) {
                    execs[index] = execs[0];
                    execs[0] = executor;
                }
                return execs;
            },

            saveAbility(addToAdversary) {
                this.fieldErrorsAbility = validateInputs(this.selectedAbility, this.requiredFieldsAbility);
                if (this.fieldErrorsAbility.length) return;

                apiV2('PATCH', `/api/v2/abilities/${this.selectedAbilityId}`, this.selectedAbility).then((response) => {
                    toast('Saved ability!', true);

                    // Replace ability in list with updated info
                    const index = this.selectedProfileAbilities.findIndex((ability) => ability.ability_id === this.selectedAbilityId);
                    this.selectedProfileAbilities[index] = response;

                    if (addToAdversary) {
                        this.selectedProfileAbilities.push(response);
                        this.unsavedChanges = true;
                        this.selectedAbilityId = '';
                        this.showAbilityChoiceModal = false;
                    }
                }).catch((error) => {
                    toast('Error saving ability', false);
                    console.error(error);
                });
            },

            removeAbility(index) {
                this.selectedProfileAbilities.splice(index, 1);
                this.unsavedChanges = true;
            },

            startAbilitySwap(event) {
                this.abilityTableDragTarget = event.target.parentNode;
                this.abilityTableDragTargetIndex = parseInt(this.abilityTableDragTarget.children[1].children[0].children[0].innerHTML, 10);
            },

            swapAbilitiesHover(event) {
                const children = Array.from(event.target.parentNode.parentNode.children);

                if (children.indexOf(event.target.parentNode) > children.indexOf(this.abilityTableDragTarget)) {
                    this.abilityTableDragEndIndex = parseInt(event.target.parentNode.children[1].children[0].children[0].innerHTML, 10);
                } else {
                    this.abilityTableDragEndIndex = parseInt(event.target.parentNode.children[1].children[0].children[0].innerHTML, 10);
                }
            },
            
            dragAbility(event){
                const fromIndex = this.abilityTableDragTargetIndex - 1;
                const toIndex = this.abilityTableDragEndIndex - 1;
                const temp = this.selectedProfileAbilities[fromIndex];
                this.selectedProfileAbilities.splice(fromIndex, 1);
                this.selectedProfileAbilities.splice(toIndex, 0, temp);

                this.unsavedChanges = true;
                this.abilityTableDragHoverId = undefined;
                this.abilityTableDragEndIndex = undefined;
            },

            getTacticBreakdown() {
                if (!this.selectedProfileAbilities) return;
                let counts = {};
                this.selectedProfileAbilities.forEach((ability) => {
                    counts[ability.tactic] ? counts[ability.tactic] += 1 : counts[ability.tactic] = 1;
                });
                return Object.keys(counts).map((tactic) => {
                    let percent = Math.ceil(counts[tactic] / this.selectedProfileAbilities.length * 10000) / 100
                    return [tactic, percent]
                })
            },

            hashStringToColor(str) {
                let hash = 5381;
                if(str) {
                    for (let i = 0; i < str.length; i++) {
                        hash = ((hash << 5) + hash) + str.charCodeAt(i);
                    }
                }

                let r = (hash & 0xFF0000) >> 16;
                let g = (hash & 0x00FF00) >> 8;
                let b = hash & 0x0000FF;
                return "#" + ("0" + r.toString(16)).substr(-2) + ("0" + g.toString(16)).substr(-2) + ("0" + b.toString(16)).substr(-2);
            }

        };
    }

    // # sourceURL=adversaries.js
</script>

<style scoped>
    .ability-row > td {
        cursor: pointer;
    }

    .ability-row > th {
        border: 0 !important;
    }

    #select-adversary {
        max-width: 800px;
        margin: 0 auto;
    }

    .code {
        font-family: monospace;
    }

    .control-buttons>.button {
        margin: 0 10px 10px 0;
    }

    .drag {
        cursor: grab;
    }

    .file-cta {
        background-color: #262626;
    }
    .file-label:hover .file-cta {
        background-color: #1e1e1e;
    }

    .lock {
        background-color: blueviolet !important;
    }

    .no-underline.has-tooltip-arrow {
        border-bottom: none;
    }

    .no-pointer {
        cursor: default;
    }

    .pointer {
        cursor: pointer;
    }

    .red-row-unclickable {
        pointer-events: none;
        font-weight: bold;
        border: 3px solid #8B0000;
    }

    .orange-row {
        border: 2px solid orange;
    }

    .row-hover {
        background-color: #484848 !important;
    }

    .row-hover-above {
      border-top: 2px solid green;
    }

    .row-hover-below {
      border-bottom: 2px solid green;
    }

    .tactic-breakdown {
        display: table;
        width: 100%;
        overflow: hidden;
        white-space: nowrap;
        cursor: pointer;
        user-select: none;
        transform-style: preserve-3d;
    }

    .tactic-item {
        display: table-cell;
        line-height: 8px;
        text-indent: -9999px;
        border-bottom: none !important;
    }
    .tactic-item.active {
        line-height: 30px;
        text-indent: 6px;
        font-size: .7em;
    }

    .unlock {
        background-color: coral !important;
    }

    .vr {
        width: 1px;
        height: 30px;
        margin: 0 20px 0 10px;
        background-color: grey;
    }
</style>
