#!/usr/bin/ruby
# Filename:	term
# Author:	David Ljung Madison <DaveSource.com>
# See License:	http://MarginalHacks.com/License/
# Description:	Run Windows Terminal, but pick a profile

require 'json'



## Assume $USER is set to the Windows user login as well
Drive = 'C'
User = ENV['USER']

## We need to know where the explorer is so we can launch the Windows App
Explorer = "/mnt/#{Drive.downcase}/Windows/SysWOW64/explorer.exe"

LocalAppData = "#{Drive}:\\Users\\#{User}\\AppData\\Local"
LocalAppDataUnix = "/mnt/#{Drive.downcase}/Users/#{User}/AppData/Local"

Settings = "#{LocalAppDataUnix}/Packages/Microsoft.WindowsTerminal_8wekyb3d8bbwe/LocalState/settings.json"
Terminal = "#{LocalAppData}\\Microsoft\\WindowsApps\\wt.exe"

def fatal(msg)
	$stderr.puts "FATAL: #{msg}"
	exit(-1)
end

def fatalException(msg)
	return nil unless block_given?
	begin
		return yield()
	rescue => e
		fatal("#{msg}:\n  #{e}")
	end
end

def readSettings
	f = fatalException("[#{Settings}] Couldn't open") {
		File.read(Settings)
	}
	settings = fatalException("[#{Settings}] Settings read error") {
		JSON.parse(f)
	}
	settings['profiles'] || fatal("[#{Settings}] Settings missing 'settings'")
	guids = Hash.new
  fatal("[#{Settings}] No profiles saved") unless settings['profiles'].class == Array
	settings['profiles'].each { |profile|
    next if profile.class == Array
		next unless profile['guid'] && profile['name']
		guids[profile['name']] = profile['guid']
	}
	[settings,guids]
end

##################################################
# Usage
##################################################
def fatal(*msg)
	msg.each { |m| $stderr.puts "[#{$0.sub(/.*\//,'')}] ERROR: #{m}" }
	exit(-1);
end

def usage(*msg)
	msg.each { |m| $stderr.puts "ERROR: #{m}" }
	$stderr.puts <<-USAGE

Usage:  #{$0.sub(/.*\//,'')} [-d] <profile>
  Run windows terminal with a specified profile
  -d      Set debug mode
  -list   Just list profiles

	USAGE
	exit -1;
end

def parseArgs
	opt = Hash.new
	loop {
		if (arg=ARGV.shift)==nil then break
		elsif arg == '-h' then usage
		elsif arg == '-?' then usage
		elsif arg == '-d' then opt[:d] = true
		elsif arg == '-list' then opt[:list] = true
		elsif arg =~ /^-geom(etry)?$/ then
			geom = ARGV.shift
			usage("-geometry must be of the form <width>x<height>") unless geom.match(/^(\d+)x(\d+)$/)
			opt[:width]=$1.to_i
			opt[:height]=$2.to_i
		elsif arg =~ /^-/ then usage("Unknown arg [#{arg}]")
		else opt[:profile] = arg
		end
	}

	usage("No profile specified") unless opt[:profile] or opt[:list]
	
	opt
end

def set(settings,name,val)
	settings[name] = val if settings[name]
	## globals is deprecated and broken:  
	## https://github.com/microsoft/terminal/issues/5458
	#return unless settings['globals']
	#return settings['globals'][name] = val if settings['globals'][name]
	settings[name] = val
end

##################################################
# Main code
##################################################
def main
	opt = parseArgs

	settings,guids = readSettings
	return guids.keys.each { |guid| puts guid } if opt[:list]
	guid = guids[opt[:profile]]
	fatal("Unknown profile [#{opt[:profile]}]") unless guid
	puts "Profile: #{opt[:profile]}\nGuid:    #{guid}" if opt[:d]

	set(settings,'defaultProfile',guid)
	set(settings,'initialCols',opt[:width]) if opt[:width]
	set(settings,'initialRows',opt[:height]) if opt[:height]

	bak = Settings+'.'+Process.pid.to_s
	File.rename(Settings,bak)
	File.open(Settings,'w') { |fh|
		fh.puts JSON.pretty_generate(settings)
	}
	system(Explorer,Terminal)
	# Race condition here - need to make sure the terminal gets a chance
	# to read it before we change it back, but if we sit on it too long
	# and we try to start up another terminal, then we're in trouble.
	sleep 0.5
	File.rename(bak,Settings)
end
main
