/*
 *        JacORB - a free Java ORB
 *
 *   Copyright (C) 1997-2014 Gerald Brose / The JacORB Team.
 *
 *   This library is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU Library General Public
 *   License as published by the Free Software Foundation; either
 *   version 2 of the License, or (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *   Library General Public License for more details.
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this library; if not, write to the Free
 *   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

package org.jacorb.orb.util;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.FileReader;
import java.io.LineNumberReader;
import java.io.PrintWriter;
import java.util.List;
import org.jacorb.config.ConfigurationException;
import org.jacorb.orb.CDRInputStream;
import org.jacorb.orb.CodeSet;
import org.jacorb.orb.ORBConstants;
import org.jacorb.orb.ParsedIOR;
import org.jacorb.orb.TaggedComponentList;
import org.jacorb.orb.etf.ProfileBase;
import org.jacorb.orb.iiop.IIOPAddress;
import org.jacorb.orb.iiop.IIOPProfile;
import org.jacorb.orb.miop.MIOPProfile;
import org.omg.CONV_FRAME.CodeSetComponentInfoHelper;
import org.omg.CORBA.ORB;
import org.omg.CSIIOP.CompoundSecMechList;
import org.omg.CSIIOP.CompoundSecMechListHelper;
import org.omg.CSIIOP.TAG_SECIOP_SEC_TRANS;
import org.omg.CSIIOP.TAG_TLS_SEC_TRANS;
import org.omg.CSIIOP.TLS_SEC_TRANS;
import org.omg.CSIIOP.TLS_SEC_TRANSHelper;
import org.omg.ETF.Profile;
import org.omg.IOP.TAG_ALTERNATE_IIOP_ADDRESS;
import org.omg.IOP.TAG_CODE_SETS;
import org.omg.IOP.TAG_CSI_SEC_MECH_LIST;
import org.omg.IOP.TAG_GROUP;
import org.omg.IOP.TAG_JAVA_CODEBASE;
import org.omg.IOP.TAG_MULTIPLE_COMPONENTS;
import org.omg.IOP.TAG_NULL_TAG;
import org.omg.IOP.TAG_ORB_TYPE;
import org.omg.IOP.TAG_POLICIES;
import org.omg.IOP.TAG_RMI_CUSTOM_MAX_STREAM_FORMAT;
import org.omg.IOP.TaggedComponent;
import org.omg.PortableGroup.TagGroupTaggedComponent;
import org.omg.PortableGroup.TagGroupTaggedComponentHelper;
import org.omg.RTCORBA.PRIORITY_BANDED_CONNECTION_POLICY_TYPE;
import org.omg.RTCORBA.PRIORITY_MODEL_POLICY_TYPE;
import org.omg.RTCORBA.PriorityModel;
import org.omg.SSLIOP.TAG_SSL_SEC_TRANS;
import org.slf4j.Logger;

/**
 * @author Gerald Brose
 */
public class PrintIOR
{
    /**
     * entry point from the command line
     */

    public static void main(String args[]) throws Exception
    {
        final org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args,null);
        final org.jacorb.orb.ORB jorb = (org.jacorb.orb.ORB)orb;
        final Logger logger =
            jorb.getConfiguration().getLogger("org.jacorb.print_ior");

        boolean urlForm = false;
        boolean corbalocForm = false;
        String iorString = null;
        String file = null;

        if( args.length < 2 || args.length > 3)
        {
            usage();
        }

        for (int i = 0; i < args.length; i++)
        {
            if ("-u".equals(args[i]))
            {
                urlForm = true;
            }
            else if ("-c".equals(args[i]))
            {
                corbalocForm = true;
            }
            else if ("-i".equals(args[i]))
            {
                iorString = args[i + 1];
                ++i;
            }
            else if ("-f".equals(args[i]))
            {
                file = args[i + 1];
                ++i;
            }
            else
            {
                usage();
            }
        }

