<template>
  <b-container fluid="xl">
    <page-title
      description="Configure network settings for the BMC and the Virtualization management interface"
    />
    <page-section section-title="Interface">
      <b-row>
        <b-col lg="3">
          <b-form-group label-for="interface-select" label="Network interface">
            <b-form-select
              id="interface-select"
              v-model="selectedInterfaceIndex"
              :options="interfaceSelectOptions"
              @change="selectInterface"
            >
            </b-form-select>
          </b-form-group>
        </b-col>
      </b-row>
    </page-section>
    <b-form novalidate @submit.prevent="submitForm">
      <page-section section-title="System">
        <b-row>
          <b-col lg="3">
            <b-form-group label="Default gateway" label-for="default-gateway">
              <b-form-input
                id="default-gateway"
                v-model.trim="form.gateway"
                type="text"
                :readonly="dhcpEnabled"
                :state="getValidationState($v.form.gateway)"
                @change="$v.form.gateway.$touch()"
              />
              <b-form-invalid-feedback role="alert">
                <div v-if="!$v.form.gateway.required">Field required</div>
                <div v-if="!$v.form.gateway.validateAddress">Invalid</div>
              </b-form-invalid-feedback>
            </b-form-group>
          </b-col>
          <b-col lg="3">
            <b-form-group label="Hostname" label-for="hostname-field">
              <b-form-input
                id="hostname-field"
                v-model.trim="form.hostname"
                type="text"
                :state="getValidationState($v.form.hostname)"
                @change="$v.form.hostname.$touch()"
              />
              <b-form-invalid-feedback role="alert">
                <div v-if="!$v.form.hostname.required">Field required</div>
                <div v-if="!$v.form.hostname.validateHostname">
                  Must be less than 64 characters
                </div>
              </b-form-invalid-feedback>
            </b-form-group>
          </b-col>
          <b-col lg="3">
            <b-form-group label="MAC address" label-for="mac-address">
              <b-form-input
                id="mac-address"
                v-model.trim="form.macAddress"
                type="text"
                :state="getValidationState($v.form.macAddress)"
                @change="$v.form.macAddress.$touch()"
              />
              <b-form-invalid-feedback role="alert">
                <div v-if="!$v.form.macAddress.required">Field required</div>
                <div v-if="!$v.form.macAddress.validateMacAddress">Invalid</div>
              </b-form-invalid-feedback>
            </b-form-group>
          </b-col>
        </b-row>
      </page-section>
      <page-section section-title="Static IPv4">
        <b-row>
          <b-col lg="9" class="mb-3">
            <b-table
              :fields="ipv4StaticTableFields"
              :items="form.ipv4StaticTableItems"
              class="mb-0"
            >
              <template v-slot:cell(Address)="{ item, index }">
                <b-form-input
                  v-model.trim="item.Address"
                  :aria-label="'Static IPV4 address ' + (index + 1)"
                  :readonly="dhcpEnabled"
                  :state="
                    getValidationState(
                      $v.form.ipv4StaticTableItems.$each.$iter[index].Address
                    )
                  "
                  @change="
                    $v.form.ipv4StaticTableItems.$each.$iter[
                      index
                    ].Address.$touch()
                  "
                />
                <b-form-invalid-feedback role="alert">
                  <div
                    v-if="
                      !$v.form.ipv4StaticTableItems.$each.$iter[index].Address
                        .required
                    "
                  >
                    Field required
                  </div>
                  <div
                    v-if="
                      !$v.form.ipv4StaticTableItems.$each.$iter[index].Address
                        .validateAddress
                    "
                  >
                    Invalid
                  </div>
                </b-form-invalid-feedback>
              </template>
              <template v-slot:cell(SubnetMask)="{ item, index }">
                <b-form-input
                  v-model.trim="item.SubnetMask"
                  :aria-label="'Static IPV4 Subnet mask ' + (index + 1)"
                  :readonly="dhcpEnabled"
                  :state="
                    getValidationState(
                      $v.form.ipv4StaticTableItems.$each.$iter[index].SubnetMask
                    )
                  "
                  @change="
                    $v.form.ipv4StaticTableItems.$each.$iter[
                      index
                    ].SubnetMask.$touch()
                  "
                />
                <b-form-invalid-feedback role="alert">
                  <div
                    v-if="
                      !$v.form.ipv4StaticTableItems.$each.$iter[index]
                        .SubnetMask.required
                    "
                  >
                    Field required
                  </div>
                  <div
                    v-if="
                      !$v.form.ipv4StaticTableItems.$each.$iter[index]
                        .SubnetMask.validateAddress
                    "
                  >
                    Invalid
                  </div>
                </b-form-invalid-feedback>
              </template>
              <template v-slot:cell(actions)="{ item, index }">
                <table-row-action
                  v-for="(action, actionIndex) in item.actions"
                  :key="actionIndex"
                  :value="action.value"
                  :title="action.title"
                  @click:tableAction="onDeleteIpv4StaticTableRow($event, index)"
                >
                  <template v-slot:icon>
                    <icon-trashcan v-if="action.value === 'delete'" />
                  </template>
                </table-row-action>
              </template>
            </b-table>
            <b-button variant="link" @click="addIpv4StaticTableRow">
              <icon-add /> Add static IP
            </b-button>
          </b-col>
        </b-row>
      </page-section>
      <page-section section-title="Static DNS">
        <b-row>
          <b-col lg="4" class="mb-3">
            <b-table
              :fields="dnsTableFields"
              :items="form.dnsStaticTableItems"
              class="mb-0"
            >
              <template v-slot:cell(address)="{ item, index }">
                <b-form-input
                  v-model.trim="item.address"
                  :aria-label="'Static DNS ' + (index + 1)"
                  :readonly="dhcpEnabled"
                  :state="
                    getValidationState(
                      $v.form.dnsStaticTableItems.$each.$iter[index].address
                    )
                  "
                  @change="
                    $v.form.dnsStaticTableItems.$each.$iter[
                      index
                    ].address.$touch()
                  "
                />
                <b-form-invalid-feedback role="alert">
                  <div
                    v-if="
                      !$v.form.dnsStaticTableItems.$each.$iter[index].address
                        .required
                    "
                  >
                    Field required
                  </div>
                  <div
                    v-if="
                      !$v.form.dnsStaticTableItems.$each.$iter[index].address
                        .validateAddress
                    "
                  >
                    Invalid
                  </div>
                </b-form-invalid-feedback>
              </template>
              <template v-slot:cell(actions)="{ item, index }">
                <table-row-action
                  v-for="(action, actionIndex) in item.actions"
                  :key="actionIndex"
                  :value="action.value"
                  :title="action.title"
                  @click:tableAction="onDeleteDnsTableRow($event, index)"
                >
                  <template v-slot:icon>
                    <icon-trashcan v-if="action.value === 'delete'" />
                  </template>
                </table-row-action>
              </template>
            </b-table>
            <b-button variant="link" @click="addDnsTableRow">
              <icon-add /> Add DNS server
            </b-button>
          </b-col>
        </b-row>
      </page-section>
      <b-button
        variant="primary"
        type="submit"
        :disabled="!$v.form.$anyDirty || $v.form.$invalid"
      >
        Save settings
      </b-button>
    </b-form>
  </b-container>
