require_relative "string.rb"
require_relative "query.rb"

class Check

  @params
  def params; @params end
  def params=(p); @params=p end

  def execute!
    begin

      case params["command"]
      when "tcp"
        return check_tcp
      when "ping"
        return check_ping
      when "http"
        return check_http
      when "https"
        return check_http(true)
      when "mysql"
        return check_mysql
      when "sql"
        return check_query
      else
        puts "Check: #{params["sms_name"]} has an invalid command type (#{params["command"]})".bgred
        return false
      end

    rescue
      return false
    end
  end

  def check_tcp
    require "socket"
    s = TCPSocket.new params["host"], params["port"].to_i
    s.close
    return true
  end

  def check_ping
    require "net/ping"
    p = Net::Ping::External.new
    if p.ping?(params["host"], 1, 0.2, params["timeout"])
      return true
    else
      return false
    end
  end

  def check_http(use_ssl = false)
    require 'net/http'
    protocol = use_ssl ? "https" : "http"
    uri = URI("http#{use_ssl ? 's' : ''}://#{params["host"]}/#{params["path"]}")
    req = Net::HTTP::Get.new(uri)
    req.basic_auth params["username"], params["password"] if params["username"]
    res = Net::HTTP.start(uri.hostname, uri.port) {|http| http.request(req) }
    return res.is_a?(Net::HTTPSuccess)
  end

  def check_mysql
    return self.database.query("SHOW TABLES;").count > 0
  end

  def check_query

    # Prevent potentially dangerous or malformed queries
    #
    unless params["query"] =~ /\A(SELECT\s(\w+|\*|count\((\w+|\*)\))(,\s(\w+|\*|count\((\w+|\*)\)))*\sFROM\s\w+()?((\sWHERE\s\w+\s((<|<=|=|!=|=>|>)\s([0-9]+\.[0-9]+|[0-9]+)|(IS NULL|IS NOT NULL)|(=|!=)\s{1}\'[\w\s\.-]{0,64}\'))(\s(AND|OR)\s\w+\s((<|<=|=|!=|=>|>)\s([0-9]+\.[0-9]+|[0-9]+)|(IS NULL|IS NOT NULL)|(=|!=)\s{1}\'[\w\s\.-]{0,64}\'))?)?|show slave status)\;\z/i
      puts "Fatal error: unsupported SQL detected".bgred
      exit false
    end

    return Comparison.execute(self.database.query(params["query"]).first, params["comparison"])
  end

  private def self.database
    require 'mysql2'
    Mysql2::Client.new(
      :host => params["host"], 
      :port => params["port"].to_i, 
      :username => params["username"], 
      :password => params["password"], 
      :database => params["database"]
    )
  end


end