        if( logger.isDebugEnabled() )
        {
            logger.debug
            (
                "Under " +
                System.getProperty ("os.name") +
                " the encoding name is " +
                System.getProperty( "file.encoding" ) +
                " and the canonical encoding name is " +
                ( new java.io.OutputStreamWriter( new ByteArrayOutputStream () ) ).getEncoding()
            );
        }

        PrintWriter out = new PrintWriter(System.out, true);

        try
        {
           if (file != null)
            {
                final LineNumberReader in = new LineNumberReader(new BufferedReader(new FileReader(file)));
                try
                {
                    String line = null;
                    while( (line = in.readLine()) != null)
                    {
                       iorString = line;
                    }
                }
                finally
                {
                    in.close();
                }
            }


           if( iorString.startsWith( "IOR:" ))
           {
              final ParsedIOR pior = new ParsedIOR(jorb, iorString );
              if (urlForm)
              {
                 out.println(CorbaLoc.parseKey(pior.get_object_key()));
              }
              else if (corbalocForm)
              {
                  out.println (printFullCorbalocIOR (orb, iorString));
              }
              else
              {
                 printIOR(jorb, pior, out);
              }
           }
           else
           {
              out.println("Sorry, we only unparse IORs in the standard IOR URL scheme");
           }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        finally
        {
            out.flush();
        }

        orb.shutdown(true);
    }


    /**
     * Given a IOR string this will decode it and output a corbaloc::... string.
     *
     * Split off into a separate function from main so its easier to be called programmatically.
     */
    public static String printCorbalocIOR (org.omg.CORBA.ORB orb, String iorString)
    {
        try
        {
            return printFullCorbalocIOR (orb, iorString);
        }
        catch (RuntimeException re)
        {
            throw new RuntimeException (re.getMessage());
        }
    }

    /**
     *
     * @param orb
     * @param iorString
     * @return a corbaloc string to fully describe a given IOR string, which
     * may have more than one profiles each may have additional
     * TAG_ALTERNATE_IIOP_ADDRESS tags.
     */
    public static String printFullCorbalocIOR (
                                    org.omg.CORBA.ORB orb, String iorString)
    {
        return CorbaLoc.generateCorbalocForMultiIIOPProfiles(orb, iorString);
    }

    private static void usage()
    {
        System.err.println("Usage: java PrintIOR "
                + "[ -i ior_str ] [ -f filename] [-u | -c]"
                + "\n\tior_str\t IOR as String"
                + "\n\t-f\t reads one or more IOR's from the file <filename>"
                + "\n\t-u\t extract object key in URL-Form instead of HEX "
                + "\n\t-c\t output corbaloc form of IOR string"
                ); // NOPMD
        System.exit( 1 );
    }

    /**
     * top-level
     */

