<UserControl xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:vm="using:DodoSSH.Client.Shell.ViewModels"
             x:Class="DodoSSH.Client.App.Views.SnippetsScreen"
             x:DataType="vm:SnippetsViewModel">

  <!--
    Commands somebody has saved, and how to get one into a terminal.

    The list and the writing belong to the vault, as every other item kind's do; this screen is the filter,
    the editor and the insert over the top. See SnippetsViewModel.

    The two buttons at the bottom right are the whole safety design, and their wording is load-bearing.
    A terminal is one input stream with no notion of being at a prompt — the remote may be inside vi, or at
    a sudo password prompt with echo off — so this application cannot say "run this command", only "type
    this into whatever is there". RUN appears solely for a snippet whose own flag says it runs, which makes
    that a decision taken once while writing it rather than a button beside every one of them.
  -->

  <Grid ColumnDefinitions="*,300">

    <Grid Grid.Column="0" RowDefinitions="Auto,*,Auto">

      <Border Grid.Row="0" Padding="14,0" Height="44"
              BorderBrush="{StaticResource Border}" BorderThickness="0,0,0,1">
        <Grid ColumnDefinitions="Auto,*,Auto" VerticalAlignment="Center">
          <TextBlock Grid.Column="0" Classes="mono" Text="SNIPPETS" FontSize="12"
                     FontWeight="SemiBold" LetterSpacing="1" Foreground="{StaticResource Text}"
                     VerticalAlignment="Center" />
          <TextBlock Grid.Column="1" Classes="mono" Text="{Binding Status}" FontSize="10.5"
                     Foreground="{StaticResource TextFaint}" Margin="10,0,0,0"
                     TextTrimming="CharacterEllipsis" VerticalAlignment="Center" />

          <!--
            The command is searched as well as the name: half of what anybody remembers about a saved
            command is a word that was inside it.
          -->
          <TextBox Grid.Column="2" x:Name="SnippetFilter" Text="{Binding Filter}" Width="240"
                   PlaceholderText="filter by name or command" VerticalAlignment="Center" />
        </Grid>
      </Border>

      <ListBox Grid.Row="1" x:Name="SnippetList" Focusable="True"
               ItemsSource="{Binding Visible}"
               SelectedItem="{Binding Selected}">
        <ListBox.ItemTemplate>
          <DataTemplate x:DataType="vm:SnippetRowViewModel">
            <Grid ColumnDefinitions="2,*" Margin="0,7,14,7">
              <Border Grid.Column="0" Classes="rowmark" />
              <StackPanel Grid.Column="1" Margin="12,0,0,0" Spacing="2">
                <StackPanel Orientation="Horizontal" Spacing="6">
                  <TextBlock Classes="mono" Text="{Binding Label}" FontSize="12" FontWeight="Medium"
                             Foreground="{StaticResource Text}" TextTrimming="CharacterEllipsis" />
                  <!--
                    The flag, where the decision is made. A snippet that presses Enter for you is not the
                    same kind of thing as one that does not, and the list is where somebody chooses between
                    them.
                  -->
                  <Border Classes="chip warn" Padding="4,0" IsVisible="{Binding RunsOnInsert}">
                    <TextBlock Text="runs immediately" FontSize="9.5" />
                  </Border>
                  <Border Classes="chip warn" Padding="4,0"
                          IsVisible="{Binding Badge, Converter={x:Static StringConverters.IsNotNullOrEmpty}}">
                    <TextBlock Text="{Binding Badge}" FontSize="9.5" />
                  </Border>
                  <!--
                    Which vault this one is in, drawn only where there is more than one to be in. A shared
                    snippet is a command the rest of a team can read and insert; the row is where somebody
                    decides whether the thing they are about to edit is theirs alone.
                  -->
                  <Border Classes="chip" Padding="4,0" IsVisible="{Binding HasVaultBadge}">
                    <TextBlock Text="{Binding VaultBadge}" FontSize="9.5" />
                  </Border>
                </StackPanel>
                <!--
                  Newlines shown as ⏎ rather than dropped. A three-line snippet flattened into one run of
                  text reads as a single command, which is the thing being decided about on this row.
                -->
                <TextBlock Classes="mono" Text="{Binding Preview}" FontSize="10.5"
                           Foreground="{StaticResource TextFaint}" TextTrimming="CharacterEllipsis" />
              </StackPanel>
            </Grid>
          </DataTemplate>
        </ListBox.ItemTemplate>
      </ListBox>

      <TextBlock Grid.Row="1" Classes="hint" Text="{Binding EmptyMessage}" FontSize="12"
                 Margin="24" HorizontalAlignment="Center" VerticalAlignment="Center"
                 TextAlignment="Center" MaxWidth="360"
                 IsVisible="{Binding !HasVisible}" />

      <Border Grid.Row="2" Padding="14,8" BorderBrush="{StaticResource BorderSubtle}"
              BorderThickness="0,1,0,0">
        <StackPanel Orientation="Horizontal" Spacing="6">
          <Button Classes="ghost" Content="+ NEW SNIPPET" Command="{Binding NewCommand}" />
          <Button Classes="ghost" Content="EDIT" Command="{Binding EditCommand}"
                  IsEnabled="{Binding HasSelection}" />
          <Button Classes="ghost" Content="DELETE" Command="{Binding DeleteCommand}"
                  IsEnabled="{Binding HasSelection}" />
          <!--
            Sharing a snippet, which is what moving one into a team's vault is. Beside EDIT rather than
            inside it: the two vaults are encrypted under different keys, so this is a re-seal into one and
            a tombstone in the other — nothing a SAVE could do — and a picker inside the form would let
            somebody correcting a typo hand a command to a team by leaving it where they found it. The
            picker itself opens beside the snippet, in the pane on the right.
          -->
          <Button Classes="ghost" Content="MOVE TO VAULT…" Command="{Binding MoveCommand}"
                  IsEnabled="{Binding CanMove}"
                  ToolTip.Tip="Re-encrypts this snippet with another vault's key. Everybody who holds that key can then read and insert it." />
        </StackPanel>
      </Border>

    </Grid>

    <Border Grid.Column="1" Background="{StaticResource Sidebar}"
            BorderBrush="{StaticResource Border}" BorderThickness="1,0,0,0">
      <ScrollViewer>
        <StackPanel Margin="14,16" Spacing="8">

          <!-- ============ The editor ============ -->
          <StackPanel Spacing="6" IsVisible="{Binding IsEditing}">
            <TextBox Text="{Binding EditorLabel}" PlaceholderText="name" />

            <!--
              Which vault a *new* snippet is filed into, asked on the form it is being typed into rather
              than through a standing preference elsewhere. Not drawn for an existing snippet — its vault is
              not a field of this form, and changing it is MOVE — and not drawn at all where there is only
              one vault to choose between, because a control offering one option is a question nobody asked.
            -->
            <StackPanel Spacing="4" IsVisible="{Binding ShowsEditorVaultChoice}">
              <TextBlock Classes="label" Text="VAULT" />
              <ComboBox HorizontalAlignment="Stretch" ItemsSource="{Binding EditorVaultChoices}"
                        SelectedItem="{Binding EditorSelectedVault}">
                <ComboBox.ItemTemplate>
                  <DataTemplate x:DataType="vm:VaultChoiceViewModel">
                    <TextBlock Text="{Binding Display}" FontSize="12" />
                  </DataTemplate>
                </ComboBox.ItemTemplate>
              </ComboBox>
              <TextBlock Classes="hint" FontSize="10.5" TextWrapping="Wrap"
                         Text="A shared vault means everybody holding its key can read this command and insert it into their own terminals." />
            </StackPanel>

            <!--
              Stored exactly as typed — no trimming, no newline normalisation. A here-document's terminator
              has to arrive on a line of its own, and tidying the trailing newline off it leaves the shell
              waiting for one that never comes.
            -->
            <TextBox Text="{Binding EditorCommand}" PlaceholderText="the command" AcceptsReturn="True"
                     Height="140" TextWrapping="NoWrap" FontFamily="{StaticResource MonoFont}"
                     FontSize="12" />
            <TextBox Text="{Binding EditorNotes}" PlaceholderText="notes" AcceptsReturn="True"
                     Height="48" TextWrapping="Wrap" />
            <CheckBox IsChecked="{Binding EditorRunsOnInsert}"
                      Content="Press Enter after inserting this" />
            <TextBlock Classes="hint" FontSize="11" TextWrapping="Wrap"
                       Text="Off means the command is typed at the prompt and waits for you. That single Enter is the only thing standing between a saved command and a running one, so leave it off unless you meant it." />
            <StackPanel Orientation="Horizontal" Spacing="6">
              <Button Classes="accent" Content="SAVE" Command="{Binding SaveCommand}" />
              <Button Classes="ghost" Content="CANCEL" Command="{Binding CancelCommand}" />
            </StackPanel>
          </StackPanel>

          <!-- ============ The selected snippet ============ -->
          <StackPanel Spacing="6" IsVisible="{Binding !IsEditing}">

            <TextBlock Classes="hint" FontSize="12"
                       Text="Choose a snippet to see it in full and put it into a terminal."
                       IsVisible="{Binding !HasSelection}" />

            <StackPanel Spacing="6" IsVisible="{Binding HasSelection}">
              <TextBlock Classes="mono" Text="{Binding Selected.Label}" FontSize="13"
                         FontWeight="SemiBold" Foreground="{StaticResource Text}" TextWrapping="Wrap" />

              <!--
                Named here as well as on the row, because this pane is where somebody decides to put a
                command into a production terminal, and who else holds a key to it is part of that decision.
                The row's badge is off the screen by the time this is being read.
              -->
              <Border Classes="chip" Padding="4,0" HorizontalAlignment="Left"
                      IsVisible="{Binding HasSelectionVaultBadge}">
                <TextBlock Text="{Binding SelectionVaultBadge}" FontSize="9.5" />
              </Border>

              <TextBlock Classes="label" Text="COMMAND" Margin="0,10,0,4" />
              <Border Background="{StaticResource Raised}" BorderBrush="{StaticResource Border}"
                      BorderThickness="1" CornerRadius="4" Padding="8">
                <SelectableTextBlock Classes="mono" Text="{Binding Selected.Snippet.Command}"
                                     FontSize="10.5" Foreground="{StaticResource TextDim}"
                                     TextWrapping="Wrap" />
              </Border>

              <TextBlock Classes="mono" Text="{Binding Selected.Snippet.Notes}" FontSize="11"
                         Foreground="{StaticResource TextFaint}" TextWrapping="Wrap" Margin="0,6,0,0"
                         IsVisible="{Binding Selected.Snippet.Notes, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />

              <!--
                The button names the tab it will type into. This screen is not the terminal — the strip
                above it is — so "INSERT" alone would leave somebody working out which of six open tabs is
                about to receive a command, at the moment that is worst to be wrong about.
              -->
              <StackPanel Spacing="6" IsVisible="{Binding ShowsSelectionActions}">
                <Button Classes="accent" Content="{Binding InsertLabel}" Margin="0,14,0,0"
                        HorizontalAlignment="Left"
                        Command="{Binding InsertCommand}" IsEnabled="{Binding CanInsert}"
                        ToolTip.Tip="Types the command at the prompt and stops. Nothing runs until you press Enter there." />

                <Button Classes="danger" Content="{Binding RunLabel}" HorizontalAlignment="Left"
                        Command="{Binding RunCommand}"
                        IsVisible="{Binding SelectionRuns}" IsEnabled="{Binding CanInsert}"
                        ToolTip.Tip="Types the command and presses Enter. Offered because this snippet is marked as one that runs." />

                <TextBlock Classes="hint" FontSize="11" TextWrapping="Wrap" Margin="0,10,0,0"
                           Text="Whatever is in the terminal receives this. Nothing here can tell whether that is a shell prompt, an editor, or a password prompt with the echo off — so check the tab before you insert." />
              </StackPanel>

              <!--
                ◆ SHARING THE SNIPPET, which is what moving it into a team's vault amounts to. A picker and
                two buttons, not a question with a yes: what is being asked is which vault, and a move is
                undone by moving it back rather than by being careful — so this is not drawn in the danger
                colours the deletion question uses.

                It takes the insert controls' place while it is up, for the reason the host pane hides
                CONNECT: the button that opened this is still on screen otherwise, offering to open it again.

                The sentence is the part worth keeping. Unlike a host, a snippet crosses whole — it has no
                group and no tags to leave behind — so what there is to say is who can read it afterwards,
                and for a command that may carry a hostname or a path that is the whole of the decision.
              -->
              <StackPanel Spacing="8" Margin="0,14,0,0" IsVisible="{Binding IsMoving}">
                <TextBlock Classes="label" Text="MOVE TO VAULT" />
                <ComboBox HorizontalAlignment="Stretch" ItemsSource="{Binding MoveVaultChoices}"
                          SelectedItem="{Binding SelectedMoveVault}">
                  <ComboBox.ItemTemplate>
                    <DataTemplate x:DataType="vm:VaultChoiceViewModel">
                      <TextBlock Text="{Binding Display}" FontSize="12" />
                    </DataTemplate>
                  </ComboBox.ItemTemplate>
                </ComboBox>
                <TextBlock Classes="hint" FontSize="10.5" TextWrapping="Wrap"
                           Text="The snippet is re-encrypted with the other vault's key, so everybody who holds that key can read this command and insert it — and nobody else can. Nothing else about it changes." />
                <StackPanel Orientation="Horizontal" Spacing="6">
                  <Button Classes="accent" Content="MOVE" Command="{Binding ConfirmMoveCommand}" />
                  <Button Classes="ghost" Content="CANCEL" Command="{Binding CancelMoveCommand}" />
                </StackPanel>
              </StackPanel>
            </StackPanel>
          </StackPanel>

        </StackPanel>
      </ScrollViewer>
    </Border>

  </Grid>

</UserControl>
