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

require 'MfsTranslator.rb'

class UsbInstallScreen	
	def initialize(extlayers, button)
		lang = ENV['LANGUAGE'][0..1]
		lang = ENV['LANG'][0..1] if lang.nil?
		lang = "en" if lang.nil?
		@tlx = MfsTranslator.new(lang, "UsbInstallScreen.xml")
		@layers = Array.new
		@extlayers = extlayers 
		@killinstall = false
		@lang = ENV['LANGUAGE'][0..1]
		@lang = ENV['LANG'][0..1] if @lang.nil?
		@lang = "en" if @lang.nil?
		@tlfile = "usbinstall.xml"
		# tlfile = "/usr/share/lesslinux/drivetools/usbinstall.xml" if File.exists?("/usr/share/lesslinux/drivetools/usbinstall.xml")
		@tl = MfsTranslator.new(@lang, @tlfile)
		### ComboBox for target drives
		@targetcombo = Gtk::ComboBox.new
		@targetdrives = Array.new
		### ProgressBar for running dd
		@installprogress = Gtk::ProgressBar.new
		# attach target screen
		target = create_target_screen(extlayers)
		extlayers["installtarget"] = target
		@layers.push target
		# attach progress screen
		installing = create_progress_screen(extlayers)
		extlayers["installprogress"] = installing
		@layers.push installing
		
		button.signal_connect('button-release-event') { |x, y|
			if y.button == 1 
				extlayers.each { |k,v|v.hide_all }
				@targetdrives = reread_drivelist(@targetcombo)
				extlayers["installtarget"].show_all
			end
		}
	end
	attr_reader :layers
	
	def create_target_screen(extlayers)
		fixed = Gtk::Fixed.new
		TileHelpers.place_back(fixed, extlayers)
		text5 = Gtk::Label.new
		text5.width_request = 250
		text5.wrap = true
		text5.set_markup("<span color='white'>" + @tlx.get_translation("gotoinstall") + "</span>")
		forw  = Gtk::EventBox.new.add Gtk::Image.new("forward.png")
		tile = Gtk::EventBox.new.add Gtk::Image.new("usbgreen.png")
		@targetcombo.height_request = 32
		@targetcombo.width_request = 380
		deltext = TileHelpers.create_label("<b>" + @tlx.get_translation("targethead") + "</b>\n\n" + @tlx.get_translation("targetbody"), 510)
		reread = Gtk::Button.new(@tl.get_translation("reread"))
		reread.width_request = 120
		reread.height_request = 32
		reread.signal_connect('clicked') { 
			@targetdrives = reread_drivelist(@targetcombo)
		}
		forw.signal_connect('button-release-event') { |x, y|
			if y.button == 1 
				# Some checks here!
				if @targetdrives.size < 1
					TileHelpers.error_dialog(@tlx.get_translation("targeterrorbody"), @tlx.get_translation("targeterrorhead"))
				elsif TileHelpers.yes_no_dialog(@tlx.get_translation("confirmbody"), @tlx.get_translation("confirmhead"))
					@killinstall = false
					target = @targetdrives[@targetcombo.active] 
					extlayers.each { |k,v|v.hide_all }
					extlayers["installprogress"].show_all
					# run_install(@cloneprogress)
					run_installation(target, "de", [0,0], @installprogress) 
					if @killinstall == false
						TileHelpers.success_dialog(@tlx.get_translation("successbody"), @tlx.get_translation("successhead"))
					else
						TileHelpers.success_dialog(@tlx.get_translation("cancelbody"), @tlx.get_translation("cancelhead"))
					end
					extlayers.each { |k,v|v.hide_all }
					extlayers["start"].show_all
				end
			end
		}
		fixed.put(tile, 0, 0)
		fixed.put(@targetcombo, 130, 128)
		fixed.put(deltext, 130, 0)
		fixed.put(reread, 520, 128)
		fixed.put(forw, 853, 282)
		fixed.put(text5, 605, 288)
		return fixed
	end
	
	def calculate_min_size 
		sysmount = ""
		[ "/lesslinux/cdrom", "/lesslinux/isoloop" ].each { |m|
			sysmount = m if system("mountpoint -q #{m}")
		}
		if sysmount == ""
			error_dialog( @tl.get_translation("no_system_title"), @tl.get_translation("no_system_found"))
			exit 1 
		end
		sysdev = ` df -k #{sysmount} | tail -n1 `.strip.split[0].to_s
		isosize = ` df -k #{sysmount} | tail -n1 `.strip.split[2].to_i * 1024  
		efisize = ` ls -lak #{sysmount}/boot/efi/efi.img `.strip.split[4].to_i 
		bootsize = ` du -k #{sysmount}/boot | tail -n1 `.strip.split[0].to_i * 1024
		padsize = 1024 ** 2 * 64 
		minsize = isosize + bootsize + efisize + padsize
		puts "#{minsize.to_s}: #{isosize.to_s} #{bootsize.to_s} #{efisize.to_s} #{padsize.to_s}"
		isoblocks = isosize / ( 1024 ** 2 * 8 ) + 1
		bootblocks = bootsize / ( 1024 ** 2 * 8 ) + 4
		efiblocks = efisize / ( 1024 ** 2 * 8 ) + 1
		return minsize, isoblocks, bootblocks, efiblocks, sysdev, sysmount 
	end
	
	def reread_drivelist(combobox, ignoredrive=nil)
		TileHelpers.umount_all
		100.downto(0) { |i| 
			begin
				combobox.remove_text(i) 
			rescue
			end
		}
		drives = Array.new
		auxdrives = Array.new
		Dir.entries("/sys/block").each { |l|
			auxdrives.push(MfsDiskDrive.new(l, false)) if l =~ /[a-z]$/ 
		}
		auxdrives.each { |d|
			if ignoredrive.nil?
				drives.push(d) unless d.mounted || d.usb == false || d.size < 3_500_000_000 
			else
				drives.push(d) unless d.device == ignoredrive.device || d.mounted || d.usb == false || d.size < 3_500_000_000 
			end
		}  
		drives.each { |d|
			label = label = "#{d.vendor} #{d.model} - #{d.human_size} - #{d.device}"
			if d.usb == true
				label = label + " (USB)"
			else
				label = label + " (SATA/eSATA/IDE)"
			end
			combobox.append_text(label)
		}
		combobox.append_text(@tlx.get_translation("nodrivecombo")) if drives.size < 1 
		combobox.active = 0
		combobox.sensitive = false
		combobox.sensitive = true if drives.size > 0
 		return drives
	end
	
	def create_progress_screen(extlayers)
		fixed = Gtk::Fixed.new
		killswitch = TileHelpers.place_back(fixed, extlayers, false)
		tile = Gtk::EventBox.new.add Gtk::Image.new("usbgreen.png")
		deltext = TileHelpers.create_label("<b>" + @tlx.get_translation("progresshead") + "</b>\n\n" + @tlx.get_translation("progressbody"), 510)
		@installprogress.width_request = 510
		@installprogress.height_request = 32
		killswitch.signal_connect('button-release-event') { |x, y|
			if y.button == 1 
				# Some checks here!
				@killinstall = true 
			end
		}
		fixed.put(tile, 0, 0)
		fixed.put(deltext, 130, 0)
		fixed.put(@installprogress, 130, 108)
		return fixed
	end
	
	def run_command(pgbar, command, args, text)
		puts "Running " + command + " : " + args.join(" ")  
		pgbar.text = text 
		vte = Vte::Terminal.new
		running = true
		vte.signal_connect("child_exited") { running = false }
		vte.fork_command(command, args)
		while running == true
			pgbar.pulse
			while (Gtk.events_pending?)
				Gtk.main_iteration
			end
			sleep 0.2 
		end 
	end
	
	def run_installation(tgt, language, contsizes, pgbar, check=false) 
		sizes = calculate_min_size
		checklist = Array.new
		bootstart = sizes[1] * 8388608 
		efistart = ( sizes[1] + sizes[2] ) * 8388608
		bootend = efistart - 1  
		efiend = ( sizes[1] + sizes[2] + sizes[3]) * 8388608 - 1
		# blank the fist few MB
		# ddstr = "dd if=/dev/zero of=/dev/#{tgt.device} bs=1024 count=1024"
		run_command(pgbar, "dd", [ "dd", "if=/dev/zero", "of=/dev/#{tgt.device}", "bs=1024", "count=1024" ] , @tl.get_translation("preparing")) 
		return false if @killinstall == true
		# puts ddstr 
		# system ddstr 
		# blank the last few MB
		tgtblocks = tgt.size / 1024 - 1024 
		puts tgtblocks.to_s 	
		# ddstr = "dd if=/dev/zero of=/dev/#{tgt.device} bs=1024 seek=#{tgtblocks.to_s}"
		# puts ddstr 
		# system ddstr 
		run_command(pgbar, "dd", [ "dd", "if=/dev/zero", "of=/dev/#{tgt.device}", "bs=1024", "seek=#{tgtblocks.to_s}" ] , @tl.get_translation("preparing")) 
	
		# Copy the ISO image
		0.upto(sizes[1] - 1) { |b|
			return false if @killinstall == true
			system("rm /var/run/lesslinux/copyblock.bin")
			system("rm /var/run/lesslinux/checkblock.bin")
			system("dd if=#{sizes[4]} of=/var/run/lesslinux/copyblock.bin bs=8388608 count=1 skip=#{b.to_s}")
			md5in = ` md5sum /var/run/lesslinux/copyblock.bin `.strip.split[0] 
			md5out = ''
			tries = 0
			matched = false
			while tries < 9 && matched == false 
				system("dd of=/dev/#{tgt.device} if=/var/run/lesslinux/copyblock.bin bs=8388608 count=1 seek=#{b.to_s}")
				system("sync")
				system("dd if=/dev/#{tgt.device} of=/var/run/lesslinux/checkblock.bin bs=8388608 count=1 skip=#{b.to_s}")
				md5out = ` md5sum /var/run/lesslinux/checkblock.bin `.strip.split[0]
				if md5in == md5out 
					matched = true
				else
					puts "ERROR WRITING #{b.to_s} - TRY #{tries.to_s}"
				end
				tries += 1 
			end
			
			# ddstr = "dd if=#{sizes[4]} of=/dev/#{tgt.device} bs=8388608 count=1 seek=#{b.to_s} skip=#{b.to_s}" 
			# puts ddstr 
			# system ddstr 
			percentage = b * 100 / ( sizes[1] - 1 ) 
			pgbar.text =  @tl.get_translation("installsys") + " - #{percentage.to_s}%"
			pgbar.fraction = b.to_f / ( sizes[1] - 1 ).to_f 
			while (Gtk.events_pending?)
				Gtk.main_iteration
			end
		}
		system("rm /var/run/lesslinux/copyblock.bin")
		system("rm /var/run/lesslinux/checkblock.bin")
		# Blank the first 32k 
		system("dd if=/dev/zero bs=8192 count=4 of=/dev/#{tgt.device}")
		# Create the boot partition legacy
		run_command(pgbar, "parted", [ "parted", "-s", "/dev/#{tgt.device}", "unit", "B", "mklabel", "gpt" ] , @tl.get_translation("partitioning")) 
		run_command(pgbar, "parted", [ "parted", "-s", "/dev/#{tgt.device}", "unit", "B", "mkpart", "primary", "ext2", "#{bootstart}", "#{bootend}" ] , @tl.get_translation("partitioning")) 
		run_command(pgbar, "parted", [ "parted", "-s", "/dev/#{tgt.device}", "unit", "B", "set", "1", "legacy_boot", "on" ] , @tl.get_translation("partitioning")) 
		run_command(pgbar, "parted", [ "parted", "-s", "/dev/#{tgt.device}", "unit", "B", "mkpart", "primary", "fat32", "#{efistart}", "#{efiend}" ] , @tl.get_translation("partitioning")) 
		run_command(pgbar, "parted", [ "parted", "-s", "/dev/#{tgt.device}", "unit", "B", "set", "2", "boot", "on" ] , @tl.get_translation("partitioning")) 
		# run_command(pgbar, "parted", [ "parted", "-s", "/dev/#{tgt.device}", "unit", "B", "mkpart", "primary", "fat32", "#{efistart}", "#{efiend}" ] , @tl.get_translation("partitioning")) 
		return false if @killinstall == true
		# tar the content of the legacy boot part 
		run_command(pgbar, "mkfs.ext2", [ "mkfs.ext2", "/dev/#{tgt.device}1" ] , @tl.get_translation("write_boot")) 
		return false if @killinstall == true
		# run_command(pgbar, "mkfs.ext2", [ "mkfs.ext2", "-L", "LLDataExtra", "/dev/#{tgt.device}3" ] , @tl.get_translation("write_boot")) 
		system("mkdir -p /var/run/lesslinux/install_boot")
		return false if @killinstall == true
		run_command(pgbar, "dd", [ "dd", "if=#{sizes[5]}/boot/efi/efi.img", "of=/dev/#{tgt.device}2" ], @tl.get_translation("write_boot")) 
		return false if @killinstall == true
		system("mount -t ext4 /dev/#{tgt.device}1 /var/run/lesslinux/install_boot")
		run_command(pgbar, "rsync", [ "rsync", "-avHP", "#{sizes[5]}/boot", "/var/run/lesslinux/install_boot/" ] , @tl.get_translation("write_boot")) 
		system("chmod -R 0644 /var/run/lesslinux/install_boot/")
		system("mkdir -p /var/run/lesslinux/install_efi")
		system("mount -t vfat /dev/#{tgt.device}2 /var/run/lesslinux/install_efi")
		# Find and move config files 
		cfgfiles = Array.new
		IO.popen("find /var/run/lesslinux/install_boot/boot -name '*.cfg'") { |line|
			while line.gets
				cfgfiles.push $_.strip
			end
		}
		IO.popen("find /var/run/lesslinux/install_efi -name '*.conf'") { |line|
			while line.gets
				cfgfiles.push $_.strip
			end
		}
		cfgfiles.push("/var/run/lesslinux/install_boot/boot/isolinux/extlinux.conf") if File.exists? ("/var/run/lesslinux/install_boot/boot/isolinux/extlinux.conf") 
		cfgfiles.each { |fname|
			puts "Editing: " + fname 
			system("cp -v #{fname}.#{language} #{fname}") if File.exists?("#{fname}.#{language}") 
			system("sed -i 's/homecont=0000-00000/homecont=#{contsizes.min.to_s}-#{contsizes.max.to_s}/g' #{fname}") if contsizes.max > 0 
			system("sed -i 's/swapsize=0000/swapsize=512/g' #{fname}")
			system("sed -i 's/blobsize=0000/blobsize=768/g' #{fname}")
			system("rm #{fname}") if fname =~ /boot0x80\.cfg$/ 	
		}
		system("cp -v /var/run/lesslinux/install_boot/boot/isolinux/{isolinux.cfg,extlinux.conf}") unless File.exists? ("/var/run/lesslinux/install_boot/boot/isolinux/extlinux.conf") 
		# Write syslinux
		system("extlinux --install /var/run/lesslinux/install_boot/boot/isolinux") 
		system("umount /var/run/lesslinux/install_boot")
		system("umount /var/run/lesslinux/install_efi")
		# Write the compat MBR
		sysstr = "dd if=/usr/share/syslinux/gptmbr.bin of=/dev/#{tgt.device}"	
		puts sysstr
		system sysstr
		pgbar.fraction = 1.0
		pgbar.text =  @tl.get_translation("install_finished") 
		# info_dialog( @tl.get_translation("finished_title"), @tl.get_translation("finished_text") ) 
	end
	
	
	
end