    public static void printIOR (ORB orb, ParsedIOR pior, PrintWriter out)
    {
        org.omg.IOP.IOR ior = pior.getIOR();

        out.println("------IOR components-----");
        out.println("TypeId\t:\t" + ior.type_id );

        List<Profile> profiles = pior.getProfiles();

        out.println("TAG_INTERNET_IOP Profiles:");
        for( int i = 0; i < profiles.size(); i++ )
        {
            out.println("\tProfile Id:\t\t" + i);

            ProfileBase profile = (ProfileBase)profiles.get(i);
            out.println("\tIIOP Version:\t\t" +
                               (int)profile.version().major + "." +
                               (int)profile.version().minor);
            if (profile instanceof IIOPProfile)
            {
                out.println("\tHost:\t\t\t" +
                  ((IIOPAddress)((IIOPProfile)profile).getAddress()).getOriginalHost());
                int port = ((IIOPAddress)((IIOPProfile)profile).getAddress()).getPort();
                if( port < 0 )
                {
                    port += 65536;
                }

                out.println("\tPort:\t\t\t" + port );
            }
            else if (profile instanceof MIOPProfile)
            {
                out.println ("MIOPProfile:\t" + ((MIOPProfile)profile).toString ());
            }
            out.println("\tObject key (URL):\t" + CorbaLoc.parseKey( profile.get_object_key()));
            out.print  ("\tObject key (hex):\t0x" );
            dumpHex( profile.get_object_key(), out);
            out.println();

            if ( profile.version().minor >= ( char ) 1 )
            {
                if( profile.getComponents().size() > 0 )
                {
                    out.println("\t-- Found " +
                                       profile.getComponents().size() +
                                       " Tagged Components--" );
                }

                printTaggedComponents(orb, profile.getComponents().asArray(), out);
            }
            out.print("\n");
        }

        TaggedComponentList multiple_components = pior.getMultipleComponents();

        if( multiple_components.size() > 0 )
        {
            out.println("Components in MULTIPLE_COMPONENTS profile: " +
                               multiple_components.size() );

            printTaggedComponents(orb, multiple_components.asArray(), out);
        }

        // Print any unknown tags. This block is a simplified version of the private
        // ParsedIOR::decode function.
        for (int i=0; i < ior.profiles.length; i++)
        {
            int tag = ior.profiles[i].tag;
            boolean found = false;

            // See if JacORB managed to parse this tag before into the ParsedIOR
            for (int j=0; j < profiles.size(); j++)
            {
                final IIOPProfile profile = (IIOPProfile)profiles.get(j);

                if (profile.tag () == tag)
                {
                    found = true;
                }

                if (tag == TAG_MULTIPLE_COMPONENTS.value)
                {
                    found = true;
                }
            }
            // This is an unknown tag that wasn't dealt with before.
            if ( ! found)
            {
                out.println ("Unknown profile found with tag " + tag);
            }
        }
    }

    /**
     * Iterates over a tagged IOP components and prints those that are
     * recognized.
     */

    private static void printTaggedComponents( ORB orb, TaggedComponent[] taggedComponents, PrintWriter out )
    {
        for( int i = 0; i < taggedComponents.length; i++ )
        {
            switch( taggedComponents[i].tag )
            {
                case TAG_SSL_SEC_TRANS.value:
                {
                    out.println("\t#"+ i + ": TAG_SSL_SEC_TRANS");
                    printSSLTaggedComponent(taggedComponents[i], out);
                    break;
                }
                case TAG_CSI_SEC_MECH_LIST.value:
                {
                    out.println("\t#"+ i + ": TAG_CSI_SEC_MECH_LIST");
                    printCSIMechComponent(taggedComponents[i], out);
                    break;
                }
                case TAG_SECIOP_SEC_TRANS.value:
                {
                    out.println("\t#"+ i + ": TAG_SECIOP_SEC_TRANS");
                    break;
                }
                case TAG_ALTERNATE_IIOP_ADDRESS.value:
                {
                    out.println("\t#"+ i + ": TAG_ALTERNATE_IIOP_ADDRESS");
                    printAlternateAddress(orb, taggedComponents[i], out);
                    break;
                }
                case TAG_CODE_SETS.value:
                {
                    out.println("\t#"+ i + ": TAG_CODE_SETS");
                    printCodeSetComponent(taggedComponents[i], out);
                    break;
                }
                case TAG_JAVA_CODEBASE.value:
                {
                    out.println("\t#"+ i + ": TAG_JAVA_CODEBASE");
                    printJavaCodebaseComponent(taggedComponents[i], out);
                    break;
                }
                case TAG_ORB_TYPE.value:
                {
                    out.println("\t#"+ i + ": TAG_ORB_TYPE");
                    printOrbTypeComponent(taggedComponents[i], out);
                    break;
                }
                case TAG_POLICIES.value:
                {
                    out.println("\t#"+ i + ": TAG_POLICIES");
                    printPolicyComponent (taggedComponents[i], out);
                    break;
                }
                case TAG_NULL_TAG.value:
                {
                    out.println("\t#"+ i + ": TAG_NULL_TAG");
                    break;
                }
                case TAG_GROUP.value:
                {
                    out.println ("\t#" + i + ": TAG_GROUP");
                    printTagGroupTaggedComponent (taggedComponents[i], out);
                    break;
                }
                case TAG_RMI_CUSTOM_MAX_STREAM_FORMAT.value:
                {
                    out.println ("\t#" + i + ": TAG_GROUP");
                    printTagRMIComponent (taggedComponents[i], out);
                    break;
                }
                default:
                {
                    out.println("\tUnknown tag : " +
                            taggedComponents[i].tag);
                }
            }
        }
    }

