#!/usr/bin/env ruby
#Encoding: UTF-8
VERSION = 1.1

%w(io/console net/http fileutils).each(&method(:require))
PATH = File.join(File.dirname(__FILE__), 'cowspeak')
STDOUT.sync = true

class String
	@@colours = [[154, 184, 208, 203, 198, 164, 129, 92], [63, 33, 39, 44, 49, 83, 118], [40,41,42,43,211, 210, 209, 208]].tap { |itself| itself.concat(itself.map(&:reverse)) }

	define_method(:colourize) do |final = ''|
		colour = @@colours.sample
		colour_size = colour.size - 1
		index, div, val = 0, length / colour_size, ''
		div = 1 if div == 0
		colour_size -= 1

		each_char.with_index do |c, i|
			index += 1 if (i % div == 0 && index < colour_size) && i > 1
			val.concat("\e[38;5;#{colour[index]}m#{c}")
		end

		val + "\e[0m" + final
	end
end

In = Class.new do
	define_singleton_method(:gets) do |*arg|
		IO.new(STDOUT.fileno).tap { |x| x.write(*arg.map { |x| String === x ? x.colourize : x.to_s.colourize }.join("\n") ) }.close
		STDIN.gets.strip.downcase
	end
end

define_method(:detect_os) do
	begin
		STDOUT.puts("Attempting to detect the current operating system".colourize)
		STDOUT.puts "Detected #{IO.readlines('/etc/os-release').select { |i| i.start_with?('NAME') }[-1].to_s.split('=')[1].strip.undump} #{RUBY_PLATFORM}".colourize
		true
	rescue Exception
		STDOUT.puts "Can't determine the OS".colourize
	end
end

def help
	message = if system("sh -c 'type -p dpkg > /dev/null'")
		"\nTips: If you are using debian / debian based system, you can install the deb file: "\
			'https://github.com/Souravgoswami/cowspeak-deb'
		else ''
	end

	opts = "--help / -h       Shows this help and exit. * --install / -i    Installs cowspeak. *
			--licence / -l    Shows the licence. * --uninstall / -u  Uninstalls cowspeak."
				.split(?*).map { |x| "\t#{File.basename($0)} #{x.strip}" }.join(?\n)

	STDOUT.puts <<~EOF.each_line.map(&:colourize).join
		Cowspeak speaks a quote on your terminal.
		It is customizable. It can also show you useful system information.
		This is cowspeak installer #{VERSION}#{message}

		Usage:
		#{opts}
	EOF
end

def install
	throw :WriteError if !File.writable?(PATH) && File.exist?(PATH)
	STDOUT.puts("Downloading file from https://raw.githubusercontent.com/Souravgoswami/cowspeak-deb/master/cowspeak/usr/bin/cowspeak. Press Enter to Confirm.".colourize)
	return nil unless STDIN.getch == ?\r

	loop do
		if File.directory?(PATH)
			STDOUT.puts("Looks like #{PATH} is a directory. Press Enter to remove the #{PATH} directory before proceeding...")
			return nil unless STDIN.getch == ?\r
			FileUtils.rm_rf(PATH)
		else break
		end
	end

	anim, str = %W(\xE2\xA0\x82 \xE2\xA0\x92 \xE2\xA0\xB2 \xE2\xA0\xB6), 'Please Wait'
	t = Thread.new { loop while str.size.times { |i| print(" \e[2K#{anim.rotate![0]} #{str[0...i]}#{str[i].swapcase}#{str[i.next..-1]}#{?..*((i += 1) % 4)}\r") || sleep(0.15) } }

	data = Net::HTTP.get(URI('https://raw.githubusercontent.com/Souravgoswami/cowspeak-deb/master/cowspeak/usr/bin/cowspeak'))
	t.kill

	File.write(PATH, data)
	STDOUT.puts("Downloaded #{File.basename(PATH)} to #{File.dirname(PATH)}".colourize("\n\n"))

	STDOUT.puts("Attempting to change the permission of /usr/bin/cowspeak to 755. Press Enter to Confirm.".colourize)
	return nil unless STDIN.getch == ?\r
	File.chmod(0755, PATH)
	STDOUT.puts("Changed permission to 755".colourize("\n\n"))

	STDOUT.puts("Attempting to change the owner and group of #{PATH} to root. Press Enter to Confrim.".colourize)
	return nil unless STDIN.getch == ?\r
	File.chown(0, 0, PATH)
	STDOUT.puts("Changed the owner and group to root".colourize("\n\n"))

	STDOUT.puts("Attempting to move #{PATH} to /usr/bin/ directory. Press Enter to Confirm.".colourize)
	return nil unless STDIN.getch == ?\r
	FileUtils.mv(PATH, '/usr/bin/')
	STDOUT.puts("\e[38;5;10mMoved #{PATH} to /usr/bin/\e[0m\n\n")

	STDOUT.puts("All Done!! Just run /usr/bin/cowspeak -dl to Download the data files to /usr/share/cowspeak".colourize)
