package Logic::SWITCH;
use Logic;
use Logic::Subnet;
use Agent::BROCADE;
use Agent::3310;
use Agent::QLOGICSW;
use strict;

#  host => , ip => , name => , 
#  return ($err_object, $nodes_list);
#  $q->{host} = ''         : local
#  $q->{host} = <hostname> : slave

sub addToConfig {
  my ($class, $q) = @_;
  my ($err, $nodes);

  while (1) {
     if ($q->{name} eq "") {
        $err = Error->error(102);
        last;
     } elsif (!$q->{ip}) {
        $err = Error->error("103");
        last;
     } else {
        my($renv, $devs, $hosts,$notifs) = PDM::ConfigFile->read();
        my(%F);
        foreach my $d (@$devs) {
          if ($d->{class} =~ /^switch/ ) {
             $F{$d->{wwn}} = 1;
          }
        }
        ($err, $nodes) = $class->add($q, $devs, \%F);
        if (!$err && $nodes) {

           Logic->clearSlave($q->{host}, $hosts);
           if (!PDM::ConfigFile->write( $renv, $devs, $hosts,$notifs)) {
              $err = Error->error('10');
           }
        }
     }
     last;
  }
  return ($err, $nodes);
}

#-------------------------------------------------
# FUNCTION: addFromFile()
# called by ras_admin discover_deviceIP 
# /etc/deviceIP.conf
# $q = 
# { monitor_on => 1
#   fileToUse => "asdasd",
#   prefix    => "name_prefix",
# }
#-------------------------------------------------

sub addFromFile {

   my($class, $q) = @_;

   my(@nodes,$err, $err_text, $x);
   my $host       = $q->{host};
   my $datahost   = $q->{datahost};
   my $silent     = $q->{silent};
   $q->{prefix} =~ s/\./_/g;

   my(@DATA, %F, $total, $found);
   my($renv, $devs, $hosts,$notifs, $Config) = PDM::ConfigFile->read();
   my $new_dev = $#$devs ;
   $DB::single = 1;

   my $cnt=1;
   foreach my $d (@$devs) {
     $F{$d->{key}} = $d;
   }
   $q->{LOCAL} = 1;
   my $err_text;

   my $dd =  &get_infoFromFile($q);

   foreach my $line (@$dd) {
     my $nodes0 = Discover->addDevice( $Config, $q, $line, \%F, \$err_text);
     push(@nodes, @$nodes0);
   }
   if ($#nodes >= 0) {
      PDM::ConfigFile->write( $renv, $devs, $hosts,$notifs);
   }
   return ($err, \@nodes, $err_text);
}



use Discover;
use DiscoveryObject;

# called by ras_admin

sub get_infoFromFile {
   my($q, $post, $util) = @_;
   my(%T, @a, $loc, $ip, $out);
   my(%F, $d, $adding, $found, $l );
   my(@NEW, %IP);
   my($xx, $sub, $remote, $x);
   my(@L, $file);
   my $all_devices = $q->{all_devices};
   $DB::single = 1;

   $remote   = $q->{REM};

   my($renv, $devices, $hosts, $notifs) = PDM::ConfigFile->read();

   foreach my $dev (@$devices) {
      next if (!Util->isMineToMonitor($dev));
      foreach my $i ('ipno','altipno') {
        my ($baseip, $extension) = split(/:/,$dev->{$i});
        $IP{$baseip} = 1;
      }
   }
   my $host = $renv->{hostname} if (Util->findMaster());

   $file = $q->{fileToUse} || "/etc/deviceIP.conf";

   open(OO, $file);
   my ($adding, @nodes, $info);
   use Data::Dumper;
   $Data::Dumper::Indent = 0;

   while ($l = <OO>) {
        chomp($l);
        next if (substr($l,0,1) eq "#");
        my ($disco_list, $name, $ip, $type);
        if ($l =~ /^HBA/) {
          my $disco_list = Discover::HBAApi->discoverInBand();
        } else {
          $l =~ s/^\s*//; # remove any beginning spaces
          next if ($l !~ /^\d+/);
          ($ip, $name, $type) = split(/\s+/, $l);
          print "Reading $l\n" if ($q->{LOCAL} && $q->{TEXT});
          Debug->print1("Reading deviceIP: $l");
          if ($IP{$ip} && !$all_devices) {
            Debug->print1("  ->device $ip/$name already in configuration");

            push(@L, Dumper(
                    DiscoveryObject->error($ip, "device already in config")));
            next;
          }
          $type = undef if (substr($type,0,1) eq "#");
          $disco_list = Discover->fromIP($ip, { type => $type });
        }
        if (!$disco_list) {
           $disco_list= [ DiscoveryObject->error($ip, "No device detected") ];
        }
        foreach my $disco_object (@$disco_list) {
          $disco_object->{monitor_on} = $q->{monitor_on};
          if ($name) {
             $disco_object->{name} = $disco_object->{username}   = $name ;
          }
          $disco_object->{prefix}     = $q->{prefix}     if ($q->{prefix});

          ##### add access mode by Charlie #########
          $disco_object->{access_mode} = $q->{access_mode} if ($q->{access_mode});


          if ($disco_object->{error}) {
            Debug->print1("  ->" . $disco_object->{error});

          } elsif ($q->{callback}) {
            Discover->logit($disco_object->serial(), $q->{callback});
          }
use Data::Dumper;
Debug->print2("  FOUND DEVICE: " . substr(Dumper($disco_object),15));
          push(@L, $disco_object);     
        }

  }
  close(OO);

  return \@L;
}



