#!/usr/bin/wish

#  Command line installer - This script takes the arguments on the command
# line and after checking to see if they are installable packages, offers
# the user a list of these packages with a short description with a check
# box for each. When the install button is selected, any packages checked
# will be installed if there is no error. A progress bar is displayed and
# text gives information as to which package, operation, etc. is being
# preformed.
#
set cllist ""
set default_packages "ubuntustudio-audio
	ubuntustudio-menu
	linux-lowlatency
	ubuntustudio-graphics
	ubuntustudio-photography
	ubuntustudio-publishing
	ubuntustudio-video
	ubuntustudio-lowlatency-settings
	ubuntustudio-performance-tweaks
	ubuntustudio-wallpapers
	carla
	ubuntustudio-branding-common"

# this number should be the number of packages listed above
set clnum 0
set default_number 12

proc makelist {args number } {
	.list delete 0 end
	.desc configure -state normal
	.desc delete 0 end
	#lets fill our listboxs
	for {set i 0} {$i < $number} {incr i} {
		set inst ""
		set package [lindex $args $i]
		#check if already installed
		catch {
		set inst [exec dpkg-query -s $package 2> /dev/null]
			}
		if { $inst == "" } {
			# this package is not installed check available
			set cachecmd "apt-cache search -n $package"
			set fhcache [open |$cachecmd "r"]
			while { [gets $fhcache cline] >= 0 } {
				set pknm [lindex $cline 0]
				if { $pknm == $package } {
					.list insert end $package
					set pkdesc [lrange $cline 2 end]
					.desc insert end $pkdesc
					}	
				}
			close $fhcache
			}
		}
	# We should check for an empty list and error out depending
	# on already installed or not available
	if { [.list size] == 0 } {
		.desc insert end "All Ubuntu Studio packages are already installed"
		}
	# we don't want people selecting from description so disable it
	# after we fill it.
	.list selection clear 0 end
	.desc configure -state disabled
}

proc pctdwn { pct } {
	# percent download pct is raw percent
	# progress bar is 600 wide, download is half of that
	set pix [expr $pct * 3]
	set white [expr 600 - $pix]
	.lower.bar configure -width $pix
	.lower.bg configure -width $white
	}

proc pctunpk { pct nofl } {
	# pct is number of the package being unpacked
	# nofl is number of packages
	# this starts at half way and goes till 5/6ths
	if { $nofl > 0 } {
		set pix [expr 300 + (200 * $pct / $nofl)]
	} else {
		set pix 0
	}
	set white [expr 600 - $pix]
	.lower.bg configure -width $white
	.lower.bar configure -width $pix
	}

proc pctset { pct nofl } {
	# pct is number of the package being setup
	# nofl number of packages
	# this starts at 5/6ths and goes till full
	if { $nofl > 0 } {
		set pix [expr 500 + (100 * $pct / $nofl)]
	} else {
		set pix 0
	}
	set white [expr 600 - $pix]
	.lower.bg configure -width $white
	.lower.bar configure -width $pix
	}

