package Rex::Hardware::VirtInfo;

use strict;
use warnings;

use Rex;
use Rex::Commands::Run;
use Rex::Helper::Run;
use Rex::Commands::Fs;
use Rex::Commands::File;
use Rex::Logger;

use Rex::Inventory::Bios;

require Rex::Hardware;

sub get {

  my $cache = Rex::get_cache();
  my $cache_key_name = $cache->gen_key_name("hardware.virt_info");

  if($cache->valid($cache_key_name)) {
    return $cache->get($cache_key_name);
  }

  if(Rex::is_ssh || $^O !~ m/^MSWin/i) {

    my ($product_name,$bios_vendor,$sys_vendor,$self_status,$cpuinfo,$modules) = ('','','','','','');

    $product_name = i_run "cat /sys/devices/virtual/dmi/id/product_name 2>/dev/null";
    $bios_vendor  = i_run "cat /sys/devices/virtual/dmi/id/bios_vendor 2>/dev/null";
    $sys_vendor  = i_run "cat /sys/devices/virtual/dmi/id/sys_vendor 2>/dev/null";

    $self_status  = i_run "cat /proc/self/status 2>/dev/null";
    $cpuinfo    = i_run "cat /proc/cpuinfo 2>/dev/null";
    $modules    = i_run "cat /proc/modules 2>/dev/null";

    my ($virtualization_type, $virtualization_role) = ('','');

    if (is_dir("/proc/xen")) {
      $virtualization_type = "xen";
      $virtualization_role = "guest";

      my $string = i_run "cat /proc/xen/capabilities 2>/dev/null";
      if ($string =~ /control_d/){
        $virtualization_role = "host";
      }
    }

    elsif (is_dir("/proc/vz")) {
      $virtualization_type = "openvz";
      $virtualization_role = "guest";

      if (is_dir("/proc/bc")) {
        $virtualization_role = "host";
      }
    }

    elsif ($product_name =~ /KVM|Bochs/) {
      $virtualization_type = "kvm";
      $virtualization_role = "guest";
    }

    elsif ($product_name =~ /VMware Virtual Platform/) {
      $virtualization_type = "vmware";
      $virtualization_role = "guest";
    }

    elsif ($bios_vendor =~ /Xen/) {
      $virtualization_type = "xen";
      $virtualization_role = "guest";
    }

    elsif ($bios_vendor =~ /innotek GmbH/) {
      $virtualization_type = "virtualbox";
      $virtualization_role = "guest";
    }

    elsif ($sys_vendor =~ /Microsoft Corporation/) {
      $virtualization_type = "VirtualPC";
      $virtualization_role = "guest";
    }

    elsif ($sys_vendor =~ /Parallels Software International Inc/) {
      $virtualization_type = "parallels";
      $virtualization_role = "guest";
    }

    elsif ($self_status =~ /VxID: \d+/) {
      $virtualization_type = "linux_vserver";
      $virtualization_role = "guest";

      if ($self_status =~ /VxID: 0/) {
        $virtualization_role = "host";
      }
    }

    elsif ($cpuinfo =~ /model name.*QEMU Virtual CPU/) {
      $virtualization_type = "kvm";
      $virtualization_role = "guest";
    }

    elsif ($cpuinfo =~ /vendor_id.*User Mode Linux|model name.*UML/) {
      $virtualization_type = "uml";
      $virtualization_role = "guest";
    }

    elsif ($cpuinfo =~ /vendor_id.*PowerVM Lx86/) {
      $virtualization_type = "powervm_lx86";
      $virtualization_role = "guest";
    }

    elsif ($cpuinfo =~ /vendor_id.*IBM\/S390/) {
      $virtualization_type = "ibm_systemz";
      $virtualization_role = "guest";
    }

    elsif ($modules =~ /kvm/) {
      $virtualization_type = "kvm";
      $virtualization_role = "host";
    }

    elsif ($modules =~ /vboxdrv/) {
      $virtualization_type = "virtualbox";
      $virtualization_role = "host";
    }

    my $data = {
      virtualization_type => $virtualization_type,
      virtualization_role => $virtualization_role,
    };

    $cache->set($cache_key_name, $data);

    return $data;

  }
}
