#
# Copyright 2002-2005 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#
#ident	"@(#)Transport.pm	1.55	05/01/11 SMI"
#
# Interconnection transport class

package Cluster::Transport;
use strict;
use POSIX;
use Cluster::Node;
use Cluster::RBAC;
use Cluster::Common;
use Sun::Solaris::Utils qw(gettext);
use vars qw(@ISA $VERSION);
$VERSION = '1.00';
@ISA = qw(Cluster::Common);

# Internationalization
# func=
;# gettext("Remove")
;# gettext("Enable")
;# gettext("Disable")
# type=
;# gettext("Adapter")
;# gettext("Cable")
;# gettext("Junction")

##############################################################################
#
# Class constructor
#
##############################################################################

sub new {
    my $proto = shift;
    my $class = ref($proto) || $proto;
    my $self  = {};
    bless ($self, $class);
    return $self;
}

##############################################################################
#
# Class Variables
#
##############################################################################

# File names and location
my $PFEXEC 	   = '/usr/bin/pfexec';     # Used in execute_cmd()
my $NODEIMAGE      = '/images/node_16.gif';
my $NODEADAPTERIMAGE   = '/images/transport/node_adapt_16.gif';
my $ADAPTERIMAGE   = '/images/transport/adapter_16.gif';
my $CABLEIMAGE     = '/images/transport/cable_16.gif';
my $PATHSIMAGE     = '/images/transport/paths_16.gif';
my $JUNCTIONIMAGE  = '/images/transport/junction_16.gif';
my $VIEW           = '/cgi-bin/transport/transport_view.pl';
my $JUNCTIONVIEW   = "$VIEW?type=Junctions";
my $CONFIG         = '/cgi-bin/transport/transport_config.pl';
my $ADD            = '/cgi-bin/transport/transport_add.pl';
my $SCCONF         = '/usr/cluster/bin/scconf';
my $SCSTAT         = '/usr/cluster/bin/scstat';
my $INF            = '/etc/cluster/ccr/infrastructure';

# Instantiate cluster objects
my $node	   = new Cluster::Node;
my $rbac           = new Cluster::RBAC;
my $runcommand	   = new Cluster::RunCommand;

# Set boolean constants
use constant TRUE  => 0;
use constant FALSE => 1;

# Command output to be saved in memory
my @SCCONFPOUT;

# Frequently used lists
my @JUNCTION_LIST;
my @CABLE_LIST;

my @status_icons = (
	["Online", "Online", "ok"], # gettext("Online")
	["Offline", "Offline", "critical"], # gettext("Offline")
	["Degraded", "Degraded", "critical"], # gettext("Degraded")
	["Wait", "Wait", "minor"] # gettext("Wait")
);

my @path_status_icons = (
	["Online", "Online", "ok"], # gettext("Online")
	["Offline", "Offline", "critical"], # gettext("Offline")
	["Faulted", "Faulted", "critical"], # gettext("Faulted")
	["Waiting", "Wait", "major"] # gettext("Wait")
);

my @component_status_icons = (
	["Enabled", "Enabled", "ok"], # gettext("Enabled")
	["Disabled", "Disabled", "minor"] # gettext("Disabled")
);

my @enabled_status_icons = (
	["yes", "Yes", "ok"], # gettext("Yes")
	["no", "No", "major"] # gettext("No")
);

##############################################################################
#
# Javascripts
#
##############################################################################

#
# Return the adapter validate jscript
#