    private static void printCSIMechComponent(TaggedComponent taggedComponent, PrintWriter out)
    {
        final CDRInputStream is = new CDRInputStream(taggedComponent.component_data);

        try
        {
            is.openEncapsulatedArray();
            CompoundSecMechList csmList = CompoundSecMechListHelper.read( is );

            if( csmList!= null )
            {
                out.println("\t\tis stateful: " + csmList.stateful );
                for( int i = 0; i < csmList.mechanism_list.length; i++ )
                {
                    out.println("\t\tCompoundSecMech #" + i);
                    out.println("\t\t\ttarget_requires: " +
                            csmList.mechanism_list[i].target_requires );
                    out.print("\t\t\ttransport mechanism tag: ");
                    switch( csmList.mechanism_list[i].transport_mech.tag )
                    {
                        case TAG_TLS_SEC_TRANS.value:
                        {
                            out.println("TAG_TLS_SEC_TRANS");
                            printTlsSecTrans(csmList.mechanism_list[i].transport_mech.component_data, out);
                            break;
                        }
                        case TAG_NULL_TAG.value:
                        {
                            out.println("TAG_NULL_TAG");
                            break;
                        }
                        default:
                        {
                            out.println("Unknown tag : " +
                                    csmList.mechanism_list[i].transport_mech.tag );
                        }
                    }
                    out.println("\t\t\tAS_ContextSec target_supports: " + csmList.mechanism_list[i].as_context_mech.target_supports );
                    out.println("\t\t\tAS_ContextSec target_requires: " + csmList.mechanism_list[i].as_context_mech.target_requires );
                    out.print("\t\t\tAS_ContextSec mech: " );
                    dumpHex(csmList.mechanism_list[i].as_context_mech.client_authentication_mech, out);
                    out.println();
                    out.print("\t\t\tAS_ContextSec target_name: " );
                    printNTExportedName(csmList.mechanism_list[i].as_context_mech.target_name, out);
                    out.println("\t\t\tSAS_ContextSec target_supports: " + csmList.mechanism_list[i].sas_context_mech.target_supports );
                    out.println("\t\t\tSAS_ContextSec target_requires: " + csmList.mechanism_list[i].sas_context_mech.target_requires );

                    for (int j = 0; j < csmList.mechanism_list[i].sas_context_mech.supported_naming_mechanisms.length; j++) {
                        out.print("\t\t\tSAS_ContextSec Naming mech: " );
                        dumpHex(csmList.mechanism_list[i].sas_context_mech.supported_naming_mechanisms[j], out);
                        out.println();
                    }
                    out.println("\t\t\tSAS_ContextSec Naming types: " + csmList.mechanism_list[i].sas_context_mech.supported_identity_types);
                    out.println();
                }
            }
        }
        finally
        {
            is.close();
        }
    }

