#!/usr/bin/ruby
# encoding: utf-8

require 'gtk2'
require "rexml/document"

# License? GPL v2.0

#LANGUAGE = ENV['LANGUAGE'][0..1]

#@xbranding = File.new( "/etc/lesslinux/branding/branding.xml" )
#@branding = REXML::Document.new  @xbranding

assi = Gtk::Assistant.new
# assi.deletable = false

$dummy = false
alldisks = nil
partarray = []
diskarray = []
niceparts = []
nicedrives = []
partsizes = []
drivesizes = []
targets = []
nicetargets = []
xml_read_count = 0
initdone = false

def read_devs
	xml_obj = nil
	if ARGV.size > 0 
		file = File.new( ARGV[0] )
		doc = REXML::Document.new(file)
		$dummy = true
	else	
		system("sudo /sbin/mdev -s")
		sleep 2
		xmlstr = ""
		IO.popen("sudo /usr/sbin/lshw-static -xml") { |x|
			while x.gets
				xmlstr = xmlstr +$_
			end
		}
		doc = REXML::Document.new(xmlstr)
	end
	return doc
end

def scan_parts (doc)
	alldisks = []
	doc.elements.each("//node[@class='storage']") { |x|
		businfo = x.elements["businfo"].text.to_s
		storageproduct = ""
		begin
			storageproduct = x.elements["vendor"].text.to_s + " " + x.elements["product"].text.to_s
		rescue
		end
		x.elements.each("node[@class='disk']") { |element|
			parts = []
			product = ""
			size = 0
			unit = ""
			cdrom = false
			diskname = element.elements["logicalname"].text.to_s
			begin
				product = element.elements["product"].text.to_s
			rescue
				product = element.elements["description"].text.to_s 
				product = storageproduct unless storageproduct == ""
			end
			begin
				size = element.elements["size"].text.to_i
				unit = element.elements["size"].attributes["units"]
			rescue
			end
			# puts element.attributes["handle"]  + " " + product + " " + businfo + " " + size.to_s + " " + unit
			if element.attributes["id"] =~ /^cdrom/ 
				#	puts "  " + element.elements["logicalname"].text
				cdrom = true
				mount_point = nil
				log_name = []
				element.elements.each("logicalname") { |l| log_name.push(l.text) }
				state = "clear"
				if log_name.size > 1
					mount_point = log_name[1] 
					state = "mounted"
				end
				parts.push( [ element.elements["logicalname"].text, "iso9660", state, mount_point, false, 0 ] )
			end
			element.elements.each("node[@class='volume']") { |n|
				state = ""
				mount_options = []
				rw = false
				begin
					puts "Checking: " + n.elements["logicalname"].text
					state = n.elements["configuration/setting[@id='state']"].attributes["value"].to_s
					mount_options = n.elements["configuration/setting[@id='mount.options']"].
						attributes["value"].to_s.split(",")
					mount_options.each { |m| rw = true if m == "rw" }
				rescue
				end
				fstype = nil
				begin
					fstype = n.elements["configuration/setting[@id='filesystem']"].attributes["value"].strip
				rescue
					fstype = n.elements["logicalname"].text
				end
				is_extended = false
				begin
					is_extended = true if n.elements["capabilities/capability[@id='partitioned:extended']"].text.strip == "Extended partition"
				rescue
				end
				unless  is_extended == true # || fstype == "swap"
					# puts "  " + n.attributes["id"] + " " + n.elements["logicalname"].text + " " + 
					#	n.elements["configuration/setting[@id='filesystem']"].attributes["value"] + " " + state
					mount_point = nil
					log_name = []
					capacity = 0
					begin
						capacity = n.elements["capacity"].text.to_i
					rescue
					end
					n.elements.each("logicalname") { |l| log_name.push(l.text) }
					mount_point = log_name[1] if log_name.size > 1
					parts.push( [ n.elements["logicalname"].text,
					fstype.to_s,
					state, mount_point, rw, capacity ] )
				end
				if is_extended == true
					n.elements.each("node[@class='volume']") { |m|
						begin
							istate = ""
							imount_options = []
							irw = false
							begin
								istate = m.elements["configuration/setting[@id='state']"].attributes["value"].to_s
								imount_options = m.elements["configuration/setting[@id='mount.options']"].
									attributes["value"].to_s.split(",")
								imount_options.each { |o| irw = true if o == "rw" }
							rescue
							end
							ifstype = nil
							begin
								ifstype = m.elements["configuration/setting[@id='filesystem']"].attributes["value"].strip
							rescue
								ifstype = "unbekanntes Dateisystem"
								m.elements.each("description") { |d|
									puts "Checking: " + d.text
									ifstype = "fat" if d.text =~ /FAT/
									ifstype = "ntfs" if d.text =~ /NTFS/
 									ifstype = "ext3" if d.text =~ /Linux/
									if d.text =~ /swap/
										ifstype = "swap"
										fstype = "swap"
									end
								}
							end
							unless fstype == "swap"
								mount_point = nil
								log_name = []
								capacity = 0
								begin
									capacity = m.elements["capacity"].text.to_i
								rescue
								end
								m.elements.each("logicalname") { |l| log_name.push(l.text) }
								mount_point = log_name[1] if log_name.size > 1
								parts.push( [ m.elements["logicalname"].text,
								ifstype.to_s,
								istate, mount_point, rw, capacity ] )
							end
						rescue
						end
					}
				end
				
			}
			alldisks.push( [  businfo, product, size, unit, cdrom, parts, diskname ] )
		}
		# FIXME: This is weird copy&paste
		x.elements.each("node[@class='disk']/node[@class='disk']") { |element|
			parts = []
			product = ""
			size = 0
			unit = ""
			cdrom = false
			diskname = element.elements["logicalname"].text.to_s
			begin
				product = element.elements["product"].text.to_s
			rescue
				# product = element.elements["description"].text.to_s
				product = "unbekannt"
			end
			begin
				size = element.elements["size"].text.to_i
				unit = element.elements["size"].attributes["units"]
			rescue
			end
			# puts element.attributes["handle"]  + " " + product + " " + businfo + " " + size.to_s + " " + unit
			if element.attributes["id"] =~ /^cdrom/ 
				#	puts "  " + element.elements["logicalname"].text
				cdrom = true
				mount_point = nil
				log_name = []
				element.elements.each("logicalname") { |l| log_name.push(l.text) }
				state = "clear"
				if log_name.size > 1
					mount_point = log_name[1] 
					state = "mounted"
				end
				parts.push( [ element.elements["logicalname"].text, "iso9660", state, mount_point, false, 0 ] )
			end
			element.elements.each("node[@class='volume']") { |n|
				state = ""
				mount_options = []
				rw = false
				begin
					puts "Checking: " + n.elements["logicalname"].text
					state = n.elements["configuration/setting[@id='state']"].attributes["value"].to_s
					mount_options = n.elements["configuration/setting[@id='mount.options']"].
						attributes["value"].to_s.split(",")
					mount_options.each { |m| rw = true if m == "rw" }
				rescue
				end
				fstype = nil
				begin
					fstype = n.elements["configuration/setting[@id='filesystem']"].attributes["value"].strip
				rescue
					fstype = "unbekanntes Dateisystem"
				end
				is_extended = false
				begin
					is_extended = true if n.elements["capabilities/capability[@id='partitioned:extended']"].text.strip == "Extended partition"
				rescue
				end
				unless is_extended == true # || fstype == "swap" 
					# puts "  " + n.attributes["id"] + " " + n.elements["logicalname"].text + " " + 
					#	n.elements["configuration/setting[@id='filesystem']"].attributes["value"] + " " + state
					mount_point = nil
					log_name = []
					capacity = 0
					begin
						capacity = n.elements["capacity"].text.to_i
					rescue
					end
					n.elements.each("logicalname") { |l| log_name.push(l.text) }
					mount_point = log_name[1] if log_name.size > 1
					parts.push( [ n.elements["logicalname"].text,
					fstype.to_s,
					state, mount_point, rw, capacity ] )
				end
				if is_extended == true
					n.elements.each("node[@class='volume']") { |m|
						begin
							istate = ""
							imount_options = []
							irw = false
							begin
								istate = m.elements["configuration/setting[@id='state']"].attributes["value"].to_s
								imount_options = m.elements["configuration/setting[@id='mount.options']"].
									attributes["value"].to_s.split(",")
								imount_options.each { |o| irw = true if o == "rw" }
							rescue
							end
							ifstype = nil
							begin
								ifstype = m.elements["configuration/setting[@id='filesystem']"].attributes["value"].strip
							rescue
								ifstype = "unbekanntes Dateisystem"
							end
							# unless fstype == "swap"
							mount_point = nil
							log_name = []
							capacity = 0
							begin
								capacity = m.elements["capacity"].text.to_i
							rescue
							end
							m.elements.each("logicalname") { |l| log_name.push(l.text) }
							mount_point = log_name[1] if log_name.size > 1
							parts.push( [ m.elements["logicalname"].text,
							ifstype.to_s,
							istate, mount_point, rw, capacity ] )
							# end
						rescue
						end
					}
				end
				
			}
			alldisks.push( [  businfo, product, size, unit, cdrom, parts, diskname ] )
		}
		x.elements.each("node[@class='volume']") { |element|
			if element.elements["logicalname"].text =~ /^\/dev\/sd/ && businfo =~ /^usb/
				diskname = element.elements["logicalname"].text.to_s
				parts = []
				product = ""
				size = 0
				unit = ""
				cdrom = false
				istate = ""
				imount_options = []
				irw = false
				begin
					istate = element.elements["configuration/setting[@id='state']"].attributes["value"].to_s
					imount_options = element.elements["configuration/setting[@id='mount.options']"].
					attributes["value"].to_s.split(",")
					imount_options.each { |o| irw = true if o == "rw" }
				rescue
				end
				ifstype = nil
				begin
					ifstype = element.elements["configuration/setting[@id='filesystem']"].attributes["value"].strip
				rescue
					ifstype = "unbekanntes Dateisystem"
				end
				# udrive = UsbDrive.new(element.elements["logicalname"].text)
				begin
					product = x.elements["vendor"].text + " " + x.elements["product"].text
				#	udrive.product = x.elements["product"].text
				rescue
				end
				mount_point = nil
				log_name = []
				size = element.elements["size"].text.to_i
				capacity = 0
				begin
					capacity = m.elements["capacity"].text.to_i
				rescue
				end
				element.elements.each("logicalname") { |l| log_name.push(l.text) }
				mount_point = log_name[1] if log_name.size > 1
				parts.push( [ element.elements["logicalname"].text, ifstype.to_s, istate, mount_point, irw, capacity ] )
				alldisks.push( [  businfo, product, size, unit, cdrom, parts, diskname ] )
			end
			#all_drives[element.elements["logicalname"].text] = udrive unless 
			#all_drives.has_key?( element.elements["logicalname"].text )
		}
	}
	return alldisks
