class Weather
  def self.get_weather(zone, hash = hash(get_seed))
    total = 0
    APP_DATA[zone][:weather].each do |arr|
      name, rate = arr
      if (total += rate) > hash
        return name
      end
    end
  end

  def self.forecast(zone, seed = get_seed, count = 50)
    res = []
    prev_hash = hash(seed - 1)
    prev_weather = get_weather(zone, prev_hash)
    count.times do |_|
      curr_hash = hash(seed)
      curr_weather = get_weather(zone, curr_hash)
      res.push({ zone: zone, prev_weather: prev_weather, curr_weather: curr_weather, weather_name: get_weather_name(curr_weather), seed: seed, time: Time.at(seed * 1400000.0 / 1000) })
      prev_hash = curr_hash
      prev_weather = curr_weather
      seed += 1
    end
    res
  end

  def self.round_to_last_weather_time(time)
    last_hour = time.hour / 8 * 8
    time.change(hour: last_hour)
  end

  def self.get_weather_name(name)
    case name
    when "fair" then "Fair Skies"
    when "showers" then "Showers"
    when "gales" then "Gales"
    when "blizzards" then "Blizzards"
    when "heat" then "Heat"
    when "thunder" then "Thunderstorms"
    when "gloom" then "Gloom"
    when "snow" then "Snow"
    when "fog" then "Fog"
    when "umbral_wind" then "Umbral Wind"
    else "Unknown Weather"
    end
  end


  def self.get_seed
    (Time.now.utc.to_i * 1000 / 1400000.0).floor
  end

  def self.hash(seed = get_seed)
    base = (seed / 3).floor * 100 + ((seed + 1) % 3) * 8
    # Ruby has no other convenient way to convert a signed integer into an unsigned one
    step1 = [ ((base << 11) ^ base) ].pack("L").unpack("L").first
    step2 = [ (([ (step1 >> 8) ].pack("L").unpack("L").first.to_i ^ step1)) ].pack("L").unpack("L").first.to_i
    step2 % 100
  end

  def self.unsigned_right(input, by)
    input << by & 0xFF00 | input >> by & 0xFF
  end
end