#
# (c) Jan Gehring <jan.gehring@gmail.com>
# 
# vim: set ts=3 sw=3 tw=0:
# vim: set expandtab:
   
package Rex::Inventory::SMBios;
   
use strict;
use warnings;


use Data::Dumper;
use Rex::Logger;
use Rex::Commands::Run;

use Rex::Inventory::SMBios::BaseBoard;
use Rex::Inventory::SMBios::Bios;
use Rex::Inventory::SMBios::CPU;
use Rex::Inventory::SMBios::Memory;
use Rex::Inventory::SMBios::MemoryArray;
use Rex::Inventory::SMBios::SystemInformation;

sub new {
   my $that = shift;
   my $proto = ref($that) || $that;
   my $self = { @_ };

   bless($self, $proto);

   $self->_read_smbios();

   return $self;
}

sub get_tree {
   my ($self, $section) = @_;

   if($section) {
      return $self->{"__dmi"}->{$section};
   }
   
   return $self->{"__dmi"};
}

sub get_base_board {
   my ($self) = @_;
   return Rex::Inventory::SMBios::BaseBoard->new(dmi => $self);
}

sub get_bios {
   my ($self) = @_;
   return Rex::Inventory::SMBios::Bios->new(dmi => $self);
}

sub get_system_information {
   my ($self) = @_;
   return Rex::Inventory::SMBios::SystemInformation->new(dmi => $self);
}


sub get_cpus {

   my ($self) = @_;
   my @cpus = ();
   my $tree = $self->get_tree("processor");
   my $idx=0;
   for my $cpu ( @{ $tree } ) {
      if($cpu->{"Socket Status"} =~m/Populated/) {
         push(@cpus, Rex::Inventory::SMBios::CPU->new(dmi => $self, index => $idx));
      }
      ++$idx;
   }

   return @cpus;

}

sub get_memory_modules {

   my ($self) = @_;
   my @mems = ();
   my $tree = $self->get_tree("memory device");
   my $idx = 0;
   for my $mem (@{ $tree }) {
      if($mem->{"Size"} =~ m/\d+/) {
         push(@mems, Rex::Inventory::SMBios::Memory->new(dmi => $self, index => $idx));
      }
      ++$idx;
   }

   return @mems;

}

sub get_memory_arrays {

   my ($self) = @_;
   my @mems = ();
   my $tree = $self->get_tree("physical memory array");
   my $idx = 0;
   for my $mema (@{ $tree }) {
      push(@mems, Rex::Inventory::SMBios::MemoryArray->new(dmi => $self, index => $idx));
      ++$idx;
   }

   return @mems;

}


sub _read_smbios {
   my ($self) = @_;

   my @data = run("smbios");

   my ($current_section, %section, $key, $val, %cur_data);
   for my $line (@data) {
      next if($line =~ /^$/);
      next if($line =~ /^\s*$/);
      next if($line =~ /^ID/);

      if($line =~ m/^\d/) {
         push(@{$section{$current_section}}, { %cur_data }) if (%cur_data);

         ($current_section) = ($line =~ m/\(([^\)]+)\)/);
         
         if(! exists $section{$current_section}) {
            $section{$current_section} = [];
         }

         %cur_data = ();
         next;
      }

      # outer section
      if($line =~ /^\s\s[a-z]/i) {
         $line =~ s/^\s*//;
         ($key, $val) = split(/: /, $line);
         $cur_data{$key} = $val;
      }
      elsif($line =~ /^\t[a-z]/i) {
         if(! ref($cur_data{$key})) {
            $cur_data{$key} = [];
         }

         $line =~ s/^\s*//;
         push(@{$cur_data{$key}}, $line);
      }

   }

   # push the last
   push(@{$section{$current_section}}, { %cur_data });


   $self->{"__dmi"} = \%section;
}

1;