end

def update_partcombo(disks, partcombo, partrows, drivecombo, driverows)
	(partrows - 1).downto(0) { |i| 
		puts "removing " + i.to_s
		partcombo.remove_text(i)
	}
	(driverows - 1).downto(0) { |i| 
		puts "removing " + i.to_s
		drivecombo.remove_text(i)
	}
	part_array = []
	new_rows = 0
	disk_array = []
	disk_rows = 0
	niceparts = []
	nicedrives = []
	partsizes = []
	drivesizes = []
	disks.each { |d|
		sizestr = ""
		if d[2] > 7_900_000_000
			sizestr = ((d[2].to_f / 1073741824 ) + 0.5).to_i.to_s + "GB"
		else
			sizestr = (d[2].to_f / 1048576 ).to_i.to_s + "MB"
		end
		businfo = "IDE/SATA"
		businfo = "USB" if d[0] =~ /^usb/
		mounted = false
		d[5].each { |p|
			psize = ""
			if p[5] > 7_900_000_000
				psize = ((p[5].to_f / 1073741824 ) + 0.5).to_i.to_s + "GB"
			else
				psize = (p[5].to_f / 1048576 ).to_i.to_s + "MB"
			end
			unless p[2] == "mounted" || d[4] == true
				nicepart = d[1] + " (" + businfo + ", " + sizestr + ") Partition " + p[0] + " (" + p[1] + ", " + psize + ")"
				partcombo.append_text(nicepart)
				new_rows += 1
				part_array.push(p[0])
				niceparts.push(nicepart)
				partsizes.push(p[5])
			else
				mounted = true
			end
		}
		unless mounted == true || d[6].strip =~ /^\/dev\/sr/  
			begin
				device = d[6]
				nicedrive = d[1] + " " + device + " (" + businfo + ", " + sizestr + ")"
				drivecombo.append_text(nicedrive)
				disk_rows += 1
				disk_array.push(device)
				nicedrives.push(nicedrive)
				drivesizes.push(d[2])
			rescue
				puts "trouble processing " + d[5].join(" // ")
			end
		end
	}
	if new_rows < 1
		partcombo.append_text("Keine geeignete Quellpartition gefunden - ggf. Laufwerkseinbindungen lösen")
		partcombo.active = 0
		partcombo.sensitive = false
	end
	if disk_rows < 1
		drivecombo.append_text("Keine geeignete Quellfestplatte gefunden - ggf. Laufwerkseinbindungen lösen")
		drivecombo.active = 0
		drivecombo.sensitive = false
	end
	partcombo.active = 0
	drivecombo.active = 0
	return new_rows, part_array, disk_rows, disk_array, niceparts, nicedrives, partsizes, drivesizes