end

def uninstall
	exit if In.gets(':: Do you want to remove cowspeak? (Y/n): ') == ?n
	STDOUT.puts(':: If you find any bug or for feature request go to https://github.com/Souravgoswami/cowspeak-deb/issues/new'.colourize)

	%w(/usr/bin/cowspeak /usr/share/man/man1/cowspeak.1.gz /usr/share/cowspeak/).select do |x|
		File.exist?(x).tap { |y| STDOUT.puts y ? ":: Found: #{x.dump}" : ":: Not Found: #{x.dump}" }
	end.each do |f|
		if File.directory?(f)
			return nil unless In.gets(":: Will Remove\n#{Dir.glob("#{f}/**/**").join("\n")}\nPress Enter to confirm: ").empty?
			FileUtils.rm_r(f)
			STDERR.puts("Deleted #{f}".colourize)
		elsif File.file?(f)
			return nil unless In.gets(":: Attempting to remove #{f}. Press Enter to confirm: ").empty?
			File.delete(f)
			STDERR.puts("Removed #{f}".colourize)
		end
	end.empty?.tap { |x| STDOUT.puts "Cowspeak is not installed. Nothing to do. Run `#{$PROGRAM_NAME} --install` to install cowspeak".colourize if x }
end

if ARGV.any? { |x| x =~ /\A-(-\binstall\b|\bi\b)/ }
	begin
		detect_os && install
	rescue UncaughtThrowError
		STDOUT.puts("Can't open cowspeak for write!!".colourize)
	rescue SocketError
		STDOUT.puts("An active internet connection is required to download the source code. May be you don't have an internet connection?".colourize)
	rescue OpenSSL::SSL::SSLError
		STDOUT.puts("An active internet connection is required to download the source code. There may be an internet issue?".colourize)
	rescue Errno::EACCES
		STDOUT.puts("Cannot move #{PATH} to /usr/bin/cowspeak - Access Denied. Please try this running as root?".colourize)
		STDOUT.puts("The downloaded source file is #{PATH}".colourize)
	rescue Errno::EPERM
		STDOUT.puts("Cannot change ownership and group of #{PATH} to root - Access Denied. Please try this running as root?".colourize)
		STDOUT.puts("The downloaded source file is #{PATH}".colourize)
	rescue Errno::ENOTTY
		STDOUT.puts("No TTY found for inputs. Please try running #{File.basename(__FILE__)} in a terminal".colourize)
	rescue SignalException, Interrupt, SystemExit
		STDOUT.puts
	rescue Exception => e
		Kernel.warn("An Exception Caught:\n#{e.to_s.each_line.map { |err| "\t" << err }.join }\n".colourize + ?*.*((e.to_s.length + 8)).colourize)
		Kernel.warn("Error in:\n#{e.backtrace.map { |err| "\t#{err}\n" }.join}".colourize)
	end

elsif ARGV.any? { |x| x =~ /\A-(-\buninstall\b|\bu\b)/ }
	begin
		detect_os && uninstall
	rescue Errno::EACCES
		STDOUT.puts('Cannot remove cowspeak. Permission Denied.'.colourize)
		STDOUT.puts('Try running this as root'.colourize)
	rescue SignalException, Interrupt, SystemExit
		STDOUT.puts
	rescue Exception => e
		Kernel.warn("An Exception Caught:\n#{e.to_s.each_line.map { |err| "\t#{err}" }.join }\n".colourize + ?*.*(e.to_s.length.+(8)).colourize)
		Kernel.warn "Error in:\n#{e.backtrace.map { |err| "\t#{err}\n" }.join }".colourize
	end

elsif ARGV.any? { |x| x =~ /\A-(-\blicence\b|\bl\b)/ }
	d, i, chars = false, 0, %w(| / - \\)
	Thread.new { STDOUT.print("\e[2K#{chars[(i += 1) % chars.size].colourize} #{'Downloading licence! Please wait...'.colourize}\r") || sleep(0.1) until d }

	begin
		puts Net::HTTP.get(URI('https://raw.githubusercontent.com/Souravgoswami/cowspeak/master/LICENSE')).each_line.map(&:colourize).join
	rescue Exception
		STDERR.puts "Unable to Download the licence. Perhaps try again?".colourize
	ensure
		d = true
	end

else
	help
end