proc install { } {
	global cllist
	global clnum
	# don't let the user select anything more, change title line
	.list configure -state disabled
	.install configure -state disabled
	.noppa configure -state disabled
	.ppa configure -state disabled
	.top configure -text "Installing Selected Packages"

	# get list of packages (before destroying .list)
	set pkgs ""
	set sel [.list curselection]
	set num [llength $sel]
	for {set i 0} {$i < $num} {incr i} {
		set snum [lindex $sel $i]
		lappend pkgs [.list get $snum]
		}

	#get rid of list box and replace with label for info
	grid remove .list .desc .scroll
	grid config .lower -column 1 -columnspan 4 -row 3 -pady 4
	grid config .info -column 1 -columnspan 4 -row 2

	# once install starts the user should not be allowed to exit
	.exit configure -state disabled
	wm protocol . WM_DELETE_WINDOW nostop	

# time to run apt-get (use cat apt.log for testing)
#	set instcmd "cat apt.log"
#	lassign [chan pipe] pr pw
	set instcmd "pkexec apt-get install -yq=0 $pkgs |& cat"
	set getcnt 0
	set unpk 0
	set stup 0
	set authok 0

	set fhinst [open |$instcmd "r"]
	fconfigure $fhinst -buffering line -blocking 0
	while { ![eof $fhinst] } {
		gets $fhinst insline
		set shortline [string range $insline 0 40]
		#only set these once instead of each if
		if { [string first "Reading" $insline] == 0} {
			.info configure -text $insline
			#this line means we got to apt-get ok
			set authok 1
		} elseif { [string first "(Reading" $insline] == 0 } {
			.info configure -text $insline
		} elseif { [string first "Building" $insline] == 0 } {
			.info configure -text $insline
		} elseif { [string first "Processing" $insline] == 0 } {
			.info configure -text $insline
		} elseif { [string first "upgraded," $insline] > -1 } {
			if { [string first "upgraded," $insline] < 14 } {
				set 1st [lindex $shortline 0]
				set 3rd [lindex $shortline 2]
				# upgraded + installed = total packages to install
				set getcnt [expr $1st + $3rd]
			}
		} elseif { [string index $insline 1] == "%" } {
			pctdwn [string index $insline 0]
			.info configure -text $insline
		} elseif { [string index $insline 2] == "%" } {
			pctdwn [string range $insline 0 1]
			.info configure -text $insline
		} elseif { [string index $insline 3] == "%" } {
			pctdwn [string range $insline 0 2]
			.info configure -text $insline
		} elseif { [string first "Unpacking" $insline] == 0 } {
			.info configure -text $insline
			incr unpk
			pctunpk $unpk $getcnt
		} elseif { [string first "Setting" $insline] == 0 } {
			.info configure -text $insline
			incr stup
			pctset $stup $getcnt
		} elseif { [string first "Failed" $insline] > -1 } {
			.info configure -text $insline
			after 500
		} elseif { [string first "E:" $insline] == 0 } {
			tk_messageBox -parent . -title Error -type ok \
				-icon error -message $insline
			exit
			}
	
		# update gui so progress bar and info show
		update
		}
	close $fhinst

	#check if we are finished because authorization failed/cancelled
	if { $authok == 0 } {
		tk_messageBox -parent . -title Error -type ok \
			-icon error -message \
			"Authorization failed, no packages installed."
		exit
		}


	# set bar to 100% and say done
	.lower.bg configure -width 0
	.lower.bar configure -width 600
	.info configure -text "Install finished, setting audio RT access"
	exec pkexec /usr/sbin/ubuntustudio-system fix
	.info configure -text "Finished"
	rt_warn

	.list configure -state normal
	makelist $cllist $clnum
	grid .list .desc .scroll
	grid remove .lower .info
	.lower.bg configure -width 600
	.lower.bar configure -width 0
	.exit configure -state normal
	.top configure -text "Select packages to install"
	ppa_check
	selectdet

	# All done allow exiting
	.exit configure -state normal
	wm protocol . WM_DELETE_WINDOW exit
	
	}

proc nostop { } {
	set result [tk_messageBox -parent . \
		-title "Error Install Won't Exit" \
		-type ok -icon warning \
		-message "once install has started GUI can't exit"]

	}

proc selectdet { } {
	# install buttom should only be active if sw is selected	
	set sel [.list curselection]
	if { [llength $sel] > 0 } {
		.install configure -state normal
		} else {
		.install configure -state disabled
		}
	}