    private static void printNTExportedName(byte[] nameData, PrintWriter out)
    {
        // check for token identifier
        if (nameData.length < 2 || nameData[0] != 0x04 || nameData[1] != 0x01)
        {
            dumpHex(nameData, out);
            out.println();
            return;
        }

        // get mech length
        int mechLen = (nameData[2] << 8) + (nameData[3] & 0xFF);
        if (mechLen > (nameData.length - 8))
        {
            dumpHex(nameData, out);
            out.println();
            return;
        }

        // get name length
        int nameLen = (nameData[mechLen + 4] << 24) +
                      (nameData[mechLen + 5] << 16) +
                      (nameData[mechLen + 6] << 8) +
                      (nameData[mechLen + 7]);
        if ((mechLen + nameLen) > (nameData.length - 8))
        {
            dumpHex(nameData, out);
            out.println();
            return;
        }
        byte[] name = new byte[nameLen];
        System.arraycopy(nameData, mechLen + 8, name, 0, nameLen);
        out.println(new String(name));
    }

    private static void printTlsSecTrans(byte[] tagData, PrintWriter out)
    {
        CDRInputStream in = new CDRInputStream(tagData );

        try
        {
            in.openEncapsulatedArray();
            TLS_SEC_TRANS tls = TLS_SEC_TRANSHelper.read( in );
            out.println("\t\t\tTLS SEC TRANS target requires: " + tls.target_requires);
            out.println("\t\t\tTLS SEC TRANS target supports: " + tls.target_supports);

            for (int i = 0; i < tls.addresses.length; i++)
            {
                int ssl_port = tls.addresses[i].port;
                if( ssl_port < 0 )
                {
                    ssl_port += 65536;
                }
                out.println("\t\t\tTLS SEC TRANS address: " + tls.addresses[i].host_name+":"+ssl_port);
            }
        }
        catch ( Exception ex )
        {
            out.print("\t\t\tTLS SEC TRANS: " );
            dumpHex(tagData, out);
            out.println();
        }
    }

    private static void printCodeSetComponent(TaggedComponent taggedComponent, PrintWriter out)
    {
        final CDRInputStream is = new CDRInputStream(taggedComponent.component_data);

        try
        {
            is.openEncapsulatedArray();

            org.omg.CONV_FRAME.CodeSetComponentInfo codeSet =
            CodeSetComponentInfoHelper.read( is );

            if( codeSet != null )
            {
                out.println("\t\tForChar native code set Id: " +
                            CodeSet.csName(codeSet.ForCharData.native_code_set ));
                out.print("\t\tChar Conversion Code Sets: ");
                for( int ji = 0; ji < codeSet.ForCharData.conversion_code_sets.length; ji++ )
                {
                    out.print( CodeSet.csName( codeSet.ForCharData.conversion_code_sets[ji] ) );

                    if( ji < (codeSet.ForCharData.conversion_code_sets.length - 1) )
                    {
                        out.print( ", " );
                    }
                }
                out.print("\n");

                out.println("\t\tForWChar native code set Id: " +
                            CodeSet.csName(codeSet.ForWcharData.native_code_set ));
                out.print("\t\tWChar Conversion Code Sets: ");
                for( int ji = 0; ji < codeSet.ForWcharData.conversion_code_sets.length; ji++ )
                {
                    out.print( CodeSet.csName( codeSet.ForWcharData.conversion_code_sets[ji] ));

                    if( ji < (codeSet.ForWcharData.conversion_code_sets.length - 1) )
                    {
                        out.print( ", " );
                    }
                }
                out.print("\n");
            }
        }
        finally
        {
            is.close();
        }
    }