end


def update_target_combo(disks, targetcombo, partcombo, partarray, niceparts, drivecombo, diskarray, nicedrives, use_part)
	100.downto(0) { |i|
		begin
			targetcombo.remove_text(i)
		rescue
		end
	}
	begin
		$stderr.puts "Use partition: " + use_part.to_s
		$stderr.puts "Selected partition: " + partarray[partcombo.active].to_s + " " + niceparts[partcombo.active].to_s
		$stderr.puts "Selected disk: " + diskarray[drivecombo.active].to_s + " " + nicedrives[drivecombo.active].to_s
	rescue
	end
	targets = Array.new
	nicetargets = Array.new
	minsize = 0
	disks.each { |d|
		if use_part == true && !d[5].nil?
			d[5].each { |p|	minsize = p[5] if partarray[partcombo.active] == p[0] }
		else	
			minsize = d[2] if diskarray[drivecombo.active] == d[6] 
		end
	}
	puts "Minimum size: " + minsize.to_s
	disks.each { |d|
		sizestr = ""
		if d[2] > 7_900_000_000
			sizestr = ((d[2].to_f / 1073741824 ) + 0.5).to_i.to_s + "GB"
		else
			sizestr = (d[2].to_f / 1048576 ).to_i.to_s + "MB"
		end
		businfo = "IDE/SATA"
		businfo = "USB" if d[0] =~ /^usb/
		if use_part == true && !d[5].nil?
			d[5].each { |p|
				psize = ""
				if p[5] > 7_900_000_000
					psize = ((p[5].to_f / 1073741824 ) + 0.5).to_i.to_s + "GB"
				else
					psize = (p[5].to_f / 1048576 ).to_i.to_s + "MB"
				end
				unless p[2] == "mounted" || p[0] =~ /^\/dev\/sr/ || 
					p[5] < minsize || partarray[partcombo.active] == p[0] 
					puts p[0].to_s + " " + p[5].to_s + " " + p[2].to_s
					targets.push(p[0])
					nicetarget = d[1] + " (" + businfo + ", " + sizestr + ") Partition " +
						p[0] + " (" + p[1] + ", " + psize + ")"
					nicetargets.push(nicetarget)
					targetcombo.append_text(nicetarget)
					targetcombo.sensitive = true
				end
			}
		elsif !(d[6].strip =~ /^\/dev\/sr/)
			# find out if mounted
			is_mounted = false
			d[5].each { |p| is_mounted = true if p[2] == "mounted" } unless d[5].nil?
			if d[2] >= minsize && is_mounted == false && diskarray[drivecombo.active] != d[6] 
				puts d[1] + " " + d[2].to_s
				targets.push(d[6])
				nicetarget = d[1] + " " + d[6] + " (" + businfo + ", " + sizestr + ")"
				nicetargets.push(nicetarget)
				targetcombo.append_text(nicetarget)
				targetcombo.sensitive = true
			end
		end
		
	}
	if targets.size < 1
		targetcombo.append_text("Kein geeignetes Ziellaufwerk vorhanden")
		targetcombo.sensitive = false
	end
	targetcombo.active = 0
	return targets, nicetargets