proc do_ppa {} {
	global cllist
	global clnum
	# stuff here
	.top configure -text "Please wait - updating system"
	.exit configure -state disabled
	.install configure -state disabled
	.noppa configure -state disabled
	.ppa configure -state disabled
	set result [tk_messageBox -parent . \
		-title "System Software Change" \
		-type okcancel -icon warning \
		-message "This is a PPA for backports of tools included in Ubuntu Studio.
		This PPA does not have official Ubuntu support.
		(message box will close when ppa is added)"]

	if { $result == "cancel" } {
		.ppa configure -state normal
		.noppa configure -state normal
		selectdet
		.exit configure -state normal
		.top configure -text "Select packages to install"
		return
	} else {
	if {[catch {exec -ignorestderr pkexec /usr/bin/ubuntustudio-installer-ppa} results options]} {
		set details [dict get $options -errorcode]
		if {[lindex $details 0] eq "CHILDSTATUS"} {
			set status [lindex $details 2]
		}
	}
	}
	makelist $cllist $clnum
	.noppa configure -state normal
	selectdet
	.exit configure -state normal
	.top configure -text "Select packages to install"

}

proc undo_ppa {} {
	global cllist
	global clnum
	.top configure -text "Please wait - updating system"
	.exit configure -state disabled
	.install configure -state disabled
	.noppa configure -state disabled
	.ppa configure -state disabled
	update
	exec pkexec /usr/bin/ubuntustudio-installer-ppa remove
	update
	makelist $cllist $clnum
	.ppa configure -state normal
	selectdet
	.exit configure -state normal
	.top configure -text "Select packages to install"
	update
}

proc ppa_check { } {
	.ppa configure -state normal
	.noppa configure -state disabled
	set code [exec lsb_release -cs]
	if { [glob -nocomplain "/etc/apt/sources.list.d/ubuntustudio-ppa-ubuntu-backports-${code}.*"]!="" } {
		set a [open "/etc/apt/sources.list.d/ubuntustudio-ppa-ubuntu-backports-${code}.list" r]              
		while {[gets $a line]>=0} {
			if {[string first "deb h" $line]==0} {
				.ppa configure -state disabled
				.noppa configure -state normal
			}
		}
		close $a
	}
	update
}

proc rt_warn { } {

	set gpcmd "groups"
	set fhgrp [open |$gpcmd "r"]
	while { [gets $fhgrp cline] >= 0 } {
		foreach x $cline {	;
			if { $x == "audio" } {
				return
			}
		}
	}
	close $fhgrp

	puts stderr "\nIn order for this user to have RT access for audio applications\n
	A log out and login needs to be performed.\n\n"
	tk_messageBox -parent . -title Warning -type ok \
		-icon error -message \
		"In order for this user to have RT access for audio applications\n
		A log out and login needs to be performed"
}


#---------------------------------------------------
#
#	Things below here are the GUI (running loop)
#
#---------------------------------------------------

wm title . "Ubuntu Studio Installer"

#row 0 - top label
label .top -text "Select packages to install" -height 2
grid config .top -column 0 -columnspan 6 -row 0

#row 1 - Package list
listbox .list -yscrollcommand ".scroll set" -height 15 \
	-selectmode multiple -selectbackground LightGrey \
	-background White -width 30
listbox .desc -height 15 -disabledforeground black \
	-yscrollcommand ".scroll set" -width 80
scrollbar .scroll -command ".list yview"
if {!$argc} {
	set cllist $default_packages
	set clnum $default_number
	makelist $default_packages $default_number
} else  {
	set cllist $argv
	set clnum $argc
	makelist $argv $argc
}

bind .list <Button> { after 1 selectdet }
grid config .list -column 1 -row 1
grid config .desc -column 2 -columnspan 3 -row 1
grid config .scroll -column 5 -row 1 -sticky ns

# row 2 & 3 - get install widgets ready but don't show
label .info -text "Authenticating" -height 2 -width 120
frame .lower 
frame .lower.bar -height 20 -width 0 -bg blue
frame .lower.bg -height 20 -width 600 -bg white
pack .lower.bar .lower.bg -side left

# row 4 - buttons
frame .bleft -width 10
frame .bright -width 10
button .install -state "disabled" -text "Install selected packages" \
	-command install
button .exit -text "Exit" -command exit
button .ppa -text "Enable Backports PPA" -command do_ppa
button .noppa -text "Disable Backports PPA" -command undo_ppa
grid config .exit -column 1 -row 4
grid config .ppa -column 2 -row 4
grid config .noppa -column 3 -row 4
grid config .install -column 4 -row 4
grid config .bleft -column 0 -row 4
grid config .bright -column 5 -row 4
ppa_check