    private static void printSSLTaggedComponent( TaggedComponent taggedComponent, PrintWriter out)
    {
        org.omg.SSLIOP.SSL  ssl = null;
        if( taggedComponent.tag == 20 )
        {
            CDRInputStream in = new CDRInputStream(taggedComponent.component_data );
            try
            {
                in.openEncapsulatedArray();
                ssl =  org.omg.SSLIOP.SSLHelper.read( in );
            }
            catch ( Exception ex )
            {
                return;
            }
            int ssl_port = ssl.port;
            if( ssl_port < 0 )
            {
                ssl_port += 65536;
            }

            out.print( "\t\ttarget_supports\t:\t" );
            //dump               ( ssl.target_supports );
            decodeAssociationOption( ssl.target_supports, out);
            out.println();
            out.print( "\t\ttarget_requires\t:\t" );
            //dump               ( ssl.target_requires );
            decodeAssociationOption( ssl.target_requires, out);
            out.println();
            out.println( "\t\tSSL Port\t:\t" + ssl_port );
        }
    }
    private static void decodeAssociationOption( int option, PrintWriter out)
    {
        boolean first = true;

        if( (option & org.omg.Security.NoProtection.value) != 0 )
        {
            if( ! first )
            {
                out.print( ", " );
            }

            out.print( "NoProtection" );

            first = false;
        }

        if( (option & org.omg.Security.Integrity.value) != 0 )
        {
            if( ! first )
            {
                out.print( ", " );
            }

            out.print( "Integrity" );

            first = false;
        }

        if( (option & org.omg.Security.Confidentiality.value) != 0 )
        {
            if( ! first )
            {
                out.print( ", " );
            }

            out.print( "Confidentiality" );

            first = false;
        }

        if( (option & org.omg.Security.DetectReplay.value) != 0 )
        {
            if( ! first )
            {
                out.print( ", " );
            }

            out.print( "DetectReplay" );

            first = false;
        }

        if( (option & org.omg.Security.DetectMisordering.value) != 0 )
        {
            if( ! first )
            {
                out.print( ", " );
            }

            out.print( "DetectMisordering" );

            first = false;
        }

        if( (option & org.omg.Security.EstablishTrustInTarget.value) != 0 )
        {
            if( ! first )
            {
                out.print( ", " );
            }

            out.print( "EstablishTrustInTarget" );

            first = false;
        }

        if( (option & org.omg.Security.EstablishTrustInClient.value) != 0 )
        {
            if( ! first )
            {
                out.print( ", " );
            }

            out.print( "EstablishTrustInClient" );

            first = false;
        }

        if( (option & org.omg.Security.NoDelegation.value) != 0 )
        {
            if( ! first )
            {
                out.print( ", " );
            }

            out.print( "NoDelegation" );

            first = false;
        }

        if( (option & org.omg.Security.SimpleDelegation.value) != 0 )
        {
            if( ! first )
            {
                out.print( ", " );
            }

            out.print( "SimpleDelegation" );

            first = false;
        }

        if( (option & org.omg.Security.CompositeDelegation.value) != 0 )
        {
            if( ! first )
            {
                out.print( ", " );
            }

            out.print( "CompositeDelegation" );

            first = false;
        }
    }


    private static void printJavaCodebaseComponent(TaggedComponent taggedComponent, PrintWriter out)
    {
        final CDRInputStream in = new CDRInputStream( taggedComponent.component_data );

        try
        {
            in.openEncapsulatedArray();
            String codebase = in.read_string();

            out.println( "\t\tCodebase: " + codebase );
        }
        finally
        {
            in.close();
        }
    }

    private static void printTagRMIComponent(TaggedComponent taggedComponent, PrintWriter out)
    {
        final CDRInputStream in = new CDRInputStream( taggedComponent.component_data );

        try
        {
            in.openEncapsulatedArray();
            byte b= in.read_octet();

            out.println( "\t\tTAG_RMI_CUSTOM_MAX_STREAM_FORMAT: " + Byte.toString(b));
        }
        finally
        {
            in.close();
        }
    }

    private static void printOrbTypeComponent (TaggedComponent taggedComponent, PrintWriter out)
    {
        final CDRInputStream is = new CDRInputStream (taggedComponent.component_data );

        try
        {
            is.openEncapsulatedArray ();
            int type = is.read_long ();

            out.print ( "\t\tType: " + type);
            if (type == ORBConstants.JACORB_ORB_ID)
            {
                out.println (" (JacORB)");
            }
            else if (type == ORBConstants.TAO_ORB_ID)
            {
                out.println (" (TAO)");
            }
            else
            {
                out.println (" (Foreign)");
            }
        }
        finally
        {
            is.close();
        }
    }