end

#========================================
# Core logic
#========================================

def apply_settings(source_dev, target_dev, assi)
	logfile = "/tmp/ddrescue_" + rand(10_000_000_000).to_s
	command = "ddrescue --no-split " + source_dev + " " + target_dev + " " + logfile 
	puts command
	if $dummy == false
		system("Terminal --geometry=80x12 --hide-toolbars --hide-menubar --disable-server -T \"Bitweises Klonen 1. " + 
			"Durchlauf - Bitte nicht schließen\" -x " + command)
	end
	command = "ddrescue --direct --max-retries=3 " + source_dev + " " + target_dev + " " + logfile 
	puts command
	if $dummy == false
		system("Terminal --geometry=80x12 --hide-toolbars --hide-menubar --disable-server -T \"Bitweises Klonen 2. " + 
			"Durchlauf - Bitte nicht schließen\" -x " + command)
	end
	command = "ddrescue --direct --retrim --max-retries=3 " + source_dev + " " + target_dev + " " + logfile
	puts command
	if $dummy == false
		system("Terminal --geometry=80x12 --hide-toolbars --hide-menubar --disable-server -T \"Bitweises Klonen 3. " + 
			"Durchlauf - Bitte nicht schließen\" -x " + command)
	end
	dialog = Gtk::Dialog.new("MBR neu geschrieben",assi,Gtk::Dialog::MODAL,
			[ Gtk::Stock::OK, Gtk::Dialog::RESPONSE_OK ]
		)
	dialog.has_separator = false
	label = Gtk::Label.new("Das Kopieren ist abgeschlossen!")
	label.wrap = true
	image = Gtk::Image.new(Gtk::Stock::DIALOG_INFO, Gtk::IconSize::DIALOG)
	hbox = Gtk::HBox.new(false, 5)
	hbox.border_width = 10
	hbox.pack_start_defaults(image);
	hbox.pack_start_defaults(label);
	dialog.vbox.add(hbox)
	dialog.show_all
	dialog.run
	dialog.destroy
	system("sudo /sbin/mdev -s")