sub transport_jscript() {
;# /* TRANSLATION_NOTE The following 3 strings are Javascript expressions */
        return "
	function trim(itemvalue) {
		// Get rid of leading space(s)
                //for (var i = 0; i < itemvalue.length; i++) {
                //        var ch = itemvalue.charAt(i);
                //       if (ch != \" \") {
                //              break
                //     }
                //}
                // Get rid of trailing space(s)
                for (var j = itemvalue.length - 1; j > -1; j--) {
                        var ch = itemvalue.charAt(j);
                        if (ch != \" \") {
                                break
                        }
                }
                var newvalue = ''
                for (var k = 0; k <= j; k++) {
                        newvalue += itemvalue.charAt(k)
                }
                return newvalue
        }

	function check_value(itemname, itemvalue) {
		if (itemvalue.length <= 0) {
                        alert('".gettext("Please input %s")."'.replace('%s',itemname));
			return false
		}
		
                if (itemvalue.indexOf(\" \") >= 0) {
                        alert('".gettext("No space is allowed in %s")."'.replace('%s',itemname));
                        return false
                }
                return true
        }

	// verify the given item name is started with the given pattern
        // and ended with digits
        function verify_name(itemvalue, pattern) {
                // verify the item name is started with pattern
                if (itemvalue.indexOf(pattern) != 0) {
                        return false
                }
                // verify the item name is ended with digits
                if (itemvalue.length == pattern.length) {
                        return false;
                }
                for (var i = pattern.length; i < itemvalue.length; i++) {
                        var digit = itemvalue.charAt(i);
                        if (digit < \"0\" || digit > \"9\") {
                                return false
                        }
                }
                return true
        }

	function verify_junction_name(jct) {
		var junction = trim(jct)
		if (!check_value('".gettext("Junction name")."', junction)) {
                        return false
                }
		return true
	}

	function verify_adapter_name(adapter) {
		var adp = trim(adapter)
                if (!check_value('".gettext("Adapter name")."', adp)) {
                        return false
                }
                if (!(verify_name(adp, 'qfe') || verify_name( adp, 'sci') || verify_name(adp, 'hme') || verify_name(adp, 'ge') || verify_name(adp, 'wrsm') || verify_name(adp, 'eri') || verify_name(adp, 'ce') || verify_name(adp, 'bge') || verify_name(adp, 'ibd') || verify_name(adp, 'e1000g') || verify_name(adp, 'iprb'))) {
                        alert('".gettext("Invalid adapter name -- %s.  Please make sure it starts with qfe, hme, sci, ge, eri, wrsm, ce, bge, ibd, e1000g or iprb and ends with digit(s).")."'.replace('%s',adp))
                        return false
                }
                return true
        }
	
	function display_adapter_submit(func) {
		self.location.href = '$CONFIG\?func=' + func + '&type=Adapter&name=' + document.inputs.adp_name.options[document.inputs.adp_name.selectedIndex].value
	} ";
}

##############################################################################
#
# Class methods
#
##############################################################################

#
# Print the paths table
#

sub paths_table($$) {
	my ($self, $q) = @_;

	# Set the headers for the node adapter table
	my @table_headers = (gettext("Endpoint"), "33%",
				gettext("Endpoint"), "33%",
				"&nbsp;", "14",
				gettext("Path Status"), "34%");

	# Determine the number of columns from the headers
	my $numcols = ($#table_headers + 1) / 2; 

	# Get the paths state list
	my @paths_state_list = $self->get_pathstate_list();

	# Start the table
	$q->start_prop_table(gettext("Transport Paths"), \@table_headers,
		$PATHSIMAGE);

	my ($separator_lacking) = 0;
	my ($have_path) = 0;

	# Draw the paths connected by junctions	
	# Note: path endpoints are always adapters
	for (my $i = 0; $i <= $#JUNCTION_LIST; $i++) {
		my @cable_list = 
			$self->get_cablelist_from($JUNCTION_LIST[$i]{'name'});

		for (my $j = 0; $j < $#cable_list; $j++) {
			for (my $k = $j + 1; $k <= $#cable_list; $k++) {
				# Start a table row
				$q->start_prop_tr();
				$have_path = 1;

				# Print a table cell for the endpoint(from)
				$q->start_prop_td();
				my $endpoint1 = "$cable_list[$j]{'node2'}:$cable_list[$j]{'name2'}";
				$q->table_link_text($endpoint1,
					gettext("Endpoint"),
					"$VIEW?type=Adapter&name=$endpoint1");
				$q->end_prop_td();

				# Print a table cell for the endpoint(to)
				my $endpoint2 = "$cable_list[$k]{'node2'}:$cable_list[$k]{'name2'}";
				$q->start_prop_td();
				$q->table_link_text($endpoint2,
					gettext("Endpoint"),
					"$VIEW?type=Adapter&name=$endpoint2");
				$q->end_prop_td();

				# Print a table cell for the path status
				$q->start_prop_td();
				$q->table_status_text($self->get_path_state($endpoint1, $endpoint2, 
									    \@paths_state_list),
						    \@path_status_icons);
				$q->end_prop_td();

				# End the row
				$q->end_prop_tr();

				# If we're not on our last row, print the line row divider,
				# giving the width of the table, in columns.
				if ($i < $#JUNCTION_LIST ||
				    $j < ($#cable_list - 1) ||
				    $k < $#cable_list) {
					$q->line_row($numcols);
				} else {
				    $separator_lacking = 1;
				}
			}
		}
	}

	# Draw path status for two directly connected adapters
	for (my $i = 0; $i <= $#CABLE_LIST; $i++) {
		if ($CABLE_LIST[$i]{'type1'} eq "Adapter" &&
		    $CABLE_LIST[$i]{'type2'} eq "Adapter") {
			# Print separator if needed
			# This handles the case of junctions and
			# direct connections.
			if ($separator_lacking) {
			    $separator_lacking = 0;
			    $q->line_row($numcols);
			}

			# Start a table row
			$q->start_prop_tr();
			$have_path = 1;

			# Print a table cell for the endpoint(from)
			$q->start_prop_td();
			my $endpoint1 = "$CABLE_LIST[$i]{'node1'}:" .
				"$CABLE_LIST[$i]{'name1'}";
			$q->table_link_text($endpoint1,
				gettext("Endpoint"),
				"$VIEW\?type=Adapter&name=$endpoint1");
			$q->end_prop_td();

			# Print a table cell for the endpoint(to)
			my $endpoint2 = "$CABLE_LIST[$i]{'node2'}:" .
				"$CABLE_LIST[$i]{'name2'}";
			$q->start_prop_td();
			$q->table_link_text($endpoint2,
				gettext("Endpoint"),
				"$VIEW\?type=Adapter&name=$endpoint2");
			$q->end_prop_td();

			# Print a table cell for the path status
			$q->start_prop_td();
			$q->table_status_text(
				$self->get_path_state($endpoint1, 
						      $endpoint2,
						      \@paths_state_list),
				\@path_status_icons);
			$q->end_prop_td();

			# End the row
			$q->end_prop_tr();

			# Print the line row if we're not on the last
			if ($i < $#CABLE_LIST) {
				$q->line_row($numcols);
			}
		}
	}

	# If we don't have paths, print a message
	if (! $have_path) {
	    # Start a table row and cell with the colspan of the table
	    $q->start_prop_tr();
	    $q->start_prop_td({ COLSPAN => 4 });

	    # Print the message in table-label-text style
	    $q->start_table_text('table-label-text');
	    print gettext("No paths exist on this cluster");
	    $q->end_table_text();

	    # End the cell and row
	    $q->end_prop_td();
	    $q->end_prop_tr();
	}

	# End the node status table
	$q->end_prop_table();
}

#
# Print the node adapter table
#

sub nodes_adapters_table($$) {
	my ($self, $q) = @_;

	# Set the headers for the node adapter table
	my @table_headers = (gettext("Node Name"), "25%",
			    "&nbsp;", "14",
			    gettext("Node Status"), "25%",
			    gettext("Adapter"), "25%",
			    "&nbsp;", "14",
			    gettext("Adapter Status"), "25%");
	# Determine the number of columns from the headers
	my $numcols = ($#table_headers + 1) / 2; 

	# Get node list
	my @node_list = $self->get_nodelist();

	# Start the property table
	$q->start_prop_table(gettext("Nodes/Adapters"), \@table_headers,
		$NODEADAPTERIMAGE);

	# Cycle through the list of nodes and print the status
	for (my $i = 0; $i <= $#node_list; $i++) {
		my @adapter_list = $self->get_adapterlist($node_list[$i]);

		# Start the adapter list cell
		for (my $j = 0; $j <= $#adapter_list; $j++) {
			# Start a table row for the node
			$q->start_prop_tr();
			if ($j == 0) {

			    # This function will print an icon and a link. It takes the
			    # label text, the alt tag text, the link to point to, and the
			    # icon to display before the text.
			    $q->start_prop_td();

			    # Make sure we have node read permissions
			    if ($rbac->check_auth($CL_AUTH_NODE_READ)) {
				    $q->table_link_text($node_list[$i],
					gettext("Node Name"),
					"$VIEW?type=Node&name=$node_list[$i]");
			    } else {
				    $q->start_table_text("table-label-text");
				    print $node_list[$i];
				    $q->end_table_text();
			    }
			    
			    $q->end_prop_td();

			    # Print a table cell for the status
			    $q->start_prop_td();
			    $q->table_status_text(
				$self->get_nodestate($node_list[$i]),
				\@status_icons);
			    $q->end_prop_td();
			} else {
			    $q->start_prop_td();
			    print "&nbsp;";
			    $q->end_prop_td();
			    $q->start_prop_td();
			    print "&nbsp;";
			    $q->end_prop_td();
			    $q->start_prop_td();
			    print "&nbsp;";
			    $q->end_prop_td();
			}
			$q->start_prop_td();

			$q->table_link_text($adapter_list[$j]{'name'},
			    gettext("Adapter Name"),
			    "$VIEW?type=Adapter&".
			    "name=$node_list[$i]:$adapter_list[$j]{'name'}");
			$q->end_prop_td();
			$q->start_prop_td();
			$q->table_status_text($adapter_list[$j]{'status'},
			    \@component_status_icons);
			$q->end_prop_td();
			$q->end_prop_tr();
		}

		# if we're not on our last row, print the line row divider
		if ($i < $#node_list) {
			$q->line_row($numcols);
		}
	}

	# End the table
	$q->end_prop_table();
}

#
# Print the junction table
#

sub junctions_table($$) {
	my ($self, $q) = @_;

	# Set the headers for the node adapter table
	my @table_headers = (gettext("Junction Name"), "33%",
				"&nbsp;", "14",
				gettext("Status"), "67%");

	# Determine the number of columns from the headers
	my $numcols = ($#table_headers + 1) / 2; 

	# Start the property table
	$q->start_prop_table(gettext("Junctions"), \@table_headers,
		$JUNCTIONIMAGE);

	# If we don't have any junctions, print a message
	if ($#JUNCTION_LIST == -1) {
		# Start a table row and cell with the colspan of the table
		$q->start_prop_tr();
		$q->start_prop_td({ COLSPAN => 3 });

		# Print the message in table-label-text style
		$q->start_table_text('table-label-text');
		print gettext("No transport junction has been " .
			      "configured on this cluster");
		$q->end_table_text();

		# End the cell and row
		$q->end_prop_td();
		$q->end_prop_tr();
    	}

	# Cycle through the list of nodes and print the status
	for (my $i = 0; $i <= $#JUNCTION_LIST; $i++) {

		# Start a table row for the node
		$q->start_prop_tr();

		# This function will print an icon and a link. It takes the
		# label text, the alt tag text, the link to point to, and the
		# icon to display before the text.
		$q->start_prop_td();
		$q->table_link_text($JUNCTION_LIST[$i]{'name'}, 
		    gettext("Junction Name"),
		    "$VIEW?type=Junction&name=$JUNCTION_LIST[$i]{'name'}");
		$q->end_prop_td();

		# Print a table cell for the status
		$q->start_prop_td();
		$q->table_status_text($JUNCTION_LIST[$i]{'status'},
		    \@component_status_icons);
		$q->end_prop_td();

		$q->end_prop_tr();

		# if we're not on our last row, print the line row divider
		if ($i < $#JUNCTION_LIST) {
			$q->line_row($numcols);
		}
	}

	# End the node status table
	$q->end_prop_table();
}

#
# Print the table of cables that are attached to the given endpoint
#

sub cables_table($$$$$) {
	my ($self, $q, $endpointname, $endpointtype, $nolink) = @_;
	my (@cable_list, @parts);

	# Set the headers for the resource group status table.
	my @table_headers = (gettext("Cable Endpoint"), "33%",
			gettext("Cable Endpoint"), "33%",
			"&nbsp;", "14",
                     	gettext("Cable Status"), "34%");

	# Determine the number of columns from the headers
	my $numcols = ($#table_headers + 1) / 2;

	if (!defined $endpointname) {
		# Print all the cables in cluster
		@cable_list = @CABLE_LIST;
        	$q->start_prop_table(gettext("Cables"), \@table_headers,
			$CABLEIMAGE);
	} else {
		# Print cables attached to the given endpointname
		@cable_list = $self->get_cablelist_from($endpointname);
        	$q->start_prop_table(sprintf(gettext("Cables - %s"), $endpointname),
				     \@table_headers, $CABLEIMAGE);
	}

	# If we don't have any cable attached to this endpoint, print a message
	if ($#cable_list == -1) {
		# Start a table row and cell with the colspan of the table
		$q->start_prop_tr();
		$q->start_prop_td({ COLSPAN => 4 });

		# Print the message in table-label-text style
		$q->start_table_text('table-label-text');
		if (!defined $endpointname) {
			print gettext("No cables have been configured " .
				      "on this cluster");
		} else {
			print sprintf(gettext("No cable is attached to %s"), $endpointname);
		}
		$q->end_table_text();

		# End the cell and row
		$q->end_prop_td();
		$q->end_prop_tr();
	}

	for (my $i = 0; $i <= $#cable_list; $i++) {
		# Start a table row
		$q->start_prop_tr();

		# Print a table cell for the cable's first endpoint
		$q->start_prop_td();
		$self->print_cable_endpoint($q, 
					$cable_list[$i]{'type1'}, 
					$cable_list[$i]{'node1'}, 
					$cable_list[$i]{'name1'}, 
					$cable_list[$i]{'port1'},
					$nolink);
		$q->end_prop_td();

		# Print a table cell for the cable's another endpoint
		$q->start_prop_td();
		$self->print_cable_endpoint($q, 
					    $cable_list[$i]{'type2'},
					    $cable_list[$i]{'node2'},
					    $cable_list[$i]{'name2'},
					    $cable_list[$i]{'port2'});
		$q->end_prop_td();

		# Print a table cell for the cable status
		$q->start_prop_td();
               	$q->table_status_text($cable_list[$i]{'status'},
		    \@component_status_icons);
		$q->end_prop_td();

		 # End the row
		$q->end_prop_tr();
		
		# Print the line row separator
		if ($i < $#cable_list) {
			$q->line_row($numcols);
		}
	}

	# End the table
        $q->end_prop_table();
}

#
# Print an endpoint of a cable
#

sub print_cable_endpoint($$$$$$$) 
{
	my ($self, $q, $type, $node, $name, $port, $nolink) = @_;

	if ($type eq "Adapter") {
		if (defined $nolink) {
			print "$node:$name";
		} else {
			$q->table_link_text("$node:$name",
				gettext("Adapter"), 
                        	"$VIEW?type=Adapter&name=$node:$name");
		}
	} elsif ($type eq "Junction") {
		if (defined $nolink) {
			print $q->img({ SRC    => $JUNCTIONIMAGE,
                           ALT    => gettext("Junction"),
                           WIDTH  => 16,
                           HEIGHT => 16,
                           BORDER => 0,
                           HSPACE => 3
                           });
			print "$name\@port$port";
		} else {
			$q->table_link_text("$name\@port$port",
				gettext("Junction"), 
	                        "$VIEW?type=Junction&name=$name");
		}
	}
}	

#
# Print the table of adapters on a given node
#

sub adapters_table($$$) {
	my ($self, $q, $nodename) = @_;

        # Set the headers for the node adapter table
        my @table_headers = (gettext("Adapter Name"), "50%",
				"&nbsp;", "14",
                                gettext("Adapter Status"), "50%");

        # Determine the number of columns from the headers
        my $numcols = ($#table_headers + 1) / 2;

	# Start the adapters table
        $q->start_prop_table(sprintf(gettext("Adapters - %s"),
			    $nodename), 
			     \@table_headers, $ADAPTERIMAGE);

	my @adapter_list = $self->get_adapterlist($nodename);
	
	for (my $i = 0; $i <= $#adapter_list; $i++) {
		$q->start_prop_tr();
		
		$q->start_prop_td();
		$q->table_link_text($adapter_list[$i]{'name'},
                                gettext("Adapter"),
                                "$VIEW?type=Adapter&name=$nodename:" .
				    "$adapter_list[$i]{'name'}");
		$q->end_prop_td();

		$q->start_prop_td();
		$q->table_status_text($adapter_list[$i]{'status'},
		    \@component_status_icons);
		$q->end_prop_td();
		
		$q->end_prop_tr();
		
		if ($i < $#adapter_list) {
			$q->line_row($numcols);
		}
	}

	# End the table
        $q->end_prop_table();
}

#
# Print the adapter or junction property table
#

sub properties_table($$$$)
{
	my ($self, $q, $name, $type) = @_;

	# Set the headers for the node adapter table
        my @table_headers = (gettext("Property"), "50%",
				"&nbsp;", "14",
                                gettext("Value"), "50%");

        # Determine the number of columns from the headers
        my $numcols = ($#table_headers + 1) / 2;

	# Get the property list	
	my @property_list = $self->get_propertylist($type, $name);

	# Start the table
	my $image = sprintf("/images/transport/%s_16.gif", lc($type));
	#XXX $image = sprintf("\$%sIMAGE", uc($type));
        $q->start_prop_table($q->sprintfn(gettext("%1 Properties - %2"),
				gettext($type), $name),
				 \@table_headers, $image);

	# If no property, this is not a valid transport component
	if ($#property_list == -1) {
		# Start a table row and cell with the colspan of the table
		$q->start_prop_tr();
		$q->start_prop_td({ COLSPAN => 3 });

		# Print the message in table-label-text style
		$q->start_table_text('table-label-text');
		print $q->sprintfn(gettext("%1 %2 doesn't exist on this cluster"), gettext($type), $name);
		$q->end_table_text();

		# End the cell and row
		$q->end_prop_td();
		$q->end_prop_tr();
	}

	for (my $i = 0; $i <= $#property_list; $i++) {
		$q->start_prop_tr();
		
		$q->start_prop_td();
		$q->start_table_text('table-label-text');
		print gettext($property_list[$i]{'property'}) . ":";
		# These strings come from scconf, so the scconf message
		# file could be used instead of putting them here,
		# subject to capitalization and spacing
		;# gettext("Node transport adapter")
		;# gettext("Adapter enabled")
		;# gettext("Adapter port names")
		;# gettext("Cluster transport junction")
		;# gettext("Junction enabled")
		;# gettext("Junction type")
		;# gettext("Junction port names")
		;# gettext("Adapter transport type");
		;# gettext("Device name");
		;# gettext("Device instance");
		;# gettext("Lazy free");
		;# gettext("Dlpi heartbeat timeout");
		;# gettext("Dlpi heartbeat quantum");
		;# gettext("Nw bandwidth");
		;# gettext("Bandwidth");
		;# gettext("Netmask");
		;# gettext("Ip address");
		;# gettext("Adapter port names");
		$q->end_table_text();
		$q->end_prop_td();
		
		$q->start_prop_td();
		if ($property_list[$i]{'property'} eq "Junction enabled" ||
			$property_list[$i]{'property'} eq "Adapter enabled") {
		    $q->table_status_text($self->trim($property_list[$i]{'value'}),
			\@enabled_status_icons);
			
		} else {
		    $q->table_status_text($self->trim($property_list[$i]{'value'}));
		}
		$q->end_prop_td();

		$q->end_prop_tr();

		if ($i < $#property_list) { 
			$q->line_row($numcols);
		}
	}

	# End the node status table
        $q->end_prop_table();
}

#
# Print the header, view and menu bar
#

sub transport_header($$$$) {
	my ($self, $q, $headername, $name) = @_;

	# Start the action bar table
        $q->start_action_bar_table($headername);

	if (!defined $name) {
		# Create the view menu links
		my @viewlinks = (gettext("Transport Status Table"), $VIEW,
				gettext("Transport Topology"),
				"$VIEW\?view=topological");

		# Print the view menu
		$q->view_menu(\@viewlinks, $VIEW);
	}

        # Print the middle of the action table
        $q->mid_action_bar_table();

        # Create the actions menu links
        my @links = ();
	my @action_helpMarkers = ();

	# Add if the user has solaris.cluster.transport.modify
	if ($rbac->check_auth($CL_AUTH_TRANSPORT_MODIFY)) {
		push (@links, gettext("Add Adapter..."),
		      "$ADD\?step=1&type=Adapter",

		      gettext("Remove Adapter..."),
		      "$CONFIG\?step=1&func=Remove&type=Adapter&name=$name");

		push (@action_helpMarkers, "transportpm-add-adapter",
		      "transportpm-remove-adapter");
	}

	# Add if the user has solaris.cluster.transport.admin
	if ($rbac->check_auth($CL_AUTH_TRANSPORT_ADMIN)) {
		push (@links, gettext("Enable Adapter..."),
		      "$CONFIG\?step=1&func=Enable&type=Adapter&name=$name",
               
		      gettext("Disable Adapter..."),
		      "$CONFIG?step=1&func=Disable&type=Adapter&name=$name");

		push (@action_helpMarkers, "transportpm-enable-adapter",
		      "transportpm-disable-adapter");
	}

	# Add if the user has transport.admin or transport.modify
	if ($rbac->check_auth($CL_AUTH_TRANSPORT_MODIFY) ||
	    $rbac->check_auth($CL_AUTH_TRANSPORT_ADMIN)) {
		push (@links, gettext("---------------------"),
		      "$VIEW");

		push (@action_helpMarkers, "separator");
	}

	# Add if the user has solaris.cluster.transport.modify
	if ($rbac->check_auth($CL_AUTH_TRANSPORT_MODIFY)) {
		push (@links, gettext("Add Cable..."),
			"$ADD\?step=1&type=Cable",
                        
			gettext("Remove Cable..."),
		      "$CONFIG\?step=1&func=Remove&type=Cable");

		push (@action_helpMarkers, "transportpm-add-cable",
		      "transportpm-remove-cable");
	}

	# Add if the user has solaris.cluster.transport.admin
	if ($rbac->check_auth($CL_AUTH_TRANSPORT_ADMIN)) {
		push (@links, gettext("Enable Cable..."),
		      "$CONFIG\?step=1&func=Enable&type=Cable",

		      gettext("Disable Cable..."),
		      "$CONFIG\?step=1&func=Disable&type=Cable");

		push (@action_helpMarkers, "transportpm-enable-cable",
		      "transportpm-disable-cable");
	}

	# Add if the user has transport.admin or transport.modify
	if ($rbac->check_auth($CL_AUTH_TRANSPORT_MODIFY) ||
	    $rbac->check_auth($CL_AUTH_TRANSPORT_ADMIN)) {
		push (@links, gettext("---------------------"),
		      "$VIEW");

		push (@action_helpMarkers, "separator");
	}	

	# Add if the user has solaris.cluster.transport.modify
	if ($rbac->check_auth($CL_AUTH_TRANSPORT_MODIFY)) {
		push (@links, gettext("Add Junction..."),
		      "$ADD\?step=1&type=Junction",
		
		      gettext("Remove Junction..."),
		      "$CONFIG\?step=1&func=Remove&type=Junction&name=$name");

		push (@action_helpMarkers, "transportpm-add-junction",
		      "transportpm-remove-junction");
	}

	# Add if the user has solaris.cluster.transport.admin
	if ($rbac->check_auth($CL_AUTH_TRANSPORT_ADMIN)) {
		push (@links, gettext("Enable Junction..."),
		      "$CONFIG\?step=1&func=Enable&type=Junction&name=$name",
                        
		      gettext("Disable Junction..."),
		      "$CONFIG\?step=1&func=Disable&type=Junction&name=$name");

		push (@action_helpMarkers, "transportpm-enable-junction",
		      "transportpm-disable-junction");
	}

	# Print if the user has transport modify or admin permissions
	if ($rbac->check_auth($CL_AUTH_TRANSPORT_MODIFY) ||
	    $rbac->check_auth($CL_AUTH_TRANSPORT_ADMIN)) {
		$q->load_action_helpMarkers(\@action_helpMarkers);
		$q->actions_menu(gettext("Action Menu"), \@links);
	}

        # End the action bar table
        $q->end_action_bar_table();
}

#
# Parse the nodename:adpname into nodename and adpname
#

sub get_node_adp($$) {
	my ($self, $str) = @_;
	my @parts = split /(\@)/, $str;
	@parts = split /(\:)/, $parts[0];
	return ($parts[0], $parts[2]);
}

#
# Return the transport junctions
#
sub get_junctionlist() {
	return @JUNCTION_LIST;
}

# 
# Get a list of transport junctions and their state. An example of
# expected 'scconf -p' output is:
#
# Cluster transport junction:                        switch1
#   Junction enabled:                                yes
#   Junction type:                                   switch
#   Junction port names:                             1 2 3
#
#   Junction port:                                   1
#     Port enabled:                                  yes
#
#   Junction port:                                   2
#     Port enabled:                                  yes
#
#   Junction port:                                   3
#     Port enabled:                                  yes
#

sub _get_junctionlist() {
	my (@junction_list, $i, $line, @parts);
	$i = 0;
	for (my $j = 0; $j <= $#SCCONFPOUT; $j++) {
		$line = $SCCONFPOUT[$j];
		if ($line =~ /Cluster transport junction:/) {
			@parts = split /(\S+)/, $line;
			$junction_list[$i]{'name'} = $parts[7];
			
			$line = $SCCONFPOUT[++$j];
			@parts = split /(\S+)/, $line;
			if ($parts[5] eq "yes") {
				$junction_list[$i]{'status'} = "enabled";
			} else {
				$junction_list[$i]{'status'} = "disabled";
			}
			$i++;
		}
	}
	return (@junction_list);
}

#
# Get Adapter list from a specified node. The expected sample adapter
# list output is:
# Cluster node name:                                 phys-hicks-1
#   Node ID:                                         1
#   Node enabled:                                    yes
#   Node private hostname:                           clusternode1-priv
#   Node quorum vote count:                          1
#   Node reservation key:                            0x390A235700000001
#   Node transport adapters:                         sci0 hme0
#
#   Node transport adapter:                          sci0
#     Adapter enabled:                               yes
#     Adapter transport type:                        dlpi
#     Adapter property:                              device_name=sci
#     Adapter property:                              device_instance=0
#     Adapter property:                              dlpi_heartbeat_timeout=10000
#     Adapter property:                              dlpi_heartbeat_quantum=1000
#     Adapter property:                              nw_bandwidth=80
#     Adapter property:                              bandwidth=30
#     Adapter property:                              dlpi_device_name=scid
#     Adapter property:                              adapter_id=8
#     Adapter property:                              netmask=255.255.255.128
#     Adapter property:                              ip_address=172.16.1.1
#     Adapter port names:                            0
#
#     Adapter port:                                  0
#       Port enabled:                                yes
#
#   Node transport adapter:                          hme0
#     Adapter enabled:                               yes
#     Adapter transport type:                        dlpi
#     Adapter property:                              device_name=hme
#     Adapter property:                              device_instance=0
#     Adapter property:                              dlpi_heartbeat_timeout=10000
#     Adapter property:                              dlpi_heartbeat_quantum=1000
#     Adapter property:                              nw_bandwidth=80
#     Adapter property:                              bandwidth=30
#     Adapter property:                              dlpi_device_name=scid
#     Adapter property:                              adapter_id=72
#     Adapter property:                              netmask=255.255.255.128
#     Adapter property:                              ip_address=172.16.1.2
#     Adapter port names:                            0
#

sub get_adapterlist($$) {
	my ($self, $nodename) = @_;
	my (@adp_list, $line, @parts, $i, $j);

	for ($j = 0; $j <= $#SCCONFPOUT; $j++) {
		$line = $SCCONFPOUT[$j];

		if ($line =~ /Cluster node name:/) {
                        @parts = split /(\S+)/, $line;
                        if (!($parts[7] eq $nodename)) {
				# not this node, continue;
                                next;
                        }

			# Found the specified node, let's find the
                        # adapter list on this node
                        $i = 0;
			for (++$j; $j <= $#SCCONFPOUT; $j++) {
				$line = $SCCONFPOUT[$j];
                                if ($line =~ /Cluster/) {

                                        # We are done with all the adps
                                        # on this node
                                        last;
                                }

				if ($line =~ /Node transport adapter:/) {
                                        @parts = split /(\S+)/, $line;
					$adp_list[$i]{'name'} = $parts[7];
					$line = $SCCONFPOUT[++$j];
                                        @parts = split /(\S+)/, $line;
                                        if ($parts[5] eq "yes") {
                                                $adp_list[$i]{'status'} = "enabled";
                                        } else {
                                                $adp_list[$i]{'status'} = "disabled";
                                        }
                                        $i++;
                                }
			}

			# Done
			last;
		}
	}

	return (@adp_list);
}

# 
# Get unconnected adapter list on the specified node
#

sub get_unconnected_adapterlist() {
	my ($self, $nodename) = @_;
	my (@adp_list, @cable_list, @unconnected_adp_list, %adp_hashlist, $i);

	@adp_list = $self->get_adapterlist($nodename);
	@cable_list = $self->get_cablelist_from($nodename);	
	# Initialize  list of adapter on $nodename that has cable attached
	for ($i = 0; $i < $#cable_list + 1; $i++) {
		$adp_hashlist{$cable_list[$i]{'name1'}}{'connection'} = "yes";
	}

	my $j = 0;
	for ($i = 0; $i < $#adp_list + 1; $i++) {
		if($adp_hashlist{$adp_list[$i]{'name'}}{'connection'} eq 'yes'){
			next;
		}
		$unconnected_adp_list[$j]{'name'} = "$nodename:$adp_list[$i]{'name'}";
		$unconnected_adp_list[$j]{'status'} = $adp_list[$i]{'status'};
		$j++;
	}
	return (@unconnected_adp_list);
}

#
# Get the cable list
#

sub get_cablelist() {
	return @CABLE_LIST;
}

#
# Get a list of transport cables configured on this cluster (internal
# use only). Expected sample output is:
#
#                    Endpoint            Endpoint            State
#                    --------            --------            -----
#  Transport cable:  phys-hicks-1:hme0@0 hub1@1              Disabled
#  Transport cable:  phys-hicks-2:hme0@0 hub1@2              Enabled
#  Transport cable:  phys-hicks-2:sci0@0 phys-hicks-1:sci0@0 Enabled
#

sub _get_cablelist() {
	my (@cable_list, $i, $line, @parts);
	$i = 0;
	# First get two endpoints
	foreach $line (@SCCONFPOUT) {
	        if ($line =~ /Transport cable:/) {
			@parts = split /(\S+)/, $line;
			$cable_list[$i]{'endpoint1'} = $parts[5];
			$cable_list[$i]{'endpoint2'} = $parts[7];
			$cable_list[$i]{'status'} = $parts[9];
			$i++;
		}
	}

	# Second, parse the endpoints to get the real values
	for ($i = 0; $i < $#cable_list + 1; $i++) {
		# get endpoint1 and endpoint2's values
		for (my $j = 1; $j <= 2; $j++) {
			my $l_endpoint = "endpoint$j";
			my $l_type = "type$j";
			my $l_name = "name$j";
			my $l_node = "node$j";
			my $l_port = "port$j";
			@parts = split /(\@)/, $cable_list[$i]{$l_endpoint};
			$cable_list[$i]{$l_port} = $parts[2];
			@parts = split /(\:)/, $parts[0];
			if ($#parts == 2) {
				# its an adapter, ex: phys-mensa-3:qfe1@0
				$cable_list[$i]{$l_type} = "Adapter";
				$cable_list[$i]{$l_node} = $parts[0];
				$cable_list[$i]{$l_name} = $parts[2];
			} else {
				# its a junction, ex: switch2@3
				$cable_list[$i]{$l_type} = "Junction";
				$cable_list[$i]{$l_node} = "";
				$cable_list[$i]{$l_name} = $parts[0];
			}
		}
	}
	return (@cable_list);
}

#
# Get the cables that are connected to the specified endpoint(node,
# adapter or junction)
#

sub get_cablelist_from($$) {
	my ($self, $endpointname) = @_;

	my (@cable_list, $i);
	$i = 0;
	# First get two endpoints
	for (my $j = 0; $j <= $#CABLE_LIST; $j++) {
		if ($CABLE_LIST[$j]{'endpoint1'} =~ $endpointname) {
			$cable_list[$i]{'status'} = $CABLE_LIST[$j]{'status'};
			$cable_list[$i]{'endpoint1'} = $CABLE_LIST[$j]{'endpoint1'};
			$cable_list[$i]{'endpoint2'} = $CABLE_LIST[$j]{'endpoint2'};
			$cable_list[$i]{'type1'} = $CABLE_LIST[$j]{'type1'};
			$cable_list[$i]{'type2'} = $CABLE_LIST[$j]{'type2'};
			$cable_list[$i]{'name1'} = $CABLE_LIST[$j]{'name1'};
			$cable_list[$i]{'name2'} = $CABLE_LIST[$j]{'name2'};
			$cable_list[$i]{'node1'} = $CABLE_LIST[$j]{'node1'};
			$cable_list[$i]{'node2'} = $CABLE_LIST[$j]{'node2'};
			$cable_list[$i]{'port1'} = $CABLE_LIST[$j]{'port1'};
			$cable_list[$i]{'port2'} = $CABLE_LIST[$j]{'port2'};
			$i++;
		} elsif ($CABLE_LIST[$j]{'endpoint2'} =~ $endpointname) {
			$cable_list[$i]{'status'} = $CABLE_LIST[$j]{'status'};
			$cable_list[$i]{'endpoint1'} = $CABLE_LIST[$j]{'endpoint2'};
			$cable_list[$i]{'endpoint2'} = $CABLE_LIST[$j]{'endpoint1'};
			$cable_list[$i]{'type1'} = $CABLE_LIST[$j]{'type2'};
			$cable_list[$i]{'type2'} = $CABLE_LIST[$j]{'type1'};
			$cable_list[$i]{'name1'} = $CABLE_LIST[$j]{'name2'};
			$cable_list[$i]{'name2'} = $CABLE_LIST[$j]{'name1'};
			$cable_list[$i]{'node1'} = $CABLE_LIST[$j]{'node2'};
			$cable_list[$i]{'node2'} = $CABLE_LIST[$j]{'node1'};
			$cable_list[$i]{'port1'} = $CABLE_LIST[$j]{'port2'};
			$cable_list[$i]{'port2'} = $CABLE_LIST[$j]{'port1'};
			$i++;
		}
			
	}
	return (@cable_list);
}

#
# Get cluster, node, adapter and junction's properties
# 

sub get_propertylist($$$)
{
	my ($self, $item_type, $item_name) = @_;

	my ($i, @p_list, $line, @parts);
	$i  = 0;
	if ($item_type eq "Cluster") {
		for (my $j = 0; $j <= $#SCCONFPOUT; $j++) {
			$line = $SCCONFPOUT[$j];
			if ($line =~ /Cluster name:/) {
				do {
					$line =~ s/^ +//;
					@parts = split /(\:)/, $line;	
					$p_list[$i]{'property'} = $parts[0];
					$p_list[$i]{'value'} = $parts[2];
					# Get rid of "<" and ">"
					$p_list[$i]{'value'} =~ tr/\</ /;
					$p_list[$i]{'value'} =~ tr/\>/ /;
					# Get rid of leading spaces
					$p_list[$i]{'property'} =~ s/^ +//;
					$line = $SCCONFPOUT[++$j]; 
					$i++;
				} while (!($line =~ /Cluster node name:/));
				last;
			}
		}
	}  elsif ($item_type eq "Node") {

		# Get this data from the node class
		@p_list = $node->get_scconf_node_properties($item_name);

	} elsif ($item_type eq "Adapter") {
		my ($nodename, $adpname) = $self->get_node_adp($item_name);
		for (my $j = 0; $j <= $#SCCONFPOUT; $j++) {
			$line = $SCCONFPOUT[$j];
			if (!($line =~ /Cluster node name:/)) {
				next;
			}
			@parts = split /(\S+)/, $line;
			if (!($parts[7] eq $nodename)) {
				next;
			}
			for (++$j; $j <= $#SCCONFPOUT; $j++) {
				$line = $SCCONFPOUT[$j];
				if (!($line =~ /Node transport adapter:/)) {
					next;
				}
				@parts = split /(\S+)/, $line;
				if (!($parts[7] eq $adpname)) {
					next;
				}
				do {
					@parts = split /(\:)/, $line;
					my @newparts = split /(\=)/, $parts[2];
					if ($#newparts >= 1) {
						$p_list[$i]{'property'} = $newparts[0];
						$p_list[$i]{'value'} = $newparts[2];
					} else{	
						$p_list[$i]{'property'} = $parts[0];
						$p_list[$i]{'value'} = $parts[2];
					}
					$p_list[$i]{'property'} =~ s/^ +//g;
					$p_list[$i]{'property'} =~ s/_/ /g;
					$p_list[$i]{'property'} = ucfirst(
					    $p_list[$i]{'property'});
					# Get rid of "<" and ">"
					$p_list[$i]{'value'} =~ tr/\</ /;
					$p_list[$i]{'value'} =~ tr/\>/ /;
					$line = $SCCONFPOUT[++$j];
					$i++;
				} while (!($line =~ /Adapter port:/) && !($line =~ /Cluster/) && !($line =~ /Node/));
				last;
			}
		}
	} elsif ($item_type eq "Junction") {
		for (my $j = 0; $j <= $#SCCONFPOUT; $j++) {
			$line = $SCCONFPOUT[$j];
			if (!($line =~ /Cluster transport junction:/)) {
				next;
			}
			@parts = split /(\S+)/, $line;
			if ($parts[7] eq $item_name) {
				$line = $SCCONFPOUT[++$j];
				do {
					$line =~ s/^ +//;
					@parts = split /(\:)/, $line;	
					$p_list[$i]{'property'} = $parts[0];
					$p_list[$i]{'value'} = $parts[2];
					# Get rid of "<" and ">"
					$p_list[$i]{'value'} =~ tr/\</ /;
					$p_list[$i]{'value'} =~ tr/\>/ /;
					$line = $SCCONFPOUT[++$j];
					$i++;
				} while (!($line =~ /Junction port:/) && !($line =~ /Cluster/));
				last;
			}
		}
	} 

	# Fix! Clean out the last element if it's partially empty
	if ($#p_list >= 0 &&
	    (!defined $p_list[$#p_list]{'property'} ||
	    !defined $p_list[$#p_list]{'value'} ||
	    $p_list[$#p_list]{'property'} eq "" ||
	    $p_list[$#p_list]{'value'} eq "")) {
		pop @p_list;
	}	

	return (@p_list);
}

#
# Get paths status
#
sub get_pathstate_list() {
#
# Sample path states output is:
#
#  Transport path:   phys-mensa-1:qfe1   phys-mensa-2:qfe1   faulted
#  Transport path:   phys-mensa-1:hme1   phys-mensa-2:hme1   Path online
#  Transport path:   phys-mensa-1:qfe1   phys-mensa-3:qfe1   Path online
#  Transport path:   phys-mensa-1:hme1   phys-mensa-3:hme1   Path online
#  Transport path:   phys-mensa-2:qfe1   phys-mensa-3:qfe1   Path online
#  Transport path:   phys-mensa-2:hme1   phys-mensa-3:hme1   waiting
#
	my (@pathstate_list, $i, $line, @parts);
	my @output = $runcommand->scstat("-W");
	$i = 0;
	for (my $j = 0; $j <= $#output; $j++) {
		$line = $output[$j];
		if ($line =~ 'Transport path:') {
			@parts = split /(\S+)/, $line;
			$pathstate_list[$i]{'endpoint1'} = $parts[5];
			$pathstate_list[$i]{'endpoint2'} = $parts[7];
			$pathstate_list[$i]{'status'} = $parts[$#parts];
			$i++;
		}
	}

	# Fix! Clean out the last element if it's partially empty
	if ($#pathstate_list >= 0 &&
	    (!defined $pathstate_list[$#pathstate_list]{'endpoint1'} ||
	    !defined $pathstate_list[$#pathstate_list]{'endpoint2'} ||
	    !defined $pathstate_list[$#pathstate_list]{'status'} ||
	    $pathstate_list[$#pathstate_list]{'endpoint1'} eq "" ||
	    $pathstate_list[$#pathstate_list]{'endpoint2'} eq "" ||
	    $pathstate_list[$#pathstate_list]{'status'} eq "")) {
		pop @pathstate_list;
	}

	return (@pathstate_list);
}

#
# Get the specified path status
#
sub get_path_state($$$$) {
	my ($self, $endpoint1, $endpoint2, $paths_state) = @_;

	my @paths_state_list = @$paths_state;

	for (my $i = 0; $i <= $#paths_state_list; $i++) {
		if (($paths_state_list[$i]{'endpoint1'} eq $endpoint1 && 
			$paths_state_list[$i]{'endpoint2'} eq $endpoint2) ||
			($paths_state_list[$i]{'endpoint2'} eq $endpoint1 && 
			$paths_state_list[$i]{'endpoint1'} eq $endpoint2)) {
			return $paths_state_list[$i]{'status'};
		}
	}

	return "offline";
}
	
# Get the pathend state of the specified endpoint(adapter on a node)
#sub get_pathendstate
#{
#	my ($self, $endpoint) = @_;
#	my (@pathend_statelist, $pathend_state, $i, $line, @parts);
#	open(SCSTATW, '/usr/cluster/bin/scstat -W |');
#	my @output = runcommand->scstat("-W");
#	$i = 0;
#	while ($line = <SCSTATW>) {
#	for (my $j = 0; $j <= $#output; $j++) {
#		if ($line =~ 'Transport path:') {
#			@parts = split /(\S+)/, $line;
#			# find the path information contains $endpoint
#			if ($parts[5] eq $endpoint || $parts[7] eq $endpoint) {
#				# Note: to "Path online", it will record
#				# "Path" only.
#				$pathend_statelist[$i] = $parts[9];
#				$i++;
#			}
#		}
#	}
#	#close(SCSTATW);
#
#	# Go through the path_statelist and find out the real state of this
#	# pathend. If one of the state is waiting/faulted, while other states
#	# are oneline, it means this pathend is ok. Otherwise, the pathend
#	# is waiting/faulted.
#
#	$pathend_state = "Offline"; # gettext("Offline")
#	for (; $i > 0; $i--) {
#		if (lc($pathend_statelist[$i-1]) eq "path") {
#			$pathend_state = "Online"; #gettext("Online")
#			last;
#		} else {
#			# if the pathend has both waiting and faulted,
#			# we will treat it as waiting since a down node
#			# will cause all its associated pathend to be faulted.
#			if (!(lc($pathend_state) eq "waiting")) {
#				$pathend_state = $pathend_statelist[$i-1];
#			} # gettext("waiting") gettext("faulted")
#		}
#	}
#	return ($pathend_state);
#}


# Display a list of adapters on the given node for user to select
#
sub display_adapterlist($$$$$) {
	my ($self, $q, $func, $name) = @_;

	my $op; 
	SWITCH: {
		if ($func eq "Remove") {
			$op = gettext("Remove Adapter");
			last SWITCH;
		}
		if ($func eq "Enable") {
			$op = gettext("Enable Adapter");
			last SWITCH;
		}
		if ($func eq "Disable") {
			$op = gettext("Disable Adapter");
			last SWITCH;
		}
	}
	$q->print_title([gettext("Transports"), "$VIEW", $op]);
	# gather information
	print "<form name=inputs action=$CONFIG>";
	print $q->start_table({ cellpadding => 5 });
	print $q->start_Tr();
	print $q->start_td();
	print $q->start_div({ class => "action-window-label-text" });
	print gettext("Node:");
	print $q->end_div();
	print $q->end_td();
	print $q->start_td();
	# Create the node menu links
	my @nodelist = $self->get_nodelist();
	my (@nodelinks, $nodename, $adpname, $selectidx);
	($nodename, $adpname) = $self->get_node_adp($name);
#	$nodelinks[0] = $nodename; 
#	$nodelinks[1] = "$CONFIG\?step=1&type=Adapter&func=$func&nodename=$nodename";
	my $j = 0;
	$selectidx = 0;
	for (my $i = 0; $i <= $#nodelist; $i++) {
		if ($nodelist[$i] eq $nodename) {
			$selectidx = $i;
		}
		$nodelinks[$j++] = $nodelist[$i];
		$nodelinks[$j++] = "$CONFIG\?step=1&type=Adapter&func=$func&name=$nodelist[$i]:";
	}
	if ($selectidx == 0) {
		# Reset the nodename in case it was not being passed in
		$nodename = $nodelist[0];
	}
	$q->select_menu(\@nodelinks, "node_menu", $nodelinks[1]);
	print $q->start_script();
	print "document.inputs.node_menu.selectedIndex=$selectidx";
	print $q->end_script();
	print $q->end_td();
	print $q->end_Tr();

	print $q->start_Tr();
	print $q->start_td();
	print $q->start_div({ class => "action-window-label-text" });
	print gettext("Adapter:");
	print $q->end_div();
	print $q->end_td();
	print $q->start_td();
	print "<select name=adp_name>";
	my @adp_list = $self->get_adapterlist($nodename);
	$selectidx = 0;
	for (my $i = 0; $i <= $#adp_list; $i++) {
		if ($adp_list[$i]{'name'} eq $adpname) {
			$selectidx = $i;
		}
		print "<option value=\"$nodename\:$adp_list[$i]{'name'}\">$adp_list[$i]{'name'}";
	}
	print "</select>";
	print $q->start_script();
	print "document.inputs.adp_name.selectedIndex=$selectidx";
	print $q->end_script();
	print $q->end_td();
	print $q->end_Tr();
	print $q->end_table();

	if (!($func eq "Enable")) {
		$q->start_message_table("warning");
		print $q->start_p({ class => "message-description-text" });
		if ($func eq "Remove") {
			print gettext("This action will permanently remove the selected adapter from the cluster transport configuration.");
		} else {
			print gettext("This action will disable the selected adapter, preventing the node from using the adapter for transport communication.");
		}
       		print $q->end_p();
	}
        $q->end_message_table();
	
	$q->buttons_table(sprintf(gettext(" %s Transport Adapter "),
	    gettext($func)),
		"display_adapter_submit('$func')",
                gettext("  Cancel  "),
               	"self.location.href = \"$VIEW\"" );
	print "</form>";
}
	
#
# Display a list of junctions on the cluster for user to select
#
sub display_junctionlist($$$$$) {
	my ($self, $q, $func, $name) = @_;

	my $op; 
	SWITCH: {
		if ($func eq "Remove") {
			$op = gettext("Remove Junction");
			last SWITCH;
		}
		if ($func eq "Enable") {
			$op = gettext("Enable Junction");
			last SWITCH;
		}
		if ($func eq "Disable") {
			$op = gettext("Disable Junction");
			last SWITCH;
		}
	}
	if ($#JUNCTION_LIST < 0) {
		$q->print_title([gettext("Transports"), $VIEW,
		    $op, $JUNCTIONVIEW, gettext("Warning")]);
		$q->start_message_table("warning");
		print $q->start_p({ class => "message-header-text" });
		print gettext("No transport junction has been Configured on this cluster");
		print $q->end_p();
		$q->end_message_table($q);
		$q->buttons_table(gettext("  Cancel  "), "self.location
.href=\"$VIEW\"" );
		print "</form>";
		return;
	}
	
	$q->print_title([gettext("Transports"), $VIEW, $op]);
	
	# Gather information
	print "<form name=inputs action=$CONFIG>";
	print $q->input({ type => "hidden",
				name => "func",
				value => $func });
	print $q->input({ type => "hidden",
				name => "type",
				value => "Junction" });

	print $q->start_table({ cellpadding => 5 });
	print $q->start_Tr();
	print $q->start_td();
	print $q->start_div({ class => "action-window-label-text" });
	print gettext("Junction:");
	print $q->end_div();
	print $q->end_td();
	print $q->start_td();
	print "<select name=name>";
	my $selectidx = 0;
        for (my $i = 0; $i <= $#JUNCTION_LIST; $i++) {
		if ($JUNCTION_LIST[$i]{'name'} eq $name) {
			$selectidx = $i;
		} 
                print "<option value=$JUNCTION_LIST[$i]{'name'}>$JUNCTION_LIST[$i]{'name'}";
        }
	print "</select>";
	print $q->start_script();
	print "document.inputs.name.selectedIndex=$selectidx";
	print $q->end_script();
        print $q->end_td();
        print $q->end_Tr();
        print $q->end_table();

	if (!($func eq "Enable")) {
		$q->start_message_table("warning");
		print $q->start_p({ class => "message-description-text" });
		if ($func eq "Remove") {
			print gettext("This action will permanently remove the selected junction from the cluster transport configuration.");
		} else {
			print gettext("This action will disable the selected junction, preventing the nodes connected to it from using the hub for transport communication.");
		}
       		print $q->end_p();
	}
        $q->end_message_table();
	
	$q->buttons_table(sprintf(gettext(" %s Transport Junction "),
		gettext($func)),
		"document.inputs.submit()",
		gettext("  Cancel  "),
		"self.location.href = \"$VIEW\"" );
	print "</form>";
}

#
# Display a list of cables on the cluster for user to select
#
sub display_cablelist($$$$) {
	my ($self, $q, $func) = @_;

	my $op; 
	SWITCH: {
		if ($func eq "Remove") {
			$op = gettext("Remove Cable");
			last SWITCH;
		}
		if ($func eq "Enable") {
			$op = gettext("Enable Cable");
			last SWITCH;
		}
		if ($func eq "Disable") {
			$op = gettext("Disable Cable");
			last SWITCH;
		}
	}
	$q->print_title([gettext("Transports"), $VIEW, $op]);
	
	# Gather information
	print "<form name=inputs action=$CONFIG>";
	print $q->input({ type => "hidden",
				name => "func",
				value => $func });
	print $q->input({ type => "hidden",
				name => "type",
				value => "Cable" });

	print $q->start_table({ cellpadding => 5 });
	print $q->start_Tr();
	print $q->start_td();
	print $q->start_div({ class => "action-window-label-text" });
	print gettext("Cable:");
	print $q->end_div();
	print $q->end_td();
	print $q->start_td();
	print "<select name=name>";
        for (my $i = 0; $i <= $#CABLE_LIST; $i++) {
                print "<option value=$CABLE_LIST[$i]{'endpoint1'}>$CABLE_LIST[$i]{'endpoint1'} ~ $CABLE_LIST[$i]{'endpoint2'}";
        }
	print "</select>";
        print $q->end_td();
        print $q->end_Tr();
        print $q->end_table();

	if (!($func eq "Enable")) {
		$q->start_message_table("warning");
		print $q->start_p({ class => "message-description-text" });
		if ($func eq "Remove") {
			print gettext("This action will permanently remove the selected cable from the cluster transport configuration.");
		} else {
			print gettext("This action will disable the selected cable, preventing this node from communicating via this transport adapter.");
		}
       		print $q->end_p();
	}
        $q->end_message_table();
	
	$q->buttons_table(sprintf(gettext(" %s Transport Cable "),
		    gettext($func)),
			"document.inputs.submit()",
                        gettext("  Cancel  "),
                        "self.location.href = \"$VIEW\"" );
	print "</form>";
}

sub config_remove
{
        my ($self, $q, $item_type, $item_name) = @_;

	my ($cmd, @cable_list);

	my $op;

	SWITCH: {
		if ($item_type eq "Adapter") {
			my ($nodename, $adpname) = $self->get_node_adp($item_name);
			$cmd = "$SCCONF -r -A node=$nodename,name=$adpname";
			$op = gettext("Remove Adapter");
			last SWITCH;
		}
		if ($item_type eq "Cable") {
			$cmd = "$SCCONF -r -m endpoint=$item_name";
			$op = gettext("Remove Cable");
			last SWITCH;
		}
		if ($item_type eq "Junction") {
			$cmd = "$SCCONF -r -B name=$item_name";
			$op = gettext("Remove Junction");
			last SWITCH;
		}
	}
	
	# Executing the command
	my $noreload = "noreload";
	if ($item_type eq "Junction") {
		$noreload = "";
	}
	$self->execute_cmd($q, $cmd,
	    [gettext("Transports"), $VIEW,
		$op,
		"$CONFIG\?step=1&func=Remove&type=$item_type&name=$item_name"],
	    $noreload);
}

sub config_changestate
{
	my ($self, $q, $item_type, $item_name, $action) = @_;

	my ($cmd, $state);
	my $op;
	if ($action eq "Disable") {
		$state = "disabled"; #gettext("disabled");
	} else {	
		$state = "enabled"; #gettext("enabled");
	}
	
	SWITCH: {
		if ($item_type eq "Adapter") {
			my ($nodename, $adpname) = $self->get_node_adp($item_name);
			#my @parts = split /(\:)/, $item_name;
			#$nodename = $parts[0];
			#$adpname = $parts[2];
			$cmd = "$SCCONF -c -A node=$nodename,name=$adpname,state=$state";
			if ($action eq "Disable") {
				$op = gettext("Disable Adapter");
			} else {
				$op = gettext("Enable Adapter");
			}
			#@item_list = $self->get_adapterlist($nodename);
			#%item_hashlist = $self->list_to_hashlist(\@item_list);
			#$cur_state = $item_hashlist{$adpname}{'status'};
			last SWITCH;
		}
		if ($item_type eq "Cable") {
			$cmd = "$SCCONF -c -m endpoint=$item_name,state=$state";
			if ($action eq "Disable") {
				$op = gettext("Disable Cable");
			} else {
				$op = gettext("Enable Cable");
			}
			#@item_list = $self->get_cablelist_from($item_name);
			# should be only one cable found
			#$cur_state = $item_list[0]{'status'};
			last SWITCH;
		}
		if ($item_type eq "Junction") {
			$cmd = "$SCCONF -c -B name=$item_name,state=$state";
			if ($action eq "Disable") {
				$op = gettext("Disable Junction");
			} else {
				$op = gettext("Enable Junction");
			}
			#@item_list = $self->get_junctionlist($item_name);
			#%item_hashlist = $self->list_to_hashlist(\@item_list);
			#$cur_state = $item_hashlist{$item_name}{'status'};
			last SWITCH;
		}
	}
	# Executing the command
	$self->execute_cmd($q, $cmd,
	    [gettext("Transports"), $VIEW,
		$op, "$ADD\?step=1&type=Cable"],
		"$CONFIG\?step=1&func=$action&type=$item_type",
	    "noreload");
}

#
# Execute the given command
#
sub execute_cmd($$$$$$)
{
        my ($self, $q, $cmd, $title, $noreload) = @_;

        my $output = `$PFEXEC $cmd 2>&1`;
        my $ret = $?;
        if ($ret == 0) {
		pop @$title; # Don't use last link
		$q->print_title($title);
                print $q->start_form();
                $q->start_message_table("info");
                print $q->start_p({ class => "message-header-text" });
                print gettext("Transport Operation Completed Successfully");
                print $q->end_p();
                print $q->start_p({ class => "message-description-text" });
                print gettext("The following command completed without error:");
                print $q->end_p();
                print $q->start_p({ class => "message-command-text" });
                print $cmd;
                print $q->end_p();
                $q->end_message_table();
                $q->buttons_table(gettext(" View Transport Information "),
				"self.location.href= \"$VIEW\"" );
                print $q->end_form();
                if (!defined $noreload) {
			print $q->start_script();
			print "top.menu.location.reload(true)";
			print $q->end_script();
                }
        } else {
		push @$title, gettext("Error"); # Add error message to title
		$q->print_title($title);
                print $q->start_form();
                $q->start_message_table("error");
                print $q->start_p({ class => "message-header-text" });
                print gettext("Error");
                print $q->end_p();
                print $q->start_p({ class => "message-description-text" });
                print gettext("The command:");
                print $q->end_p();
                print $q->start_p({ class => "message-command-text" });
                print $cmd;
                print $q->end_p();
                print $q->start_p({ class => "message-description-text" });
                print gettext("Failed with the following error:");
                print $q->end_p();
                print $q->start_p({ class => "message-command-text" });
                print $output;
                print $q->end_p();
                $q->end_message_table();
                $q->buttons_table(gettext("  < Back  "), "history.back()",
				  gettext("  Cancel  "),
				  "self.location.href = \"$VIEW\"" );
                print $q->end_form();
        }
}

#
# Add a cable
#
sub add_cable
{
	my ($self, $q, $step, $endpoint1, $endpoint2) = @_;
	
	my (@node_list, @adp_list, @all_adp_list, @jn_list);
	if ($step == 1) {
		@node_list = $self->get_nodelist();

		# Get full list of nodename:adp
		my $idx = -1;
		for (my $i = 0; $i < $#node_list + 1; $i++) {
			@adp_list = $self->get_unconnected_adapterlist($node_list[$i]);
			for (my $j = 0; $j < $#adp_list + 1; $j++) {
				$idx++;
				$all_adp_list[$idx] = $adp_list[$j]{'name'};
			}
		}
	
		if ($idx < 0) {
			$q->print_title([gettext("Transports"), $VIEW,
			    gettext("Add Cable"), "$ADD\?step=1&type=Cable",
			    gettext("Warning")]);
			print "<form>";
                        $q->start_message_table("warning");
                        print $q->start_p({ class => "message-description-text" });
                        print gettext("There is no free adapter. Do you want to add a new adapter first?");
                        print $q->end_p();
                        $q->end_message_table();
                        $q->buttons_table(gettext("Yes, Add New Transport Adapter"),
				"self.location.href=\"$ADD\?type=Adapter&step=1\"",
				gettext("  Cancel  "),
				"self.location.href=\"$VIEW\"" );
                        print "</form>";
		} else {		
			# Get full list of junctions
			for (my $i = 0; $i < $#JUNCTION_LIST + 1; $i++) {
				$jn_list[$i] = $JUNCTION_LIST[$i]{'name'};
			}
			
			$q->print_title([gettext("Transports"), $VIEW,
			    gettext("Add Cable")]);
		
			# gather information
			print $q->br();
			$q->start_table_text('table-label-text');
			print gettext("Select the two endpoints for the new cable:");
			$q->end_table_text();
			print "<form name=inputs action=$ADD>";
                        print $q->input({ type => "hidden",
                                        name => "step",
                                        value => 2 });
                        print $q->input({ type => "hidden",
                                        name => "type",
                                        value => "Cable" });
			print $q->start_table({ cellpadding => 5 });

			print $q->start_Tr();
                        print $q->start_td();
                        print $q->start_div({ class => "action-window-label-text
" });
                        print gettext("Endpoint:");
                        print $q->end_div();
                        print $q->end_td();
                        print $q->start_td(); 
			print $q->popup_menu({ name => 'endpoint1',
						values => \@all_adp_list });
			print $q->end_td();
	                print $q->end_Tr();
			
			print $q->start_Tr();
	                print $q->start_td();
			print $q->start_div({ class => "action-window-label-text
" }); 
                        print gettext("Endpoint:");
                        print $q->end_div();
                        print $q->end_td();
                        print $q->start_td();

			# The endpoint2 should include junction list
			push @jn_list, @all_adp_list;
			print $q->popup_menu({ name => 'endpoint2',
						values => \@jn_list });
			print $q->end_td();
			print $q->end_Tr();
			print $q->end_table();
		
			$q->buttons_table(gettext(" Add Transport Cable"),
				"document.inputs.submit()",
				gettext("  Cancel  "),
				"self.location.href = \"$VIEW\"");	

			print "</form>";
		}	
	} else {
		# generate the command
		my $cmd = "$SCCONF -a -m endpoint=$endpoint1,endpoint=$endpoint2";
		# Executing the command
                $self->execute_cmd($q, $cmd,
		    [gettext("Transports"), $VIEW,
			gettext("Add Cable"), "$ADD\?step=1&type=Cable"],
		    "noreload");
	}
}

sub add_adapter{
	my ($self, $q, $step, $node_name, $adp_name, $trtype) = @_;

	my (@node_list, $i);
	
	if ($step == 1) {
		@node_list = $self->get_nodelist();
		$q->print_title([gettext("Transports"), $VIEW,
		    gettext("Add Adapter")]);

		# gather information
		print "<form name=inputs action=$ADD>";
		print $q->input({ type => "hidden", name => "step",
				value => 2 });
		print $q->input({ type => "hidden", name => "type",
				value => "Adapter" });
		print $q->start_table({ cellpadding => 5 });

		print $q->start_Tr();
		print $q->start_td();
		print $q->start_div({ class => "action-window-label-text" });
		print gettext("Node:");
		print $q->end_div();
                print $q->end_td();
		print $q->start_td();
		print "<select name=node_name>";
		for ($i = 0; $i <= $#node_list; $i++) {
			print "<option value=$node_list[$i]>$node_list[$i]";
		}
		print "</select>";
		print $q->end_td();
		print $q->end_Tr();
		
		print $q->start_Tr();
		print $q->start_td();
		print $q->start_div({ class => "action-window-label-text" });
		print gettext("Adapter Name:");
		print $q->end_div();
                print $q->end_td();
		print $q->start_td();
		print $q->input({ type=> "text", name => "adp_name",
				 size => 10,  maxlength => 20 });
		print $q->end_td();
		print $q->end_Tr();

		print $q->start_Tr();	
		print $q->start_td();
		print $q->start_div({ class => "action-window-label-text" });
		print $q->end_div();
                print $q->end_td();
		print $q->start_td();
                print $q->input({ type => "hidden", name => "trtype",
                                value => "dlpi" });	
		print $q->end_td();
		print $q->end_Tr();
	
		print $q->end_table();
		
		$q->buttons_table(gettext(" Add Transport Adapter "),
			"if (verify_adapter_name(document.inputs.adp_name.value)) document.inputs.submit()",
			gettext("  Cancel  "),
			"window.location.href = \"$VIEW\"" );
		print "</form>";
	} else {
		# generate the command	
		my $cmd="$SCCONF -a -A trtype=$trtype,node=$node_name,name=$adp_name";
		# Executing the command
                $self->execute_cmd($q, $cmd,
		    [gettext("Transports"), $VIEW,
			gettext("Add Adapter"), "$ADD\?step=1&type=Adapter"],
		    "noreload");
	}
}

sub add_junction
{
	my ($self, $q, $step, $junction_name, $junction_type) = @_;
	if ($step == 1) {
		$q->print_title([gettext("Transports"), $VIEW,
		    gettext("Add Junction")]);

		# gather information
		print "<form name=inputs action=$ADD>";
                print $q->input({ type => "hidden", name => "step",
                                value => 2 });
                print $q->input({ type => "hidden", name => "type",
                                value => "Junction" });	
		print $q->start_table({ cellpadding => 5 });

		print $q->start_Tr();
                print $q->start_td();
                print $q->start_div({ class => "action-window-label-text" });
                print gettext("Junction Name:");
                print $q->end_div();
                print $q->end_td();
                print $q->start_td();
		print $q->input({ type=> "text", name => "junction_name",
                                 size => 10,  maxlength => 20 });
		print $q->end_td();	
		print $q->end_Tr();


		print $q->start_Tr();
		print $q->start_td();
                print $q->start_div({ class => "action-window-label-text" });
                print $q->end_div();
                print $q->end_td();
                print $q->start_td();
                print $q->input({ type => "hidden", name => "junction_type",
                                value => "switch" });	
		print $q->end_td();
		print $q->end_Tr();
		print $q->end_table();
		
		$q->buttons_table(gettext(" Add Transport Junction "),
                        "if (verify_junction_name(document.inputs.junction_name.value)) document.inputs.submit()",
                        gettext("  Cancel  "),
                        "window.location.href = \"$VIEW\"" );
                print "</form>";		
	} else {
		# generate the command	
		my $cmd="$SCCONF -a -B type=$junction_type,name=$junction_name";
	
		# Executing the command
                $self->execute_cmd($q, $cmd,
		    [gettext("Transports"), $VIEW,
			gettext("Add Junction"), "$ADD\?step=1&type=Adapter"]);
	}
}

#
# Preload "scconf -p" command output into memory
#

sub get_commandoutput($)
{
	my ($self) = @_;
	my $updated;
	($updated, @SCCONFPOUT) = $runcommand->scconfp_cache();

	# If we have been updated, recreate the other lists
	if ($updated == TRUE) {
		splice(@JUNCTION_LIST, 0, $#JUNCTION_LIST + 1);
		splice(@CABLE_LIST, 0, $#CABLE_LIST + 1);
		@JUNCTION_LIST = _get_junctionlist();
		@CABLE_LIST = _get_cablelist();
	}
}

# Return true
1;
