#!/bin/bash

#===========================================================================================
# Copyright (C) 2017 Nafiu Shaibu.
# Purpose: General library including system
#-------------------------------------------------------------------------------------------
# This is is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 3 of the License, or (at your option) 
# any later version.

# This is distributed in the hopes that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

#===========================================================================================

######################Thu 09 Feb 2017 08:39:59 PM GMT##########################
#	true_test.h, host_ip.h, loggs.h, network.h, architecture.h, vnc_info.h	  #
#	error.h, disk_details.h, audio_display.h, boot_system.h, curses_dialog.h  #

: ${HD_IMG_DIR:=$HOME/.img_qemubox} ##contains harddisk images
: ${LOG_DIR:=${HD_IMG_DIR}/logs_dir}
: ${QBOX_DIR:="/usr/local/bin/QBox"}
: ${TEMP_FOLDER:="${HD_IMG_DIR}/.tmp_qbox"}
: ${QDB_FOLDER:=${HD_IMG_DIR}/.qdb} ##qbox database files location

: ${PYTHON_LOC:=${QBOX_DIR}/python3}
: ${BASIC_BASH:=${QBOX_DIR}/bash_s}
: ${LIB_DIR:=/usr/local/bin/QBox/include_dir}

. ${LIB_DIR}/define_macros

if [[ $1 = "<loggs.h>" ]]; then
	DEFINE LOGGS_H

	: ${LOGS_FILE:="${TEMP_FOLDER}/.error.tt"}
	. ${LIB_DIR}/import '<interpreters.h>'

	##logger_func
	##logger_func sed ':a;N;$!ba;s/\n/ /g'
	#1. :a create a label 'a'
	#2. N append the next line to the pattern space
	#3. $! if not the last line, ba branch (go to) label 'a'
	#4. s substitute, /\n/ regex for new line, / / by a space, /g global match (as many times as it can)
	function logger_logging(){
		if [ -f $1 ] && [ "`<$1`" != ""  ]; then
			${QBOX_DIR}/bin/qemubox_logger "`${SED_INT} ':a;N;$!ba;s/\n/ /g' $1`" ${LOG_DIR}/qboxlog
			rm -f $1
		fi
		
		[ -f $1 ] && { rm -f $1; }
	}