end

#========================================
# First window - tell the user what we do
#========================================

desclabel = Gtk::Label.new
desclabel.set_markup("Dieser Assistent hilft Ihnen beim <b>Kopieren von Festplatten oder Partitionen</b>. Das Programm ist in der Lage, auch im Falle defekter Blöcke einen Großteil der Daten zu kopieren.\n\nIm Gegensatz zu anderen Imaging- oder Kopierprogrammen kopiert dieses Werkzeug auch unbelegte Blöcke. So können Sie sogar von Kopien defekter Festplatten noch gelöschte Dateien wiederherstellen. Ein weiteres Einsatzbeispiel ist der Umzug eines kompletten Betriebssystems auf eine größere Festplatte. Nach dem Kopieren können Sie mit Partitionierungsprogrammen wie GParted die enthaltenen Partitionen auf den freien Platz strecken.\n\nDie neue Festplatte muss mindestens so groß sein wie die alte.")
desclabel.wrap = true
desclabel.width_request = 550
desclabel.xalign = 0.1

descpage = assi.append_page(desclabel)
assi.set_page_title(desclabel, "Exakte Kopie von Festplatten" )
assi.set_page_type(desclabel, Gtk::Assistant::PAGE_CONTENT)
assi.set_page_complete(desclabel, true) # false)

#========================================
# Second window - choose the source dev
#========================================

partlabel = Gtk::Label.new("Wählen Sie das Laufwerk, welches Sie kopieren wollen. Sie können einzelne Partitionen oder gesamte Festplatten kopieren. Für einen Umzug ist die Auswahl der gesamten Festplatte notwendig, zur Vorbereitung einer Datenrettung genügt in der Regel das Kopieren einer einzelnen Partition.")
partlabel.wrap = true
partlabel.width_request = 550
partlabel.xalign = 0.1

partbox = Gtk::VBox.new(false, 5)
partbox.pack_start(partlabel, false, true, 5)

partradio = Gtk::RadioButton.new("Inhalt einer Partition kopieren")
partcombo = Gtk::ComboBox.new
# partcombo.append_text("/dev/sda1 Hulla")
# partcombo.append_text("/dev/sdb9 Bulla")
# partcombo.active = 0
partrows = 0
partbox.pack_start(partradio, false, true, 5)
partbox.pack_start(partcombo, false, true, 5)
diskradio = Gtk::RadioButton.new(partradio, "Komplette Festplatte kopieren")
diskcombo = Gtk::ComboBox.new
# diskcombo.append_text("/dev/sda Hulla")
# diskcombo.append_text("/dev/sdb Bulla")
# diskcombo.active = 0
diskrows = 0
diskcombo.sensitive = false
partbox.pack_start(diskradio, false, true, 5)
partbox.pack_start(diskcombo, false, true, 5)

partpage = assi.append_page(partbox)
assi.set_page_title(partbox, "Auswahl des Laufwerkes" )
assi.set_page_type(partbox, Gtk::Assistant::PAGE_CONTENT)
assi.set_page_complete(partbox, false)

