#!/usr/bin/ruby
#
# puavo-autopilot-session-stress - simulate desktop usage and do crazy things
#
# Copyright (C) 2015 Opinsys Oy
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
# Street, Fifth Floor, Boston, MA 02110-1301 USA.

#
# Simulates system use by starting some programs and doing crazy things.
# Takes no command line arguments, but can (and must) be configured with
# tags from Puavo.
# See README for more information.

require 'getoptlong'
require 'json'

# actions

def click_mouse
  system('xte', 'mouseclick 1')
end

def enough_memory?
  IO.readlines('/proc/meminfo').each do |line|
    field, value, units = * line.split
    if field == 'MemAvailable:' && units == 'kB' then
      available_memory = value.to_i
      puts ">>>>> calculated avilable memory to #{ available_memory }"
      if available_memory >= 524288 then
        return true
      else
        return false
      end
    end
  end

  raise 'Did not find the amount of available memory'
end

def run_if_enough_memory(*cmd)
  begin
    if enough_memory? then
      system(*cmd)
    else
      puts "Not enough available memory for running #{ cmd }"
    end
  rescue StandardError => e
    warn "Could not look up available memory: #{ e.message }"
  end
end

def firefox(page)
  run_if_enough_memory('firefox', '-new-window', page)
end

def kill_current_window
  system('xte', 'keydown Alt_L', 'key F4', 'keyup Alt_L')
  press_enter()
end

def kill_kill_kill
  16.times do
    move_mouse_somewhere()
    click_mouse()
    kill_current_window()
    press_enter()
  end
end

def logout
  system('gnome-session-quit', '--force', '--no-prompt', '--logout')
end

def reboot
  system('gnome-session-quit', '--reboot')
  sleep(1)
  press_enter()
end

def move_mouse(x_dist, y_dist)
  x = (x_dist / 20.0).to_i
  y = (y_dist / 20.0).to_i
  r = 0.0

  while r <= 1 do
    system('xte', "mousermove #{ x } #{ y }")
    sleep(0.02)
    r += 0.05
  end
end

def move_mouse_somewhere
  x = (rand() * 800).to_i - 400
  y = (rand() * 600).to_i - 300
  move_mouse(x, y)
end

def press_enter
  system('xte', 'key Return')
end

def write_line(line)
  system('xte',
         * line.chomp.split('').map { |s| "key #{ s }" },
         'key Return')
end

def get_random_command_string(sum, commands_with_cumulative_probability)
  random_number = rand() * sum
  commands_with_cumulative_probability.reverse.each do |cmdinfo|
    if random_number >= cmdinfo[0]
      return cmdinfo[1]
    end
  end

  raise 'Internal error on get_random_command'
end

reboot_likelihood = 0.0
slowness_factor = 5.0

getopts =
  GetoptLong.new(
    [ '--reboot-likelihood', GetoptLong::REQUIRED_ARGUMENT ],
    [ '--slower-by',         GetoptLong::REQUIRED_ARGUMENT ])

getopts.each do |opt, arg|
  case opt
  when '--reboot-likelihood'
    reboot_likelihood = arg.to_f
  when '--slower-by'
    slowness_factor = arg.to_f
  end
end

while true do
  spacechar = ' '
  loadavg = IO.read('/proc/loadavg').split(spacechar).first.to_f

  commands = [
              [ 60, %q{ move_mouse_somewhere()                                }, ],
              [ 20, %q{ click_mouse()                                         }, ],
              [ 20, %q{ press_enter()                                         }, ],
              [ 30, %q{ write_line('humppaa')                                 }, ],

              [ 6,  %q{ firefox('http://areena.yle.fi/')                      }, ],
              [ 6,  %q{ firefox('http://www.amazon.com/')                     }, ],
              [ 6,  %q{ firefox('http://www.apple.com/')                      }, ],
              [ 6,  %q{ firefox('http://www.bing.com/')                       }, ],
              [ 15, %q{ firefox('http://www.facebook.com/')                   }, ],
              [ 6,  %q{ firefox('http://www.google.com/')                     }, ],
              [ 3,  %q{ firefox('http://www.redhat.com/')                     }, ],
              [ 3,  %q{ firefox('http://www.ubuntu.com/')                     }, ],
              [ 6,  %q{ firefox('http://www.yahoo.com/')                      }, ],
              [ 9,  %q{ firefox('http://www.youtube.com/')                    }, ],
              [ 3,  %q{ firefox('http://www.youtube.com/watch?v=mahBZ4lSZHQ') }, ],
              [ 3,  %q{ firefox('http://www.youtube.com/watch?v=S1Lz8b3w618') }, ],

              [ 3,  %q{ run_if_enough_memory('gimp')                          }, ],
              [ 3,  %q{ run_if_enough_memory('khangman')                      }, ],

              [ 3,  %q{ run_if_enough_memory('libreoffice', '--base'   )      }, ],
              [ 2,  %q{ run_if_enough_memory('libreoffice', '--calc'   )      }, ],
              [ 2,  %q{ run_if_enough_memory('libreoffice', '--draw'   )      }, ],
              [ 2,  %q{ run_if_enough_memory('libreoffice', '--impress')      }, ],

              [ 4 * (loadavg.to_i + 1), %q{ kill_current_window()             }, ],
              [ 1 * (loadavg.to_i + 1), %q{ kill_kill_kill()                  }, ],
              [ 1 * (loadavg.to_i + 1), %q{ logout()                          }, ],

              # if we are low on memory, make it more likely for us to start
              # killing things
              [ (enough_memory? ? 0 : 20), %q{ kill_kill_kill()               }, ],

              [ reboot_likelihood, %q{ reboot()                               }, ],
             ]

  commands_with_cumulative_probability = []
  sum = 0
  commands.each do |cmdinfo|
    commands_with_cumulative_probability << [ sum, cmdinfo[1] ]
    sum += cmdinfo[0]
  end

  cmd_string = get_random_command_string(sum,
                                         commands_with_cumulative_probability)
  puts "puavo-autopilot-session is going to run #{ cmd_string.strip }"

  job = fork { eval(cmd_string) }
  Process.detach(job)

  # sleep a bit before doing more....
  # also slow down when system load rises (as users would do anyway)
  sleep(1  + slowness_factor * Math.log(1 + loadavg) * rand())
end