sub add {
  my($class, $q, $devs, $F) = @_;
  my (@nodes, $err);
  my($ipno, $python, $msg, $adding);
  my $host = $q->{host};
  my $ip   = $q->{ip};
  my $name = $q->{name};


  if (!($ipno = Util->testIp($ip))) {
      my $err = Error->error("switch.101", $ip);
      return ($err, []);
  }
  my($wwn, $type, $label) = $class->find_wwn($ipno, $q->{host});
  if (!$wwn) {
      my $err = Error->error("switch.102", $ipno);
      return ($err, []);
  
  } elsif (!$F->{$wwn} ) {
      $F->{$wwn} = 1;
      my($new_dev) = $#$devs  + 1;

      my $nd = PDM::ConfigFile->addDevice($devs, {
      type     => $type,
      class    => "switch.$type",
      name     => $name || "S" . $ip,
      ip       => $ip,
      telnet   => Util->encodeAll($q->{password}),
      wwn      => $wwn,
      userLabel=> $label,
      key      => $wwn,
      ipno     => $ipno,
      host     => $q->{host},
      active   => "Y",
      });

      my($renv, $devs1, $hosts1,$notifs1) = PDM::ConfigFile->read();

      $F->{$wwn} = 1;
      push(@nodes, $nd);

  } else {
      my $err = Error->error("switch.103");
      return ($err, []);
  }
  return (undef, \@nodes);  

}

sub find_wwn {
   my($class, $ip, $host) = @_;
   my($wwn, $type);
   my $renv = System->get_renv();
   my $TO = $renv->{"timeout.http"} || 30;

   if (!$host) {
      return &get_find_wwn0({ip => $ip});
   } else {
      my $rc = Util::Http->getCommand($host, "Logic::SWITCH::find_wwn0&ip=$ip&HTTP=1", $TO);
      if ($rc =~ /OK /) {
         my @report = split(/\|/, substr($rc,3));
         return @report;
      } else {
         return ();
      }
   }
}

sub get_oid {
  my($class, $ip) = @_;

   my $DIR = System->get_home();
   my $comm = "$DIR/snmp/bin/snmpwalk -r 0 -t 15 -On $ip public mib-2.1.2.0";
   my ($err,$id) = Util->run_command($comm, "getWWN", 10);
   my $oid;

   if($id->[0] =~ /sysObjectID.0 = OID: enterprises.(.+)/){
      $oid    = $1;

   } elsif ($id->[0] =~ /sysObjectID.0 = OID: storage-subsystem.(.+)/){
      #  2g 8port shows up as sysObjectID.0 = OID: storage-subsystem.3.4.1.1.4
      $oid    = "42.2.28." . $1;

   } elsif ($id->[0] =~ /sysObjectID.0 = OID: private.(.+)/){
      #  2g 8port shows up as sysObjectID.0 = OID: storage-subsystem.3.4.1.1.4
      $oid      = "private." . $1;

   } elsif ($id->[0] =~ /OID/){
     # We received a response from this device
     my($name,$val) = split(/ = OID: /, $id->[0]);
     $oid = $val;
   }
   return $oid;
}