</template>

<script>
import IconTrashcan from '@carbon/icons-vue/es/trash-can/20';
import IconAdd from '@carbon/icons-vue/es/add--alt/20';
import BVToastMixin from '@/components/Mixins/BVToastMixin';
import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin';
import PageSection from '@/components/Global/PageSection';
import PageTitle from '@/components/Global/PageTitle';
import TableRowAction from '@/components/Global/TableRowAction';
import VuelidateMixin from '@/components/Mixins/VuelidateMixin';
import { mapState } from 'vuex';
import { required, helpers } from 'vuelidate/lib/validators';

// IP address, gateway and subnet pattern
const validateAddress = helpers.regex(
  'validateAddress',
  /^(?=.*[^.]$)((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.?){4}$/
);
// Hostname pattern
const validateHostname = helpers.regex('validateHostname', /^\S{0,64}$/);
// MAC address pattern
const validateMacAddress = helpers.regex(
  'validateMacAddress',
  /^(?:[0-9A-Fa-f]{2}([:-]?)[0-9A-Fa-f]{2})(?:(?:\1|\.)(?:[0-9A-Fa-f]{2}([:-]?)[0-9A-Fa-f]{2})){2}$/
);

export default {
  name: 'NetworkSettings',
  components: {
    PageTitle,
    PageSection,
    TableRowAction,
    IconTrashcan,
    IconAdd
  },
  mixins: [BVToastMixin, VuelidateMixin, LoadingBarMixin],
  data() {
    return {
      dhcpEnabled: null,
      ipv4Configuration: '',
      ipv4StaticTableFields: [
        { key: 'Address', label: 'IP address' },
        { key: 'SubnetMask', label: 'Subnet mask' },
        { key: 'actions', label: '', tdClass: 'text-right' }
      ],
      dnsTableFields: [
        { key: 'address', label: 'IP address' },
        { key: 'actions', label: '', tdClass: 'text-right' }
      ],
      selectedInterfaceIndex: 0,
      selectedInterface: {},
      form: {
        gateway: '',
        hostname: '',
        macAddress: '',
        ipv4StaticTableItems: [],
        dnsStaticTableItems: []
      }
    };
  },
  validations() {
    return {
      form: {
        gateway: { required, validateAddress },
        hostname: { required, validateHostname },
        ipv4StaticTableItems: {
          $each: {
            Address: {
              required,
              validateAddress
            },
            SubnetMask: {
              required,
              validateAddress
            }
          }
        },
        macAddress: { required, validateMacAddress },
        dnsStaticTableItems: {
          $each: {
            address: {
              required,
              validateAddress
            }
          }
        }
      }
    };
  },
  computed: {
    ...mapState('networkSettings', [
      'ethernetData',
      'interfaceOptions',
      'defaultGateway'
    ]),
    interfaceSelectOptions() {
      return this.interfaceOptions.map((option, index) => {
        return {
          text: option,
          value: index
        };
      });
    }
  },
  watch: {
    ethernetData: function() {
      this.selectInterface();
    }
  },
  created() {
    this.startLoader();
    this.$store
      .dispatch('networkSettings/getEthernetData')
      .finally(() => this.endLoader());
  },
  beforeRouteLeave(to, from, next) {
    this.hideLoader();
    next();
  },
  methods: {
    selectInterface() {
      this.selectedInterface = this.ethernetData[this.selectedInterfaceIndex];
      this.getIpv4StaticTableItems();
      this.getDnsStaticTableItems();
      this.getInterfaceSettings();
    },
    getInterfaceSettings() {
      this.form.gateway = this.defaultGateway;
      this.form.hostname = this.selectedInterface.HostName;
      this.form.macAddress = this.selectedInterface.MACAddress;
      this.dhcpEnabled = this.selectedInterface.DHCPv4.DHCPEnabled;
    },
    getDnsStaticTableItems() {
      const dns = this.selectedInterface.StaticNameServers || [];
      this.form.dnsStaticTableItems = dns.map(server => {
        return {
          address: server,
          actions: [
            {
              value: 'delete',
              enabled: this.dhcpEnabled,
              title: 'delete static dns row'
            }
          ]
        };
      });
    },
    addDnsTableRow() {
      this.$v.form.dnsStaticTableItems.$touch();
      this.form.dnsStaticTableItems.push({
        address: '',
        actions: [
          {
            value: 'delete',
            enabled: this.dhcpEnabled,
            title: 'delete static dns row'
          }
        ]
      });
    },
    deleteDnsTableRow(index) {
      this.$v.form.dnsStaticTableItems.$touch();
      this.form.dnsStaticTableItems.splice(index, 1);
    },
    onDeleteDnsTableRow(action, row) {
      this.deleteDnsTableRow(row);
    },
    getIpv4StaticTableItems() {
      const addresses = this.selectedInterface.IPv4StaticAddresses || [];
      this.form.ipv4StaticTableItems = addresses.map(ipv4 => {
        return {
          Address: ipv4.Address,
          SubnetMask: ipv4.SubnetMask,
          actions: [
            {
              value: 'delete',
              enabled: this.dhcpEnabled,
              title: 'delete static ipv4 row'
            }
          ]
        };
      });
    },
    addIpv4StaticTableRow() {
      this.$v.form.ipv4StaticTableItems.$touch();
      this.form.ipv4StaticTableItems.push({
        Address: '',
        SubnetMask: '',
        actions: [
          {
            value: 'delete',
            enabled: this.dhcpEnabled,
            title: 'delete static ipv4 row'
          }
        ]
      });
    },
    deleteIpv4StaticTableRow(index) {
      this.$v.form.ipv4StaticTableItems.$touch();
      this.form.ipv4StaticTableItems.splice(index, 1);
    },
    onDeleteIpv4StaticTableRow(action, row) {
      this.deleteIpv4StaticTableRow(row);
    },
    submitForm() {
      this.startLoader();
      let networkInterfaceSelected = this.selectedInterface;
      let selectedInterfaceIndex = this.selectedInterfaceIndex;
      let interfaceId = networkInterfaceSelected.Id;
      let isDhcpEnabled = networkInterfaceSelected.DHCPv4.DHCPEnabled;
      let macAddress = this.form.macAddress;
      let hostname = this.form.hostname;
      let networkSettingsForm = {
        interfaceId,
        hostname,
        macAddress,
        selectedInterfaceIndex,
        isDhcpEnabled
      };
      networkSettingsForm.staticIpv4 = this.form.ipv4StaticTableItems.map(
        updateIpv4 => {
          delete updateIpv4.actions;
          updateIpv4.Gateway = this.form.gateway;
          return updateIpv4;
        }
      );
      networkSettingsForm.staticNameServers = this.form.dnsStaticTableItems.map(
        updateDns => {
          return updateDns.address;
        }
      );
      this.$store
        .dispatch(
          'networkSettings/updateInterfaceSettings',
          networkSettingsForm
        )
        .then(success => {
          this.successToast(success);
        })
        .catch(({ message }) => this.errorToast(message))
        .finally(() => {
          this.$v.form.$reset();
          this.endLoader();
        });
    }
  }
};
</script>