elif [[ "$1" = "<network.h>" ]]; then
	DEFINE NETWORK_H 0
	
	function set_parameters(){
		if [[ $1 -eq 0 ]]; then
		
			NETWORK0="-net nic"
			VLAN0=$2
			MAC0=$3
			MODEL0=$4
		
			USER0=${5//_/ }
			VLAN_USER0=$6	
			REDIRECT0=$7
		
			TAP0=${8//_/ }
			VLAN_TAP0=$9
			IFNAME0=${10}
			SCRIPT0=${11}
			FD_TAP0=${12}
		
			SOCKET0=${13//_/ }	
			VLAN_SOCKET0=${14}	
			LISTEN0=${15}
			CONNECT0=${16}	
			FD_SOCKET0=${17} 
			MCAST0=${18}
		
		elif [[ $1 -eq 1 ]]; then
		
			NETWORK1="-net nic"
			VLAN1=$2
			MAC1=$3
			MODEL1=$4
		
			USER1=${5//_/ }
			VLAN_USER1=$6	
			REDIRECT1=$7
		
			TAP1=${8//_/ }
			VLAN_TAP1=$9
			IFNAME1=${10}
			SCRIPT1=${11}
			FD_TAP1=${12}
		
			SOCKET1=${13//_/ }	
			VLAN_SOCKET1=${14}	
			LISTEN1=${15}
			CONNECT1=${16}	
			FD_SOCKET1=${17} 
			MCAST1=${18}
		
		
		elif [[ $1 -eq 2 ]]; then
		
			NETWORK2="-net nic"
			VLAN2=$2
			MAC2=$3
			MODEL2=$4
		
			USER2=${5//_/ }
			VLAN_USER2=$6	
			REDIRECT2=$7
		
			TAP2=${8//_/ }
			VLAN_TAP2=$9
			IFNAME2=${10}
			SCRIPT2=${11}
			FD_TAP2=${12}
		
			SOCKET2=${13//_/ }	
			VLAN_SOCKET2=${14}	
			LISTEN2=${15}
			CONNECT2=${16}	
			FD_SOCKET2=${17}
			MCAST2=${18}	
		
		elif [[ $1 -eq 3 ]]; then
			NETWORK3="-net nic"
			VLAN3=$2
			MAC3=$3
			MODEL3=$4
		
			USER3=${5//_/ }
			VLAN_USER3=$6	
			REDIRECT3=$7
		
			TAP3=${8//_/ }
			VLAN_TAP3=$9
			IFNAME3=${10}
			SCRIPT3=${11}
			FD_TAP3=${12}
		
			SOCKET3=${13//_/ }	
			VLAN_SOCKET3=${14}	
			LISTEN3=${15}
			CONNECT3=${16}	
			FD_SOCKET3=${17} 
			MCAST3=${18}	
		fi	
	}
	
	#define USER_MODE ADAPTER 0
	NETWORK0=
	VLAN0=
	MAC0=
	MODEL0=
	
	USER0=
	VLAN_USER0=
	REDIRECT0=
	
	TAP0=
	VLAN_TAP0=
	IFNAME0=
	SCRIPT0=
	FD_TAP0=
	SOCKET0=
	VLAN_SOCKET0=
	LISTEN0=
	CONNECT0=
	FD_SOCKET0=
	MCAST0=

	#define ADAPTER 1
	NETWORK1=
	VLAN1=
	MAC1=
	MODEL1=
	
	USER1=
	VLAN_USER1=
	REDIRECT1=
	
	TAP1=
	VLAN_TAP1=
	IFNAME1=
	SCRIPT1=
	FD_TAP1=
	SOCKET1=
	VLAN_SOCKET1=
	LISTEN1=
	CONNECT1=
	FD_SOCKET1=
	MCAST1=

	#define ADAPTER 2
	NETWORK2=
	VLAN2=
	MAC2=
	MODEL2=
	
	USER2=
	VLAN_USER2=
	REDIRECT2=
	
	TAP2=
	VLAN_TAP2=
	IFNAME2=
	SCRIPT2=
	FD_TAP2=
	SOCKET2=
	VLAN_SOCKET2=
	LISTEN2=
	CONNECT2=
	FD_SOCKET2=
	MCAST2=

	#define ADAPTER 3
	NETWORK3=
	VLAN3=
	MAC3=
	MODEL3=
	
	USER3=
	VLAN_USER3=
	REDIRECT3=
	
	TAP3=
	VLAN_TAP3=
	IFNAME3=
	SCRIPT3=
	FD_TAP3=
	SOCKET3=
	VLAN_SOCKET3=
	LISTEN3=
	CONNECT3=
	FD_SOCKET3=
	MCAST3=

elif [[ "$1" = "<architecture.h>" ]]; then
	DEFINE ARCHITECTURE_H 0
	
	. ${LIB_DIR}/import '<interpreters.h>'
	
	QEMU=
	VM_NAME=
	CPU=
	CORE=
	RAM_SIZE=
	SMB_SERVER=
	QEMU_FULLSCREEN=
	NUM_CPU=
	QEMU_USB=
	CDROM=
	QEMU_GRAPH=
	KVM_ENABLE=
	
	declare -A STR_ARCH=([x86_64]="Intel-8086(64bit)" [x86]="Intel-8086(64bit)" [amd64]="Intel-8086(64bit)" [i686]="Intel-8086(64bit)" \
						 [x86_32]="Intel-8086(32bit)" [i386]="Intel-8086(32bit)" [arm]="ARM_little_endian" [armeb]="ARM_big_endian" \
						 [ppc]="PowerPC(32bit)" [ppc64]="PowerPC(64bit)" [sparc]="SPARC(32bit)" [sparc64]="SPARC(64bit)" [mips]="MIPS_little_endian" \
						 [mipsel]="MIPS_big_endian")
						 
	function pointing_dev_choice(){
		case $1 in
			2) QEMU_USB="-usbdevice mouse" ;;
			3) QEMU_USB="-usbdevice tablet" ;;
			1) QEMU_USB="" ;;
		esac
	}
	
	function sound_drivers() {
		case "$1" in 
			1) QEMU_SOUND="-soundhw sb16" ;;
			2) QEMU_SOUND="-soundhw es1370" ;;
			3) QEMU_SOUND="-soundhw hda" ;;
		esac
	}
	
	function detection_msg() {
		NOT_DEFINE ${GUIDED_MODE_BOOT_VM} && {
			${DIALOG} \
				--colors --title "\Zb\Z0Architecture Detection\Zn\ZB" --yesno "\nDetected ${STR_ARCH[$1]} architecture...\n\n\Zb\Z1Do you want to use ${STR_ARCH[$1]} ?\Zn\ZB" $((HEIGHT-5)) $((WIDTH-5))	
		
			let "test_return=$?"
		
			case ${test_return} in 
				${DIALOG_OK}) return ${SUCCESS} ;;
				${DIALOG_CANCEL}) return ${FAILURE} ;;
			esac
		} || {
			if check_is_set $1; then
				return ${SUCCESS}
			else 
				return ${FAILURE}
			fi 
		}
	}
	
	function architecture_type_choice(){
        case $1 in
            1) QEMU=`${BASIC_BASH}/check_pkg_install.sh %CHECK_RUN% qemu-system-i386` 
            	BOOT_ORDER="-boot order=d"
            	KVM_ENABLE="-enable-kvm"
            ;;
            2) QEMU=`${BASIC_BASH}/check_pkg_install.sh %CHECK_RUN% qemu-system-x86_64` 
            	BOOT_ORDER="-boot order=d"
            	KVM_ENABLE="-enable-kvm"
            ;;
            3) QEMU=`${BASIC_BASH}/check_pkg_install.sh %CHECK_RUN% qemu-system-arm` 
            	BOOT_ORDER="-boot order=d"
            ;;
            4) QEMU=`${BASIC_BASH}/check_pkg_install.sh %CHECK_RUN% qemu-system-armeb` 
            	BOOT_ORDER="-boot order=d"
            ;;
            5) QEMU=`${BASIC_BASH}/check_pkg_install.sh %CHECK_RUN% qemu-system-ppc` 
            	BOOT_ORDER="-boot order=d"
            ;;
            6) QEMU=`${BASIC_BASH}/check_pkg_install.sh %CHECK_RUN% qemu-system-ppc64` 
            	BOOT_ORDER="-boot order=d"
            ;;
            7) QEMU=`${BASIC_BASH}/check_pkg_install.sh %CHECK_RUN% qemu-system-sparc` 
            	BOOT_ORDER="-boot order=d"
            ;;
            8) QEMU=`${BASIC_BASH}/check_pkg_install.sh %CHECK_RUN% qemu-system-sparc64` 
            	BOOT_ORDER="-boot order=d"
            ;;
            9) QEMU=`${BASIC_BASH}/check_pkg_install.sh %CHECK_RUN% qemu-system-mipsel` 
            	BOOT_ORDER="-boot order=d"
            ;;
            10) QEMU=`${BASIC_BASH}/check_pkg_install.sh %CHECK_RUN% qemu-system-mips` 
            	BOOT_ORDER="-boot order=d"
            ;;
        esac
	}	
	
	function detect_architecture() {
		local iso_file_name=$(basename $1)
		
		local arch=$(echo ${iso_file_name} | ${AWK_INT} -f ${QBOX_DIR}/awk/qemu-s-arch.awk)
		
		case ${arch} in 
			x86_64|x86|amd64|i686) 
				if detection_msg ${arch}; then
					return 2
				else 
					detect_architecture "GLOBBING"
				fi 
			;;
			i386|x86_32) 
				if detection_msg ${arch}; then
					return 1
				else 
					detect_architecture "GLOBBING"
				fi 				
			;;
			arm) 
				if detection_msg ${arch}; then
					return 3
				else 
					detect_architecture "GLOBBING"
				fi 				
			;;
			armeb) 
				if detection_msg ${arch}; then
					return 4
				else 
					detect_architecture "GLOBBING"
				fi
			;;
			ppc) 
				if detection_msg ${arch}; then
					return 5
				else 
					detect_architecture "GLOBBING"
				fi
			;;
			ppc64) 
				if detection_msg ${arch}; then
					return 6
				else 
					detect_architecture "GLOBBING"
				fi
			;;
			sparc) 
				if detection_msg ${arch}; then
					return 7
				else 
					detect_architecture "GLOBBING"
				fi
			;;
			sparc64) 
				 
				if detection_msg ${arch}; then
					return 8
				else 
					detect_architecture "GLOBBING"
				fi
			;;
			mips) 
				detection_msg ${arch} 
				if [[ $? -eq ${SUCCESS} ]]; then
					return 10
				else 
					detect_architecture "GLOBBING"
				fi
			;;
			mipsel) 
				detection_msg ${arch} 
				if [[ $? -eq ${SUCCESS} ]]; then
					return 9
				else 
					detect_architecture "GLOBBING"
				fi
			;;
			*) 
				NOT_DEFINE ${__CMDLINE__} && {
					exec 3>&1
				
					value=`${DIALOG} \
						--no-shadow --nook --nocancel --title "Linux Direct Boot" --menu "Choose Architecture" 18 50 30 1 "PC,intel-8086(32bit)" \
						2 "PC,intel-8086(64bit)" 3 "PC,ARM,little endian" 4 "PC,ARM,big endian" 5 "PC,PowerPC(32bit)" 6 "PC,PowerPC(64bit)" 7 "PC,SPARC(32bit)" \
						8 "PC,SPARC(64bit)" 9 "PC,MIPS,little endian" 10 "PC,MIPS,big endian" 2>&1 1>&3`
				
					let "test_return=$?"
					exec 3>&-
				
					#architecture_type_choice $value
					return $value
				} || {
					printf "%s\n" "   Options:[1 -------------------->PC,intel-8086(64bit) ]"		\
						  "           [2 -------------------->PC,ARM,little endian ]"				\
						  "           [3 -------------------->PC,ARM,big endian    ]"				\
						  "           [4 -------------------->PC,intel-8086(32bit) ]"		\
						  "           [5 -------------------->PC,PowerPC(32bit)    ]"		\
						  "           [6 -------------------->PC,PowerPC(64bit)    ]"		\
						  "           [7 -------------------->PC,SPARC(64bit)      ]"		\
						  "           [8 -------------------->PC,SPARC(32bit)      ]"		\
						  "           [9 -------------------->PC,MIPS,little endian]"		\
						  "           [10-------------------->PC,MIPS,big endian   ]"		
						  
					printf "%s" "What Computer architecture do you want to emulate "
					read -n 2 value 
					
					isdigit ${value} && { return $value; } || { return 12; }
				}
			;;
		esac
	}
	
	