sub get_find_wwn0 {
   my($q) = @_;

   my $ip   = $q->{ip};
   my $http = $q->{HTTP};

   my($err, $id, $comm);
   my($wwn, $type);
   
   # first try to get OID for this hardware
   my $DIR   = System->get_home();

   my $response = undef;
   my $ipno  = Util->name2ip($ip);

   my $oid   = Logic::SWITCH->get_oid($ipno);
   $response = 1 if ($oid);

   my(@return);

   while (1) {

     if ($oid) {

        if (($oid =~ /1663.1.1.1.1.12/) || # 64 port qlogic switch QLOGIC branded
         ($oid =~ /42.2.28.3.4.1.1.5/)|| # 64 port qlogic switch SUN branded
         ($oid =~ /1663.1.1.1.1.11/)  || # 2g 16 port qlogic switch QLOGIC branded
         ($oid =~ /42.2.28.3.4.1.1.3/)|| # 2g 16 port qlogic switch SUN branded
         ($oid =~ /1663.1.1.1.1.14/)  || # 2g 8 port qlogic switch QLOGIC branded
         ($oid =~ /42.2.28.3.4.1.1.4/)   # 2g 8  port qlogic switch SUN branded
          ) {
           # was 1.1.1.0
         $comm = "$DIR/snmp/bin/snmpwalk -r 0 -t 15 -m all -Os  $ip public mib-2.75.1.1.2.0";
           my $id;
           ($err,$id) = Util->run_command($comm, "getWWN", 10);
           my ($name, $wwn) = split(/ *= */, $id->[0]);
           $wwn = lc($wwn);
           $wwn =~ s/hex://; 
           $wwn =~ s/ //g;
           @return = ($wwn, 'switch2','Switch2');
           last;
        } elsif ($oid =~ /1663.1.1.1.1.17/){
          # Qlogic 5200
           $comm = "$DIR/snmp/bin/snmpwalk -r 0 -t 15 -m all -Os  $ip public mib-2.75.1.1.2.0";
           my $id;
           ($err,$id) = Util->run_command($comm, "getWWN", 10);
           my ($name, $wwn) = split(/ *= */, $id->[0]);
           $wwn = lc($wwn);
           $wwn =~ s/hex://; 
           $wwn =~ s/ //g;
           @return = ($wwn, 'qlogicsw','Qlogic5200');
           last;
        } elsif ( ($oid =~ /.1.3.6.1.4.1.289/) || ($oid =~ /^289./) ){
          # McDATA Switch
          my $wwn = Util->snmpWWN($ipno);
          @return = ($wwn, 'mcdata','mcdata');
          last;
        } elsif ( $oid =~ /private.824.1.9/){
           #Inrange switch
         $comm = "$DIR/snmp/bin/snmpwalk -r 0 -t 15 -m all -Os  $ip public mib-2.75.1.1.2.0";
           my $id;
           ($err,$id) = Util->run_command($comm, "getWWN", 10);
           my ($name, $wwn) = split(/ *= */, $id->[0]);
           $wwn = lc($wwn);
           $wwn =~ s/hex://; 
           $wwn =~ s/ //g;
           @return = ($wwn, 'inrange','inrange');
           last;
        }
     }
     
     my $com;
     ($err,$com) = Util->run_command(
           System->get_home() . "/bin/sanbox version $ip", "raidutil.txt", 10);
     "@$com" =~ /WWN:\s+(\w+)/;
     $wwn = lc($1);
  
     if ("@$com" =~ /No response/) {
        my $wwn = Agent::BROCADE->getWWN($ip); 
        my $mymodel = Agent::BROCADE->getModel($ip); 
        @return = ($wwn, 'brocade', $mymodel);
        last;
  
     } elsif("@$com" =~ /Command requires user login/) {
        # a qlogic switch with security turned on
        # Try snmp to get information
        # should be 1.1.1.0
        
        $comm = "$DIR/snmp/bin/snmpwalk -r 0 -t 5 -m all -Os  $ip public mib-2.75.1.1.2.0";
        my $id;
        ($err,$id) = Util->run_command($comm, "getWWN", 10);

        my ($name, $wwn) = split(/ *= */, $id->[0]);
        $wwn = lc($wwn);
        $wwn =~ s/hex://; 
        $wwn =~ s/ //g;
        @return = ($wwn, 'switch2','Switch2');
        last;
     
     } else {
       ($err,$com) = Util->run_command(
          System->get_home() . "/bin/sanbox get_zone $ip sl all", "raidutil.txt", 10);
       if ("@$com" !~ /Port: \d/) {
        if ($response){
             @return = ($wwn, 'switch2', 'Switch1'); last;
        } else {
           # This device didn't support snmp, so it can't be a switch
           # Not sure what this device would be(Could be inrange switch)
           @return = (undef, undef, undef); last;
        }
       }else{
          @return = ($wwn, 'switch', 'Switch1'); last;
       }
     }
     last;
  }
  if ($http) {
     print "\nOK $return[0]|$return[1]|$return[2]|$ipno";
  } else {
     return @return;
  }
}
sub find_name {
   my($class, $ip) = @_;

   
   my $comm;
   my $DIR = System->get_home();
   my $err;
   my $id;
   $comm = "$DIR/snmp/bin/snmpwalk -r 0 -t 15 -m all -Osb  $ip public sysName";
   ($err,$id) = Util->run_command($comm, "getWWN", 10);

   my $name;
   if($id->[0] =~ /sysName.0 = (.+)/){
      $name = $1;
      $name =~ s/[<>"]//g;
      return ($name);
   } 

   return undef;
}
1;
