#!/bin/sh

# Copyright (c) 2016, Justin D Holcomb All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
#   list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
#   this list of conditions and the following disclaimer in the documentation
#   and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# Add a new disk to guest
__add_guest_disk() {
	local _size="$1"
	__generate_zvol_disk_options_string
	__get_next_disk_number

	if [ -z "$_size" ]; then
		__load_guest_default_parameters
		local _size="$_GDP_size"
	fi

	# Find the last disk number and increment one
	if [ -z "$_disk_number" ]; then
		local _disk_number="$_NEXT_disk_number"
	fi

	__log 1 "Creating $_size disk$_disk_number for $_GUEST_name using these option: $_ZVOL_disk_options_string... " -n
	zfs create -V $_size $_ZVOL_disk_options_string $_GUEST_pool/chyves/guests/$_GUEST_name/disk$_disk_number

	if [ "$?" = 0 ]; then
		__log 1 "done."
	else
		__log 1 "ERROR creating disk."
	fi

	if [ -n "$( __return_guest_bhyve_pid )" ]; then
		echo "Guest is running. Shutdown the guest and then start the guest with chyves. The disk bhyve strings need to be regenerated."
	fi
}

# Delete disk from guest
__delete_guest_disk() {
	local _disk="$1"

	# Verify the disk exists
	__verify_valid_dataset "guests/$_GUEST_name/$_disk"

	# Check if guest is running because zfs will not be able to remove the disk if so.
	if [ -n "$( __return_guest_bhyve_pid )" ]; then
		__fault_detected_exit "Guest is running, please shutdown the guest before removing the disk."
	fi

	# Prompt user and handle either response.
	read -p "Do you want to delete $_disk on $_GUEST_name? This is NOT reversible, nor will snapshots will NOT be able to undo this action. Are you sure? [Y/N]? " an </dev/tty
	case "$an" in
		y|Y)  __log 1 "Deleting $_disk from $_GUEST_name... " -n
		      zfs destroy -r $_GUEST_pool/chyves/guests/$_GUEST_name/$_disk

	        # Handling for exit code
	        if [ "$?" -eq "0" ]; then
	          __log 1 "done."
	        else
	          __log 1 "unsuccessful."
	        fi
		;;
		*)    __log 1 "$_disk was not removed from $_GUEST_name."
		;;
	esac
}

# Set GV indicating clone origin of disk as requested by $1
__gvset_disk_clone_origin_for_info_func() {
	local _disk_in_question="$1"

	# This check is needed for diskless guests. This could happen for custom attached raw image files.
	if [ -z "$_disk_in_question" ]; then
		local _answer="^NO"
	else

		# Check if the first disk is image based.
		if [ -n "$( echo "$_disk_in_question" | grep "/chyves/$_GUEST_pool/guests/$_GUEST_name/img" )" ]; then

			# Find the ZFS dataset that the first disk belongs to.
			local _dataset_name="$_disk_in_question"
			while [ ! $_found_root_dataset ];
			do
				local _dataset_name="$( dirname $_dataset_name )"
				zfs list $_dataset_name > /dev/null 2>&1
				if [ "$?" -eq 0 ]; then
					local _image_origin="$( zfs get -H -o value origin $_dataset_name | cut -d'/' -f4 | head -n1 )"
					local _found_root_dataset=1
				fi
			done

			# Print the results
			if [ "$_image_origin" = "-" ]; then
				local _answer="NO"
			else
				local _answer="Child of $_image_origin"
			fi

		# Catch all, assumes the disk is ZFS volume backed.
		else

			local _disk_in_question="$( echo "$_disk_in_question" | cut -d'/' -f4- )"       # The 'cut' removes the "/dev/zvol" portion of $_FIRST_disk value.
			local _disk_origin="$( zfs get -H -o value origin $_disk_in_question | cut -d'/' -f4 | head -n1 )"
			if [ "$_disk_origin" = "-" ]; then
				local _answer="NO"
			else
				local _answer="Child of $_disk_origin"
			fi
		fi
	fi

	_DISK_clone_origin_for_info_func="$_answer"
}

# Set GV for the first disk for a guest
__gvset_first_disk() {
	__gvset_guest_disk_list -new-line
	_FIRST_disk="$( echo "$_GUEST_disk_list" | head -n1 )"
}

# Set GV of list of guests' disks and count
__gvset_guest_disk_list() {
	local _disks_string _final_count _flags _num_of_raw _num_of_volumes _raw_dataset_list _volumes_dataset_list
	local _flags="$1"
	# -space
	# -comma
	# -grep
	# -new-line

	# Volumes for guest
	local _volumes_dataset_list="$( zfs list -d 4 -H -r -t volume -o name $_GUEST_pool/chyves/guests/$_GUEST_name | awk '{ print "/dev/zvol/"$1 }' | sort -k1V )"
	local _num_of_volumes="$( echo $_volumes_dataset_list | tr ' ' '\n' | grep -c "" )"

	# Raw images for guest
	local _raw_dataset_list="$( find /chyves/$_GUEST_pool/guests/$_GUEST_name/img/ -type f -print )"
	local _num_of_raw="$( echo $_raw_dataset_list | tr ' ' '\n' | grep -c "" )"

	# Combine raw images and volumes
	local _disks_dataset_list="$( echo -e "$_raw_dataset_list\n$_volumes_dataset_list" )"
	local _final_count="$( echo $_disks_dataset_list | tr ' ' '\n' | grep -c "" )"

	# Formatting statements
	if [ "$_flags" = "-new-line" ]; then
		local _final_formated_output="$( echo "$_disks_dataset_list" | grep -v -E '^$' )"
	elif [ "$_flags" = "-comma" ]; then
		local _final_formated_output="$( echo "$_disks_dataset_list" | tr '\n' ',' )"
	elif [ "$_flags" = "-grep" ]; then
		local _final_formated_output="$( echo "$_disks_dataset_list" | tr '\n' '|' )"
	elif [ "$_flags" = "-space" ]; then
		local _final_formated_output="$( echo "$_disks_dataset_list" | tr '\n' ' ' )"
	fi

	_GUEST_disk_list="$_final_formated_output"
	_GUEST_disk_list_count="$_final_count"
}

# Resize a disk
__resize_guest_disk() {
	local _disk="$1"
	local _size="$2"
	__gvset_user_input_to_bytes $_size
	# Verify the disk exists
	__verify_valid_dataset "guests/$_GUEST_name/$_disk"

	# Check if guest is running because zfs will not be able to resize the disk if so.
	if [ -n "$( __return_guest_bhyve_pid )" ]; then
		__fault_detected_exit "Guest is running, please shutdown the guest before resizing the disk."
	fi

	local _current_size="$( zfs get -H -p -o value volsize $_GUEST_pool/chyves/guests/$_GUEST_name/$_disk )"
	local _desired_size="$_USER_input_to_bytes"

	# Give warning when trying to reduce the size.
	if [ "$_desired_size" -lt "$_current_size" ]; then
		echo "It is not recommended to reduce the size of a guest disk. Data loss is possible and the guest partition table needs to be reconfigure prior to these changes."
		echo "Press enter to continue or Ctrl + c to cancle."
		read _void
	fi

	# Check if guest exists
	__log 1 "Resizing $_disk to $size... " -n
	zfs set volsize=$_desired_size $_GUEST_pool/chyves/guests/$_GUEST_name/$_disk

	# Handling for exit code
	if [ "$?" -eq "0" ]; then
		__log 1 "done."
	else
		__log 1 "unsuccessful."
	fi
}