elif [[ "$1" = "<error.h>" ]]; then
	DEFINE ERROR_H 0
	
	err_code=
	
	#err_code set 
	DEFINE ERR_VALUE_NOT_SET 255
	DEFINE ERR_IN_DISK_CREATION 256
	DEFINE ERR_OCCURRED_DURING_BOOT 257
	DEFINE QDB_NOT_EXIT 258
	DEFINE NO_ISO_FILES 259
	
	##Error strings format [name of variable]=error string //space char is not allowed in error string
	declare -A STRERROR=([QEMU]="|*Architecture_is_NULL\n" \
						[VM_NAME]="|*VM_Name_not_set\n" \
						[NUM_CPU]="|*Number_of_CPU_NULL\n" \
						[RAM_SIZE]="|*Ram_size_is_NULL_or_Not_in_valid_format[0-9][G,M]_eg.10G\n" \
						[QEMU_GRAPH]="|*Display_is_NULL\n" \
						[QEMU_SOUND]="|*Sound_is_NULL\n" \
						[QEMU_USB]="|*Pointing_device_is_NULL\n" \
						[VM_CDROM]="|*cdrom_is_NULL\n" \
						[VLAN_NUM]="|*VLAN_number_should_be_within_this_range_[0-1000]\n" \
						[FD_N]="|*File_descriptor_should_be_within_this_range_[0-1000]\n" \
						[PORT_NUM]="|*Port_Number_should_be_with_this_range_[1-65535]\n" \
						[MAC_ADDR]="|*Mac_Address_format_error\n" \
						[IP_ADDR]="|*IP_format_error_[xxx.xxx.xxx.xxx]\n" \
						[HOST_PORT_NUM]="${STRERROR[PORT_NUM]}" \
						[GUEST_PORT_NUM]="${STRERROR[PORT_NUM]}" \
						[vm_name]="|*Name_is_not_unique_or_Name_is_empty\n" \
						[DSK_VALID_SIZE]="|*Input_not_valid_Input_cannot_be_less_than_one_and_it_should_be_in_the_format_[0-9][G,M]_eg.10G\n" \
						[INITRD]="|*Not_initial_Ram_disk\n"\
						[KERNEL]="|*Not_a_kernel_image\n"\
						[256]="Disk_was_not_created\n"\
						[257]="Boot_error\n"\
						[255]="value_not_set\n"\
						[259]="No_iso_files_in_your_home_directory\n")
							
							
	##output error string using err_code 
	#argu err_code, display_type[__DIALOG__ | __CLI__]
	function perror() {
		local msg_str=${STRERROR[$1]}
		local msg_str=${msg_str//_/ } ##remove _ char from msg_str
		#local msg_str=${msg_str//|/\\n} ## replace "|" with "\n"
		local lineno=${LINENO}
		
		if [[ $1 -ne 0 ]]; then
			[ "$2" = "__DIALOG__" ] && {
				${DIALOG} \
					--colors --title "\Zb\Z1Error\Zn\ZB" --msgbox "\n[${lineno}]:${msg_str} " $((HEIGHT-7)) $((WIDTH-20))	
			} || {
				tput setaf 9
				echo -e "\n[${lineno}]:${msg_str}"
				tput sgr0
			}
		fi 
		
		let err_code=0
	}
	
	##input is in this format [values to test]:[error strings]:[function to test truth of values]
	function err_str() {
		local err_=""
		local tmp=$1
		local ret=${SUCCESS}
		
		local var_name=${tmp%%:*} ##get the name of variable
		local test_function=${tmp##*:} ##get the name of function to use for testing
		local str_error=$(echo ${tmp%:*} | cut -d ":" -f2)
		
		eval ${test_function} '$'${var_name} #function pointer in bash
		
		echo "$?:${str_error}"  ## return Test:ERROR_MSG
	}
	
	##Error format [[ Test:ERROR_MSG ]]
	function error_func_display() {
		declare -a ERR_FORMAT=($@)
		local err_ocurred=${FAILURE} #true
		local did_err_ocurred=${FAILURE}
		
		local msg_str=""
		for (( i=0; i<${#ERR_FORMAT[@]}; i++ )); do 
			local arr_=${ERR_FORMAT[$i]} 
			local _test_=${arr_%%:*}
			
			if [[ ${_test_} -ne ${SUCCESS} ]]; then
				msg_str+=${arr_##*:}
				err_ocurred=${SUCCESS} #false
			else
				err_ocurred=${FAILURE}
			fi 
			did_err_ocurred=$(( did_err_ocurred & err_ocurred ))
		done
		
		[ ${did_err_ocurred} -eq ${SUCCESS} ] && {
			msg_str=${msg_str//_/ } ##remove _ char from msg_str
			msg_str=${msg_str//|/\\n} ## replace "|" with "\n"
			
			if NOT_DEFINE ${__CMDLINE__}; then
				${DIALOG} \
					--colors --title "\Zb\Z1Error\Zn\ZB" --msgbox "${msg_str}" $((HEIGHT-7)) $((WIDTH-20))		
			else 
				tput setaf 9
				echo -e "\n\t${msg_str//\\n/}"
				tput sgr0
			fi 
		}
		
		return ${did_err_ocurred}
	}
	
elif [[ $1 = "<random_uid.h>" ]]; then
	DEFINE RANDOM_UID_H
	
	RANDOM_UID=`cat /dev/urandom |tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1`
	
elif [[ $1 = "<disk_details.h>" ]]; then
	DEFINE DISK_DETAILS_H 0
	
	. ${LIB_DIR}/include '<random_uid.h>'
	
	if NOT_DEFINE ${TRUE_TEST_H} || NOT_DEFINE ${LOGGS_H} || NOT_DEFINE ${BASIC_UTILS_H}; then 
		. ${LIB_DIR}/include '<true_test.h>'
		. ${LIB_DIR}/include "<loggs.h>"
		. ${LIB_DIR}/include '<basic_utils.h>'
	fi 
	
	: ${QEMU_DSKIMG_CREATOR:=`${BASIC_BASH}/check_pkg_install.sh %CHECK_RUN% qemu-img`}
	install_pkg QEMU_DSKIMG_CREATOR qemu-img

	DISK_FORMAT=
	DISK_SIZE=
	HD_BI_IMG=
	VM_CDROM=
	
	printf -v RAND "%04d" $RANDOM 
	Disk_Name=${HD_IMG_DIR}/${RANDOM_UID}${RAND}.img

	function disk_image_creation(){
		local _return=${SUCCESS}

		case $1 in
			1) ${QEMU_DSKIMG_CREATOR} create -f qcow2 $2 $3 2>${TEMP_FOLDER}/.error.tt 1>&2 ;;
			2) ${QEMU_DSKIMG_CREATOR} create -f raw -o size=$3 $2 2>${TEMP_FOLDER}/.error.tt 1>&2 ;;
			3) ${QEMU_DSKIMG_CREATOR} create -f qed -o size=$3 $2 2>${TEMP_FOLDER}/.error.tt 1>&2 ;;
			4) ${QEMU_DSKIMG_CREATOR} create -f vmdk -o size=$3 $2 2>${TEMP_FOLDER}/.error.tt 1>&2 ;;
			5) ${QEMU_DSKIMG_CREATOR} create -f vdi -o size=$3 $2 2>${TEMP_FOLDER}/.error.tt 1>&2 ;;
		esac

		[ $? -ne ${SUCCESS} ] && _return=${FAILURE}
		
		logger_logging ${LOGS_FILE}
		return ${_return}
	}

elif [[ $1 = "<audio_display.h>" ]]; then
	DEFINE AUDIO_DISPLAY_H

	QEMU_SOUND=
	DISPLAY_=
	VGA=
elif [[ $1 = "<boot_system.h>" ]]; then
	DEFINE BOOT_SYSTEM_H
	
	if NOT_DEFINE ${BASIC_UTILS_H} || NOT_DEFINE ${CURSES_DIALOG_H} || NOT_DEFINE ${ERROR_H}; then
		. ${LIB_DIR}/include '<basic_utils.h>'
		. ${LIB_DIR}/include '<curses_dialog.h>'
		. ${LIB_DIR}/include '<error.h>'
	fi
	
	NOT_DEFINE ${LOGGS_H} && {
		. ${LIB_DIR}/include '<loggs.h>'
	}
	
	#function pointer
	function boot_system_err_func() {
		local y=""
		
		eval y=$1
		
		check_is_set $y
		return $? 
	}
	
	
	printf -v MACADDR "52:54:%02x:%02x:%02x:%02x" $(( $RANDOM & 0xff)) $(( $RANDOM & 0xff )) $(( $RANDOM & 0xff)) $(( $RANDOM & 0xff ))
	default_install_network="-net nic,vlan=0,macaddr=${MACADDR},model=e1000 -net user,vlan=0"

	#boot function
	function boot_system() {
		let err_set=0 
		let i_var=0
		
		if NOT_DEFINE ${DIRECT_LINUX_BOOT}; then
			declare -a CONFIG_PARAMS=("QEMU" "VM_NAME" "NUM_CPU" "RAM_SIZE" "QEMU_GRAPH" "Disk_Name" \
									"VM_CDROM" "BOOT_ORDER" )
		else
			declare -a CONFIG_PARAMS=("QEMU" "VM_NAME" "KERNEL" "INITRD" "Disk_Name")	
		fi 
		
		let "i=0, percentage=0"
		let "_move_boot=${FAILURE}, _move_save=${FAILURE}"
		let "issaved=${FAILURE}"
		
		{
		while : ; do 
			#Thu 23 Mar 2017 07:13:30 PM GMT -----Checking that values are set-------
			[ ${_move_boot} -eq ${FAILURE} ] && [ ${_move_save} -eq ${FAILURE} ] && {
				eval tmp_param='$'${CONFIG_PARAMS[$i]}
				
				if check_is_set $tmp_param; then
					echo "XXX"
					echo $percentage
					echo "checking $(String_to_Lower ${CONFIG_PARAMS[$i]}) ($percentage%)"
					echo "XXX"
					
					[ $i -eq $(expr ${#CONFIG_PARAMS[@]} - 1) ] && { _move_boot=${SUCCESS}; }
				else
						let "err_set = ${ERR_VALUE_NOT_SET}"
						break
				fi 
			}
			
			#-----------------Booting VM---------------------
			[ ${_move_boot} -eq ${SUCCESS} ] && [ ${_move_save} -eq ${FAILURE} ] && {
				echo "XXX"
				echo $percentage
				echo "Booting ${VM_NAME:6:18} ($percentage%)"
				echo "XXX"	
				
				if NOT_DEFINE ${DIRECT_LINUX_BOOT}; then
					${QEMU} ${VM_NAME} ${NUM_CPU} ${RAM_SIZE} ${default_install_network} ${QEMU_GRAPH} ${QEMU_SOUND} \
					${QEMU_USB} ${HD_BI_IMG} ${VM_CDROM} ${KVM_ENABLE} ${BOOT_ORDER} 2>${LOGS_FILE}
				else 
					${QEMU} ${VM_NAME} ${default_install_network} ${KERNEL} ${INITRD} ${KERNEL_CMD} 2>${LOGS_FILE}
				fi 
				
				[ $? -eq ${FAILURE} ] && { 
					let "err_code = ${ERR_OCCURRED_DURING_BOOT}"
					logger_logging ${LOGS_FILE}
					break 
				}
				_move_save=${SUCCESS}
				
				sleep 0.6
			}
			
			
			#---------------Saving VM----------------------
			[ ${_move_boot} -eq ${SUCCESS} ] && [ ${_move_save} -eq ${SUCCESS} ] && {
				echo "XXX"
				echo $percentage
				echo "Saving ${VM_NAME:6:18} ($percentage%)"
				echo "XXX"	
				
				DEFINE_D ${DIRECT_LINUX_BOOT} && { issaved=$1; } 
				
				[ $issaved -ne ${SUCCESS} ] && {
					
					. ${BASIC_BASH}/qemu-bootfile-generator.sh ${Disk_Name} ${QEMU} %${VM_NAME} %${CPU} %${CORE} %${RAM_SIZE} \
					%${VGA} %${DISPLAY_} %${NETWORK0} %${VLAN0} %${MAC0} %${MODEL0} %${USER0} %${VLAN_USER0} %${REDIRECT0} %${TAP0} \
					%${VLAN_TAP0} %${FD_TAP0} %${IFNAME0} %${SCRIPT0} %${SOCKET0} %${VLAN_SOCKET0} %${FD_SOCKET0} %${LISTEN0} %${CONNECT0} \
					%${MCAST0} %${NETWORK1} %${VLAN1} %${MAC1} %${MODEL1} %${USER1} %${VLAN_USER1} %${REDIRECT1} %${TAP1} \
					%${VLAN_TAP1} %${FD_TAP1} %${IFNAME1} %${SCRIPT1} %${SOCKET1} %${VLAN_SOCKET1} %${FD_SOCKET1} %${LISTEN1} %${CONNECT1} \
					%${MCAST1} %${NETWORK2} %${VLAN2} %${MAC2} %${MODEL2} %${USER2} %${VLAN_USER2} %${REDIRECT2} %${TAP2} \
					%${VLAN_TAP2} %${FD_TAP2} %${IFNAME2} %${SCRIPT2} %${SOCKET2} %${VLAN_SOCKET2} %${FD_SOCKET2} %${LISTEN2} %${CONNECT2} \
					%${MCAST2} %${NETWORK3} %${VLAN3} %${MAC3} %${MODEL3} %${USER3} %${VLAN_USER3} %${REDIRECT3} %${TAP3} \
					%${VLAN_TAP3} %${FD_TAP3} %${IFNAME3} %${SCRIPT3} %${SOCKET3} %${VLAN_SOCKET3} %${FD_SOCKET3} %${LISTEN3} %${CONNECT3} \
					%${MCAST3} %${SMB_SERVER} %${QEMU_SOUND} %${QEMU_USB} %${HD_BI_IMG} %${KVM_ENABLE} %${KERNEL} %${INITRD} %${QEMU_KEYBOARD} \
					%${QEMU_FULLSCREEN} % %${SNAP_OT} %${KERNEL_CMD} % % #2>/dev/null
					
					issaved=${SUCCESS}
				}
				
				sleep 1			
			}
			
			(( i_var=i ))
			(( i+=1 ))
			
			if NOT_DEFINE ${DIRECT_LINUX_BOOT}; then
				(( percentage=i * 100 / 14 + 7 ))
			else
				(( percentage=i * 100 / 14 + 7 ))
			fi 
			
			[ $percentage -ge 100 ] && break
			sleep 0.3
		done } | ${DIALOG} --gauge "Please wait" 7 70 0
		
		if [[ ${err_set} -eq 255 ]]; then
			local TMP_CMP=${CONFIG_PARAMS[$i_var]}
			error_func_display "$(err_str "${TMP_CMP}:${STRERROR[$TMP_CMP]}:boot_system_err_func")" 
			return ${FAILURE}			
		fi
		
		perror ${err_code} "__DIALOG__"
		
		if DEFINE_D ${DIRECT_LINUX_BOOT}; then
			UNDEFINE DIRECT_LINUX_BOOT
		fi 
		
		return ${SUCCESS}
	}

elif [[ $1 = "<curses_dialog.h>" ]]; then
	DEFINE CURSES_DIALOG_H
	
	declare -i HEIGHT=18
	declare -i WIDTH=50
	
	: ${DIALOG=$(${BASIC_BASH}/check_pkg_install.sh %CHECK_RUN% dialog)}
	install_pkg DIALOG dialog

	: ${DIALOG_OK:=0}
	: ${DIALOG_BACK:=3}
	: ${DIALOG_CANCEL:=1}

elif [[ $1 = "<true_test.h>" ]]; then		#Wed 08 Feb 2017 10:26:58 PM GMT
	DEFINE TRUE_TEST_H
# return
	declare -i SUCCESS=0
	declare -i FAILURE=1

elif [[ $1 = "<vnc_info.h>" ]]; then
	DEFINE VNC_INFO_H

	VNC_DISPLAY=3`${QBOX_DIR}/bin/qemubox_random 15`00
	VNC_PORT=`expr ${VNC_DISPLAY} + 5900`
elif [[ $1 = "<host_ip.h>" ]]; then
	DEFINE HOST_IP_H
	if NOT_DEFINE ${LOGGS_H}; then
		source ${LIB_DIR}/include '<loggs.h>'
	fi 

	HOST_IP=`${PYTHON_INT} ${PYTHON_LOC}/netiface_deter.py 2>${LOGS_FILE}`
	[ "${HOST_IP}" = "" ] && HOST_IP="127.0.0.1"
	logger_logging ${LOGS_FILE}
elif [[ $1 = "<basic_utils.h>" ]]; then
	DEFINE BASIC_UTILS_H
	#basic system utilities
	
	. ${LIB_DIR}/import '<strings_definitions.h>'
	. ${LIB_DIR}/import '<init.h>'
	. ${LIB_DIR}/import '<interpreters.h>'
	
	if NOT_DEFINE ${TRUE_TEST_H}; then
		. ${LIB_DIR}/include '<true_test.h>'
	fi
	
	function check_is_file() {
		[ -f $1 ] && return ${SUCCESS} || return ${FAILURE}
	}
	
	function check_is_set() {
		local tmp=$1
		[ -n "$tmp" ] && { tmp=""; return ${SUCCESS}; } || { tmp=""; return ${FAILURE}; }
	}
	
	function String_to_Upper() {
		echo $(echo $1 | ${AWK_INT} '{print toupper($0)}')
	}
	
	function String_to_Lower() {
		echo $(echo $1 | ${AWK_INT} '{print tolower($0)}')
	}
	
	function check_is_iso_file() {
		local tmp=$(String_to_Lower `basename $1`)
		
		if check_is_file $1; then
			case ${tmp##*.} in 
				iso|img) return ${SUCCESS} ;;
				*) return ${FAILURE} ;;
			esac
		else
			return ${FAILURE}
		fi 
	}
	
	#function pointer for ip verification
	function ip_func_pointer() {
		local test_ip=${FAILURE}
		
		if [ -z $1 ] || is_IP_Valid $1; then
			test_ip=${SUCCESS}
		fi 	
		return ${test_ip}	
	}

	##Test whether input is char 
	function isdigit(){
		if [ -z "$1" ]; then
			return 	$FAILURE
		fi 
	
		case "$1" in 
			[[:digit:]]|[[:digit:]]*) return $SUCCESS ;;
			*)	return $FAILURE ;;
		esac
	}

	##Verify IP address format
	function is_IP_Valid(){
	
		local _return=${FAILURE}
	
		if [[ $1 =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} ]]; then
			OLDIFS=${IFS}
			IFS="."
			declare -a IP=($1)
			IFS=${OLDIFS}
			[[ ${IP[0]} -le 255 ]] && [[ ${IP[1]} -le 255 ]] && [[ ${IP[2]} -le 255 ]] && [[ ${IP[3]} -le 255 ]] && {
				_return=${SUCCESS}
			}
		fi 
	
		return $_return
	}	

	## verify macaddress
	function is_valid_macaddr() {
		local test_mac=${FAILURE}
	
		if [[ $1 =~ [[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]] ]]; then
			test_mac=${SUCCESS}
		fi 	
	
		return ${test_mac}
	}

	function is_valid_VLAN() {
		local test_vlan=${FAILURE}
	
		if isdigit $1 && [ $1 -ge 0 ] && [ $1 -le 1000 ]; then
			test_vlan=${SUCCESS}
		fi	
		return ${test_vlan}
	}

	##is valid file descriptor
	function is_valid_fd() {
		local test_fd=${FAILURE}
	
		if isdigit $1 && [ $1 -ge 0 ] && [ $1 -le 1000 ]; then
			test_fd=${SUCCESS}
		fi		
	
		return ${test_fd}
	}

	##unique for the vms. The name is used as the primary key for vms database
	function is_VMName_unique(){
		local _return=${FAILURE}
	
		if check_is_set $(String_to_Upper $1) ; then
			local search="^$1\$"
			local unique=$(${AWK_INT} -F "|" -v var=$search '$1 ~ var {print $1}' ${QDB_FOLDER}/vms.qdb 2>/dev/null)
			[ -z ${unique} ] && _return=${SUCCESS}
		fi 
	
		return ${_return}
	}

	#ret: array of path to iso files
	function check_for_iso_files() {
		local -a iso_files=
		local index=0
		
		for iso in $(find ${HOME} -maxdepth 2 -type f -a -name "*.iso" -print 2>>/dev/null); do 
			iso_files[$index]=$iso
			(( index++ ))
		done
	
		echo -n ${iso_files[@]}
	}

	function disk_size_valid(){
	#Sat 28 Jan 2017 12:18:24 AM GMT 
		local tmp=$1
		if [[ -z "$1" ]]; then
			return ${FAILURE}
		fi 
	
		local first_part=${tmp%%[[:alpha:]]*}
		local second_part=${tmp##*[[:digit:]]}
	
		isdigit ${first_part} && [[ ${first_part} -ge 1 ]] && [[ ${second_part} =~ [[:alpha:]] ]] && [[ "${second_part}" = "G" || "${second_part}" = "M" ]] && { return ${SUCCESS}; } 
	
		return ${FAILURE}
	}

	function is_valid_port_num() {
		local test_port=${FAILURE}
	
		if isdigit $1 && [ $1 -ge 1 ] && [ $1 -le 65535 ]; then
			test_port=${SUCCESS}
		fi 			
		return ${test_port}
	}

	#argu: Test_variable:Name_configuration_part_to_test
	function _test_already_configured() {
		local _ret=${SUCCESS}
	
		if [[ ${1%%:*} -eq ${SUCCESS} ]]; then
			NOT_DEFINE ${__CMDLINE__} && {
				${DIALOG} \
					--colors --title "\Zb\Z1Already Configured\Zn\ZB" --yesno "Already configured:\Zb\Z1${1##*:}\Zn\ZB.\nDo you want to reconfigure?" \
					$((HEIGHT-7)) $((WIDTH-20))
				
				case $? in 
					${DIALOG_OK}) _ret=${SUCCESS} ;;
					${DIALOG_CANCEL}) _ret=${FAILURE} ;;
				esac
			} || {
				tput setaf 9
				echo -en $(get_string_by_name COND_ALREADY_CONFIGURED "${1##*:}[y/N]?")
				tput sgr0
				read -n 1 ans
			
				case "$ans" in 
					Y|y) _ret=${SUCCESS} ;;
					*) _ret=${FAILURE} ;;
				esac 
			}
		fi 
	
		return $_ret
	}

	#argu: test_condition:display_text
	function _check_configured() {
		local -a _argu_arr=( $@ )
		local _configured=${FAILURE}
		local msg_str=""
	
		for (( index=0; index<${#_argu_arr[@]}; index++ )); do 
			if [[ ${_argu_arr[$index]%%:*} -eq ${FAILURE} ]]; then
				msg_str+=${_argu_arr[$index]##*:}
				_configured=${SUCCESS}
			fi 
		done 
	
		[ ${_configured} -eq ${SUCCESS} ] && {
			msg_str=${msg_str//_/ }
			msg_str=${msg_str//|/\\n}
		
			NOT_DEFINE ${__CMDLINE__} && { 
				${DIALOG} \
					--colors --title "\Zb\Z1 Not Configured Yet\Zn\ZB" --msgbox "You have not configured.\n \Zb\Z1${msg_str}\Zn\ZB." \
					$((HEIGHT-7)) $((WIDTH-20))		
			} || { 
				tput setaf 9
				echo -en "\nYou have not configured.\n$msg_str"
				tput sgr0
			}
		}
	
		return ${_configured}
	}
	
	##create desktop files
	#argu name of vm
	function create_desktop_icon(){
		local _filename=$(String_to_Lower $1)
		local _filename="${HOME}/Desktop/${_filename}.desktop"
		touch ${_filename}
	
		echo -e "[Desktop Entry]\nTerminal=true">${_filename}
		echo -e "Encoding=UTF-8\nType=Application\nIcon=/usr/local/bin/QBox/icon/qbox_shortcut.png\nName=$1\nGenericName=Virtual Machine Manager">>${_filename}
		echo -e "Exec=sh -c '${QBOX_DIR}/QBox --startvm $1 ;$SHELL'\nComment=QBox for easy management of VMs locally or remotely">>${_filename}
	
		chmod 751 ${_filename}
		return ${SUCCESS}
	}
	
	##get the value for a field in the vm bootfile 
	##argu: id_of_field, file_name, variable_to_set_value_to
	#ret: success if successful Or failure
	function get_value_for_field() {
		local value=""
		local file_name=$2
		local value=$(${AWK_INT} -F "|" -v var="^$1\$" '$1 ~ var {print $2}' ${file_name})
		
		[ "$value" != "" ] && { echo -n "$value"; } || { echo -n ""; }
	}

	function package_install_func() {
		local pkg_man="`{ type yum >/dev/null 2>&1 && which yum; } || { type apt-get >/dev/null 2>&1 && which apt-get; }`"
	
		[ ${INST_CON} -eq 0 ] && {
			tput setaf 9
			echo -e "\n	NOTICE!!!\nQBox will now try to install [$1]\nIn case of [INSTALL-ERROR-LOOPS] press [CTRL+C] to exit\n"
			tput sgr0
			sleep 3 && INST_CON=10
			echo -e "Updating Cache..." && sudo ${pkg_man} update >/dev/null 2>&1
			[ $? -eq 0 ] && echo -e "[OK]" || echo -e "[ERROR]"
		}
	
		echo -e "Installing [$1]..." && sudo ${pkg_man} install $1 -y >/dev/null 2>&1
		[ $? -eq 0 ] && { echo -e "[OK]"; return ${SUCCESS}; } || { 
			echo -e "[ERROR]"
			package_install_func $1 
		}
	}

	function pkg_display_download(){
		path_error_display="`{ type zenity >/dev/null 2>&1 && which zenity; } || { type dialog >/dev/null 2>&1 && which dialog; } || { echo 1; }`"
		base_n="`[ "${path_error_display}" = "1" ] && echo 1 || basename $path_error_display`"
		
		case "$base_n" in 
			zenity) 
				${path_error_display} \
						--question --title="Package $1 Required"  --width=30 --height=20 --window-icon=question \
						--text="QBox required $1 to continue..\n Do you want to install it?" >/dev/null 2>&1
					
				if [ $? -eq 0 ]; then
					INST_CON=0
					package_install_func $1
					return $?
				else
				  : #_return_="`which $1`"
				fi
			;;
			dialog) 
				${path_error_display} \
						--no-shadow --title "Package $1 Required" --yesno "QBox required $1 to continue..\n Do you want to install it?" 18 50
			
				if [ $? -eq 0 ]; then
					clear
					INST_CON=0
				   package_install_func $1
					return $?
				else
					: #_return_="`which $1`"
				fi 
			;;
			1) 
				echo "Package $1 Required"
				echo -en "QBox required $1 to continue..\n Do you want to install it?[YES/no] "
				read 
			
				case $REPLY in 
		    		[Yy]|[Yy][Ee][Ss]) 
		    			INST_CON=0
		    			package_install_func $1
		    			return $?
					;;
					*) ;; #_return_="`which $1`"
				esac
			;;
		esac
	}
	
	
	function install_pkg(){
		declare -A PKG_NAME=( [ncat]="nmap" [dialog]="dialog" [awk]="awk" \
									[python]="python" [php]="phpmyadmin" [notify-send]="notify-osd" \
									[sed]="sed" )

		eval y='$'$1

		[ "$y" = "" ] && {
			pkg_display_download ${PKG_NAME[$2]} && { eval $1="`which $2`"; }
		}
	}
	
fi