#========================================
# Third window - choose the target dev
#========================================

targlabel = Gtk::Label.new
targlabel.set_markup("Wählen Sie das Ziellaufwerk. Es werden nur Laufwerke angezeigt, welche mindestens die Größe des im letzten Schritt ausgewählten Quelllaufwerkes haben.")
targlabel.wrap = true
targlabel.width_request = 550
targlabel.xalign = 0.1

targcombo = Gtk::ComboBox.new

targbox = Gtk::VBox.new(false, 5)
targbox.pack_start(targlabel, false, true, 5)
targbox.pack_start(targcombo, false, true, 5)

targpage = assi.append_page(targbox)
assi.set_page_title(targbox, "Auswahl des Zieles" )
assi.set_page_type(targbox, Gtk::Assistant::PAGE_CONTENT)
assi.set_page_complete(targbox, false)

#========================================
# Last window - confirm the settings
#========================================

lastlabel = Gtk::Label.new("Wollen Sie das Kopieren mit den vorgenommenen Einstellungen durchführen?")
lastlabel.wrap = true
lastlabel.width_request = 550
lastlabel.xalign = 0.1

ovlabel = Gtk::Label.new
ovlabel.wrap = true
ovlabel.width_request = 500
ovlabel.xalign = 0.3

lastdesc = Gtk::Label.new
lastdesc.set_markup("<b>Haftungsausschluß:</b> Ich bin mir bewußt, dass beim Kopieren alle bislang vorhandenen Daten auf der Zielfestplatte oder -partition überschrieben werden und unwiederbringlich verloren sind.")
lastdesc.wrap = true
lastdesc.width_request = 500
lastdesc.xalign = 0.1
lastcheck = Gtk::CheckButton.new
lasthbox = Gtk::HBox.new(false, 5)
lasthbox.pack_start(lastcheck, false, true, 5)
lasthbox.pack_start(lastdesc, false, true, 5)

lastbox = Gtk::VBox.new(false, 5)
lastbox.pack_start(lastlabel, false, true, 5)
lastbox.pack_start(ovlabel, false, true, 5)
lastbox.pack_start(lasthbox, false, true, 5)

lastpage = assi.append_page(lastbox)
assi.set_page_title(lastbox, "Zusammenfassung")
assi.set_page_type(lastbox, Gtk::Assistant::PAGE_CONFIRM)
assi.set_page_complete(lastbox, false)

partcombo.signal_connect('changed') {
	lastcheck.active = false
	assi.set_page_complete(lastbox, false)
	targets, nicetargets = update_target_combo(alldisks, targcombo, partcombo, 
		partarray, niceparts, diskcombo, diskarray, nicedrives, partradio.active?) if initdone == true
	if targets.size > 0 
		assi.set_page_complete(targbox, true)
	else
		assi.set_page_complete(targbox, false)
	end
}

diskcombo.signal_connect('changed') {
	lastcheck.active = false
	assi.set_page_complete(lastbox, false)
	targets, nicetargets = update_target_combo(alldisks, targcombo, partcombo, 
		partarray, niceparts, diskcombo, diskarray, nicedrives, partradio.active?) if initdone == true
	if targets.size > 0 
		assi.set_page_complete(targbox, true)
	else
		assi.set_page_complete(targbox, false)
	end
}

partradio.signal_connect("clicked") { |b|
	lastcheck.active = false
	assi.set_page_complete(lastbox, false)
	diskcombo.sensitive = false
	partcombo.sensitive = true
	targets, nicetargets = update_target_combo(alldisks, targcombo, partcombo, partarray, 
		niceparts, diskcombo, diskarray, nicedrives, partradio.active?) if initdone == true
	if targets.size > 0 
		assi.set_page_complete(targbox, true)
	else
		assi.set_page_complete(targbox, false)
	end
}

diskradio.signal_connect("clicked") { |b|
	lastcheck.active = false
	assi.set_page_complete(lastbox, false)
	partcombo.sensitive = false
	diskcombo.sensitive = true
	targets, nicetargets = update_target_combo(alldisks, targcombo, partcombo, partarray, 
		niceparts, diskcombo, diskarray, nicedrives, partradio.active?) if initdone == true
	if targets.size > 0 
		assi.set_page_complete(targbox, true)
	else
		assi.set_page_complete(targbox, false)
	end
}

targcombo.signal_connect('changed') {  |b|
	assi.set_page_complete(lastbox, false)
	lastcheck.active = false
}

