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

class CloneScreen	
	def initialize(extlayers)
		lang = ENV['LANGUAGE'][0..1]
		lang = ENV['LANG'][0..1] if lang.nil?
		lang = "en" if lang.nil?
		@tl = MfsTranslator.new(lang, "CloneScreen.xml")
		@layers = Array.new
		### Kill cloning
		@killclone = false
		### ComboBox for source drives
		@sourcecombo = Gtk::ComboBox.new
		@sourcedrives = Array.new
		### ComboBox for target drives
		@targetcombo = Gtk::ComboBox.new
		@targetdrives = Array.new
		### ProgressBar for running dd
		@cloneprogress = Gtk::ProgressBar.new
		
		# attach source screen
		source = create_source_screen(extlayers)
		extlayers["clonesource"] = source
		@layers.push source
		# attach target screen
		target = create_target_screen(extlayers)
		extlayers["clonetarget"] = target
		@layers.push target
		# attach progress screen
		cloning = create_progress_screen(extlayers)
		extlayers["cloneprogress"] = cloning
		@layers.push cloning
		
		# create_progress_screen
		
	end
	attr_reader :layers
	
	def create_source_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'>" + @tl.get_translation("gototarget") + "</span>")
		forw  = Gtk::EventBox.new.add Gtk::Image.new("forward.png")
		tile = Gtk::EventBox.new.add Gtk::Image.new("rescuegreen.png")
		@sourcecombo.height_request = 32
		@sourcecombo.width_request = 380
		deltext = TileHelpers.create_label(@tl.get_translation("selectsource"), 510)
		@sourcedrives = reread_drivelist(@sourcecombo)
		reread = Gtk::Button.new(@tl.get_translation("reread"))
		reread.width_request = 120
		reread.height_request = 32
		forw.signal_connect('button-release-event') { |x, y|
			if y.button == 1 
				if @sourcedrives.size < 1 
					TileHelpers.error_dialog(@tl.get_translation("nodrivebody"), @tl.get_translation("nodrivehead"))
				else
					@targetdrives = reread_drivelist(@targetcombo, @sourcedrives[@sourcecombo.active] )
					if @targetdrives.size < 1
						TileHelpers.error_dialog(@tl.get_translation("onedrivebody"), @tl.get_translation("nodrivehead"))
					else	
						extlayers.each { |k,v|v.hide_all }
						extlayers["clonetarget"].show_all
					end
				end
			end
		}
		reread.signal_connect('clicked') { 
			@sourcedrives = reread_drivelist(@sourcecombo)
		}
		fixed.put(tile, 0, 0)
		fixed.put(@sourcecombo, 130, 108)
		fixed.put(deltext, 130, 0)
		fixed.put(reread, 520, 108)
		fixed.put(forw, 853, 282)
		fixed.put(text5, 605, 288)
		return fixed
	end
	
	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'>" + @tl.get_translation("gotoclone") + "</span>")
		forw  = Gtk::EventBox.new.add Gtk::Image.new("forward.png")
		tile = Gtk::EventBox.new.add Gtk::Image.new("rescuegreen.png")
		@targetcombo.height_request = 32
		@targetcombo.width_request = 380
		deltext = TileHelpers.create_label(@tl.get_translation("selecttarget"), 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, @sourcedrives[@sourcecombo.active] )
		}
		forw.signal_connect('button-release-event') { |x, y|
			if y.button == 1 
				# Some checks here!
				if TileHelpers.yes_no_dialog(@tl.get_translation("confirmbody"), @tl.get_translation("confirmhead"))
					source = @sourcedrives[@sourcecombo.active] 
					target = @targetdrives[@targetcombo.active] 
					if source.size < target.size ||  TileHelpers.yes_no_dialog(@tl.get_translation("toobigbody"), @tl.get_translation("toobighead"))
						extlayers.each { |k,v|v.hide_all }
						extlayers["cloneprogress"].show_all
						run_clone(@cloneprogress)
						if @killclone == false
							TileHelpers.success_dialog(@tl.get_translation("successbody"), @tl.get_translation("successhead"))
						else
							TileHelpers.success_dialog(@tl.get_translation("failedbody"), @tl.get_translation("failedhead"))
						end
						extlayers.each { |k,v|v.hide_all }
						extlayers["start"].show_all
					end
				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 create_progress_screen(extlayers)
		fixed = Gtk::Fixed.new
		killswitch = TileHelpers.place_back(fixed, extlayers, false)
		tile = Gtk::EventBox.new.add Gtk::Image.new("rescuegreen.png")
		deltext = TileHelpers.create_label(@tl.get_translation("progresslabel"), 510)
		@cloneprogress.width_request = 510
		@cloneprogress.height_request = 32
		killswitch.signal_connect('button-release-event') { |x, y|
			if y.button == 1 
				# Some checks here!
				@killclone = true 
			
			end
		}
		fixed.put(tile, 0, 0)
		fixed.put(deltext, 130, 0)
		 fixed.put(@cloneprogress, 130, 108)
		return fixed
	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
			else
				drives.push(d) unless d.device == ignoredrive.device || d.mounted
			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.active = 0
		return drives
	end
	
	def run_clone(progress)
		@killclone = false
		progress.text = "Start cloning..."
		progress.fraction = 0.0
		starttime = Time.now.to_i
		# threshold for certain block sizes - in bytes
		thres = 32 * 1024 ** 3 
		# chunk size - in megabytes
		chunk = 128
		source = @sourcedrives[@sourcecombo.active] 
		target = @targetdrives[@targetcombo.active] 
		min = [source.size, target.size].min
		puts "Source size: #{source.size.to_s}"
		puts "Target size: #{target.size.to_s}"
		puts "Min size:    #{min.to_s}"
		if min < thres 
			chunk = 16
		end
		# real number is one higher!
		num_chunks = ( min / chunk / ( 1024 ** 2) )
		puts num_chunks.to_s 
		0.upto(num_chunks) { |n|
			unless @killclone == true
				current_time = Time.now.to_i
				position = n * chunk * 1024 ** 2
				chunkbytes = chunk * 1024 ** 2
				progress.fraction = n.to_f / num_chunks.to_f
				while (Gtk.events_pending?)
					Gtk.main_iteration
				end
				command = "ddrescue --force --retry-passes=5 -i #{position.to_s} -o #{position.to_s} -s #{chunkbytes.to_s} /dev/#{source.device} /dev/#{target.device}"
				puts "RUNNING: #{command}"
				system command
				t = @tl.get_translation("percentdone").gsub("PERCENTAGE",  (n * 100 / num_chunks).to_s )
				# t = (n * 100 / num_chunks).to_s + "% abgeschlossen" 
				delta_time = current_time - starttime
				if delta_time > 20 && n > 2
					time_per_chunk = delta_time.to_f / n.to_f
					time_remaining = ( num_chunks.to_f - n.to_f ) * time_per_chunk
					minutes_remaining = ( time_remaining + 30.0 ) / 60.0 
					nice_minutes = minutes_remaining.to_i % 60
					nice_hours = minutes_remaining.to_i / 60
					if nice_hours < 1 && nice_minutes < 3
						t = t + " - " +  @tl.get_translation("remain1") # ca. eine Minute verbleibend"
					elsif nice_hours < 2
						t = t + " - " + @tl.get_translation("remain2").gsub("MINUTES", minutes_remaining.to_i.to_s)
					else
						t = t + " - " + @tl.get_translation("remain2").gsub("MINUTES", nice_minutes.to_s).gsub("HOURS", nice_hours.to_s) 
					end
				end
				progress.text = t
				while (Gtk.events_pending?)
					Gtk.main_iteration
				end
			end
		}
	end
	
end

