# Container class for helper methods. class USPSFlags::Helpers class << self # Valid options for flag generation. # # @param [Symbol] type Specify subset of flags. # @option type [Symbol] :all All flags # @option type [Symbol] :officer Officer flags # @option type [Symbol] :insignia Insignia-eligible officer flags (no past officers) # @option type [Symbol] :squadron Squadron-level officer flags # @option type [Symbol] :district District-level officer flags # @option type [Symbol] :national National-level officer flags # @option type [Symbol] :special Special flags # @option type [Symbol] :us US flag # @return [Array] Valid options for flag generation (based on the provided type). def valid_flags(type = :all) squadron_past = %w[PLTC PC] squadron_elected = %w[1LT LTC CDR] squadron_swallowtail = %w[PORTCAP FLEETCAP LT FLT] district_past = %w[PDLTC PDC] district_elected = %w[D1LT DLTC DC] district_swallowtail = %w[DLT DAIDE DFLT] national_past = %w[PSTFC PRC PVC PCC] national_elected = %w[NAIDE NFLT STFC RC VC CC] special = %w[CRUISE OIC ENSIGN WHEEL] us = %w[US] squadron = squadron_past + squadron_elected + squadron_swallowtail district = district_past + district_elected + district_swallowtail national = national_past + national_elected past = squadron_past + district_past + national_past case type when :all squadron + district + national + special + us when :officer squadron + district + national when :insignia squadron + district + national - past when :squadron squadron when :district district when :national national when :special special when :us us when :past past when :swallowtail past + squadron_swallowtail + district_swallowtail when :bridge squadron_elected.last(2) + squadron_past.last(2) + district_elected.last(2) + district_past.last(2) + national_elected.last(2) + national_past.last(2) when :command [squadron_elected.last, squadron_past.last, district_elected.last, district_past.last, national_elected.last, national_past.last] end end # Gets the generation details for the given rank. # # This is used USPSFlags::Generate, and should never need to be called directly. # @private def flag_details(rank) { style: flag_style(rank), color: flag_color(rank), type: flag_type(rank), level: flag_level(rank), count: flag_count(rank) } end # Displays an overlay grid with regularly spaced locator markers. # # This is useful for adjusting or creating new SVG data generators, but should not otherwise need to be called. # @private def grid(width: USPSFlags::Config::BASE_FLY, height: USPSFlags::Config::BASE_HOIST) <<~SVG SVG end # Displays an overlay indicator of concentric circles and radiating lines. # # This is useful for adjusting or creating new SVG data generators, but should not otherwise need to be called. # @private def locator <<~SVG SVG end # Creates a vertical arrow for the trident spec sheet. # # This is used USPSFlags::Core.trident_spec, and should never need to be called directly. # @private def v_arrow(x, top, bottom, pointer_top = nil, pointer_bottom = nil, label: nil, label_offset: (USPSFlags::Config::BASE_FLY/120), label_offset_y: 0, label_align: "left", color: "#CCCCCC", stroke_width: (USPSFlags::Config::BASE_FLY/600), stroke_dash: "10, 10", font_size: (USPSFlags::Config::BASE_FLY/60), arrow_size: (USPSFlags::Config::BASE_FLY/120), fly: USPSFlags::Config::BASE_FLY, unit: nil) label = bottom - top if label.nil? label = label.to_i if label - label.to_i == 0 label = Rational(label) * fly / USPSFlags::Config::BASE_FLY if label == label.to_i label = label.to_i label_fraction = "" else label, label_fraction = label.to_simplified_a end svg = "" unless pointer_top.nil? svg << <<~SVG SVG end unless pointer_bottom.nil? svg << <<~SVG SVG end svg << <<~SVG #{label} #{label_fraction} #{unit} SVG svg end # Creates a horizontal arrow for the trident spec sheet. # # This is used USPSFlags::Core.trident_spec, and should never need to be called directly. # @private def h_arrow(y, left, right, pointer_left = nil, pointer_right = nil, label: nil, label_offset: (USPSFlags::Config::BASE_FLY/45), label_offset_x: 0, label_align: "middle", color: "#CCCCCC", stroke_width: (USPSFlags::Config::BASE_FLY/600), stroke_dash: "10, 10", font_size: (USPSFlags::Config::BASE_FLY/60), arrow_size: (USPSFlags::Config::BASE_FLY/120), fly: USPSFlags::Config::BASE_FLY, unit: nil) label = right - left if label.nil? label = label.to_i if label - label.to_i == 0 label = Rational(label) * fly / USPSFlags::Config::BASE_FLY if label == label.to_i label = label.to_i label_fraction = "" else label, label_fraction = label.to_simplified_a end svg = "" unless pointer_left.nil? svg << <<~SVG SVG end unless pointer_right.nil? svg << <<~SVG SVG end svg << <<~SVG #{label} #{label_fraction} #{unit} SVG svg end # Resizes and saves a PNG image. # # This is used USPSFlags::Generate, and should never need to be called directly. # @private def resize_png(png_ins_file, flag:, size:, size_key:) MiniMagick::Tool::Convert.new do |convert| convert << "-background" << "none" convert << "-format" << "png" convert << "-resize" << "#{size}" convert << png_ins_file convert << "#{USPSFlags::Config.flags_dir}/PNG/insignia/#{flag}.#{size_key}.png" end end # Image sizes for generated PNG images. # # This is used USPSFlags::Generate, and should never need to be called directly. # @private def png_sizes {1500 => "H", 1000 => "K", 500 => "D", "thumb" => "T"} end # Gets size key for saving PNG images. # # This is used USPSFlags::Generate, and should never need to be called directly. # @private def size_and_key(size:, flag:) return [size, size] unless size == "thumb" size = case flag when "ENSIGN" 200 when "US" 300 else 150 end [size, "thumb"] end # Prints message(s) to the console and logs them. # # This should never need to be called directly. # @private def log(*messages) ::FileUtils.mkdir_p(USPSFlags::Config.log_path) outputs = [STDOUT] begin log_file = File.open("#{USPSFlags::Config.log_path}/flag.log", 'a') outputs << log_file rescue Errno::EACCES => e puts "\nError accessing log file." unless USPSFlags::Config.log_fail_quietly end messages.each do |message| outputs.each { |f| f.write(message) } end messages ensure log_file.close if log_file.is_a?(File) end private def flag_style(rank) if valid_flags(:past).include?(rank) :past elsif valid_flags(:swallowtail).include?(rank) :swallowtail else :regular end end def flag_color(rank) if valid_flags(:command).include?(rank) count = 3 :blue elsif valid_flags(:bridge).include?(rank) count = 2 :red else :white end end def flag_level(rank) if rank == "DAIDE" :d elsif rank == "NAIDE" :n elsif rank == "FLT" :s elsif rank == "DFLT" :d elsif rank == "NFLT" :n else nil end end def flag_count(rank) if valid_flags(:command).include?(rank) 3 elsif valid_flags(:bridge).include?(rank) 2 else 1 end end def flag_type(rank) if valid_flags(:squadron).include?(rank) :s elsif valid_flags(:district).include?(rank) :d elsif rank == "STFC" :stf elsif valid_flags(:national).include?(rank) :n elsif rank == "PORTCAP" :pc elsif rank == "FLEETCAP" :fc elsif rank == "DAIDE" :a elsif rank == "NAIDE" :a elsif rank == "FLT" :f elsif rank == "DFLT" :f elsif rank == "NFLT" :f end end end end