    private static void printAlternateAddress(ORB orb, TaggedComponent taggedComponent, PrintWriter out)
    {
        final CDRInputStream is = new CDRInputStream(taggedComponent.component_data);

        try
        {
            is.openEncapsulatedArray();
            String hostname = is.read_string();
            short port = is.read_ushort();

            IIOPAddress result = new IIOPAddress (hostname, port);
            try
            {
               result.configure(((org.jacorb.orb.ORB)orb).getConfiguration ());
            }
            catch( ConfigurationException ce)
            {
               ((org.jacorb.orb.ORB)orb).getConfiguration ().getLogger ("PrintIOR").warn("ConfigurationException", ce );
            }


            out.println("\t\tAddress: " + result.toString ());
        }
        finally
        {
            is.close();
        }
    }

    private static void printTagGroupTaggedComponent(TaggedComponent taggedComponent, PrintWriter out)
    {
        final CDRInputStream is = new CDRInputStream(org.omg.CORBA.ORBSingleton.init(), taggedComponent.component_data);

        is.openEncapsulatedArray();
        TagGroupTaggedComponent tagGroup = TagGroupTaggedComponentHelper.read (is);
        is.close ();

        out.println ("\t\tVersion: " + tagGroup.group_version.major + ":" + tagGroup.group_version.minor);
        out.println ("\t\tDomain: " + tagGroup.group_domain_id);
        out.println ("\t\tObjectGroupID: " + tagGroup.object_group_id);
        out.println ("\t\tObject Version: " + tagGroup.object_group_ref_version);
    }

    private static void dumpHex(byte values[], PrintWriter out)
    {
        for (int i=0; i<values.length; i++)
        {
            int n1 = (values[i] & 0xff) / 16;
            int n2 = (values[i] & 0xff) % 16;
            char c1 = (char)(n1>9 ? ('A'+(n1-10)) : ('0'+n1));
            char c2 = (char)(n2>9 ? ('A'+(n2-10)) : ('0'+n2));
            out.print(c1);
            out.print(c2);
            out.print(' ');
        }
    }



    private static void printPolicyComponent (TaggedComponent taggedComponent, PrintWriter out)
    {
        final CDRInputStream is = new CDRInputStream (taggedComponent.component_data);

        try
        {
            int val;
            int count = 0;

            is.openEncapsulatedArray ();
            int len = is.read_long ();

            while (len-- != 0)
            {
                val = is.read_long ();
                out.print( "\t\t#" + count++ + ": ");
                is.openEncapsulation ();
                switch (val)
                {
                    case PRIORITY_BANDED_CONNECTION_POLICY_TYPE.value:
                    {
                        long i;
                        short low;
                        short high;

                        out.println ("RTCORBA::PRIORITY_BANDED_CONNECTION");
                        val = is.read_long ();
                        for (i = 0; i < val; i++)
                        {
                            low = is.read_short ();
                            high = is.read_short ();
                            out.println ("\t\t\tBand " + i + ": " + low + "-" + high);
                        }
                        break;
                    }
                    case PRIORITY_MODEL_POLICY_TYPE.value:
                    {
                        out.print("RTCORBA::PRIORITY_MODEL");
                        val = is.read_long ();
                        switch (val)
                        {
                            case PriorityModel._CLIENT_PROPAGATED:
                            {
                                out.print (" (CLIENT_PROPAGATED, ");
                                break;
                            }
                            case PriorityModel._SERVER_DECLARED:
                            {
                                out.print (" (SERVER_DECLARED, ");
                                break;
                            }
                            default:
                            {
                                out.print (" (Unknown, ");
                                break;
                            }
                        }
                        short prio = is.read_short ();
                        out.println (prio + ")");
                        break;
                    }
                    default:
                    {
                        out.println ("Unknown (" + val + ")");
                        break;
                    }
                }
                is.closeEncapsulation ();
            }

        }
        finally
        {
            is.close();
        }
    }
}