lastcheck.signal_connect('clicked') { |b|
	if b.active? 
		assi.set_page_complete(lastbox, true)
	else
		assi.set_page_complete(lastbox, false)
	end
}

#========================================
# Common settings and callbacks
#========================================

assi.set_title  "Exakte Kopie von Festplatten"
assi.border_width = 10
assi.set_size_request(600, 410)
assi.signal_connect('destroy') { Gtk.main_quit }
assi.signal_connect('cancel')  { assi.destroy }
assi.signal_connect('close')   { |w|
	source_dev = diskarray[diskcombo.active]
	source_dev = partarray[partcombo.active] if partradio.active? == true
	apply_settings(source_dev, targets[targcombo.active], w)
	w.destroy
}

assi.set_forward_page_func{|curr|
	#searchformats = []
	#formatcount = 0
	#format_checkboxes.each { |c|
	#	searchformats.push(formats[formatcount]) if c.active?
	#	formatcount += 1
	#}
	scandev = ""
	nicedev = ""
	scansize = 0
	mintime = 0
	maxtime = 0
	if partradio.active? == true
		scandev = partarray[partcombo.active]
		nicedev = niceparts[partcombo.active]
		scansize = partsizes[partcombo.active]
	else
		scandev = diskarray[diskcombo.active]
		nicedev = nicedrives[diskcombo.active]
		scansize = drivesizes[diskcombo.active]
	end
	maxtime = scansize.to_i / 720_000_000
	mintime = scansize.to_i / 3_600_000_000
	minmaxunit = " Minuten"
	if mintime > 120
		mintime = scansize.to_i / 3_600_000_000 / 60
		maxtime = scansize.to_i / 720_000_000 / 60
		minmaxunit = " Stunden"
	end
	begin
		ovlabel.set_markup("<b>Quelllaufwerk:</b> " + nicedev.to_s + "\n\n<b>Ziellaufwerk:</b> " + 
			nicetargets[targcombo.active] + "\n\n<b>Geschätzte Dauer:</b> " + mintime.to_s  + " bis " +
			maxtime.to_s + minmaxunit)
	rescue
	end
	#	" überschreiben\n\n<b>Benötigte Zeit:</b> " + 
	#	mintime.to_i.to_s + " bis " + maxtime.to_i.to_s + minmaxunit + " (geschätzt)" )
	puts curr
	if curr == 0
		# when switching from first to second screen, read drivelist
		puts "current screen 0, rereading drivelist"
		alldisks = scan_parts(read_devs) if xml_read_count < 1
		
		#alldisks.each { |d|
			# d[0] businfo
			# d[1] Name
			# d[2] Größe in Bytes
			# d[3] Einheit
			# d[4] Boolean CDROM
			# d[5] Partitionen / Array
			# d[5][0][0] Device 
			# d[5][0][1] Filesystem
			# d[5][0][2] Mounted (String)
			# d[5][0][4] Mounted (Boolean)
			#puts " -+- " + d[5][0][6].to_s + " -+-"
		#}
		if xml_read_count < 1
			partrows, partarray, diskrows, diskarray, niceparts, nicedrives, partsizes, drivesizes = 
				update_partcombo(alldisks, partcombo, partrows, diskcombo, diskrows)
		end
		targets, nicetargets = update_target_combo(alldisks, targcombo, partcombo, partarray, niceparts, diskcombo, diskarray, nicedrives, partradio.active?) if xml_read_count < 1
		xml_read_count += 1
		if diskrows < 1 
			diskradio.sensitive = false
			diskcombo.sensitive = false
		else
			diskradio.sensitive = true
		end
		if partrows < 1 
			partradio.sensitive = false
			partcombo.sensitive = false
			diskradio.active = true
		else
			partradio.sensitive = true
		end
		if diskrows + partrows > 0
			assi.set_page_complete(partbox, true)
		else
			assi.set_page_complete(partbox, false)
		end
		if targets.size > 0 
			assi.set_page_complete(targbox, true)
		else
			assi.set_page_complete(targbox, false)
		end
		initdone = true
		# usbdrives = get_usbdrives_lshw
		# puts usbdrives
		# usable_drives = create_drivelist(choicebox, usable_drives.size, usbdrives)
		# assi.set_page_complete(choice_vbox, usable_drives.size > 0)
		1
	else
		curr + 1
	end
	
}

assi.show_all
Gtk.main