/*jadclipse*/// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) radix(10) lradix(10) 
// Source File Name:   PipeParser.java


package gov.va.med.cds.hapi.extension;


import java.util.ArrayList;
import java.util.StringTokenizer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import ca.uhn.hl7v2.ErrorCode;
import ca.uhn.hl7v2.HL7Exception;
import ca.uhn.hl7v2.model.Group;
import ca.uhn.hl7v2.model.Message;
import ca.uhn.hl7v2.model.Primitive;
import ca.uhn.hl7v2.model.Segment;
import ca.uhn.hl7v2.model.Structure;
import ca.uhn.hl7v2.model.Type;
import ca.uhn.hl7v2.model.Varies;
import ca.uhn.hl7v2.parser.DefaultEscaping;
import ca.uhn.hl7v2.parser.EncodingCharacters;
import ca.uhn.hl7v2.parser.EncodingNotSupportedException;
import ca.uhn.hl7v2.parser.Escaping;
import ca.uhn.hl7v2.parser.Parser;
import ca.uhn.hl7v2.util.FilterIterator;
import ca.uhn.hl7v2.util.MessageIterator;
import ca.uhn.hl7v2.util.Terser;


// Referenced classes of package ca.uhn.hl7v2.parser:
//            Parser, EncodingCharacters, EncodingNotSupportedException, Escape
/***********************************************************************************************************************
 * CustomLabParser supports creation of a Parser that supports a custom ModelClassFactory, and thus custom Message and
 * Segment classes.
 */
public class CustomLabParser
    extends
        Parser
{
	private static final Escaping ESCAPE = new DefaultEscaping();
	
	private static class MessageStructure
    {

        public String messageStructure;
        public boolean explicitlyDefined;


        public MessageStructure( String theMessageStructure, boolean isExplicitlyDefined )
        {
            messageStructure = theMessageStructure;
            explicitlyDefined = isExplicitlyDefined;
        }
    }


    public CustomLabParser( )
    {
        super( new LabModelClassFactory() );
    }


    public String getEncoding( String message )
    {
        String encoding = null;
        if ( message.length() < 4 )
            return null;
        boolean ok = true;
        if ( !message.startsWith( "MSH" ) )
            return null;
        char fourthChar = message.charAt( 3 );
        for ( StringTokenizer st = new StringTokenizer( message, String.valueOf( "\r" ), false ); st.hasMoreTokens(); )
        {
            String x = st.nextToken();
            if ( x.length() > 0 )
            {
                if ( Character.isWhitespace( x.charAt( 0 ) ) )
                    x = stripLeadingWhitespace( x );
                if ( x.length() >= 4 && x.charAt( 3 ) != fourthChar )
                    return null;
            }
        }

        int nextFieldDelimLoc = 0;
        for ( int i = 0; i < 11; i++ )
        {
            nextFieldDelimLoc = message.indexOf( fourthChar, nextFieldDelimLoc + 1 );
            if ( nextFieldDelimLoc < 0 )
                return null;
        }

        if ( ok )
            encoding = "VB";
        return encoding;
    }


    public String getDefaultEncoding( )
    {
        return "VB";
    }


    public boolean supportsEncoding( String encoding )
    {
        boolean supports = false;
        if ( encoding != null && encoding.equals( "VB" ) )
            supports = true;
        return supports;
    }


    /**
     * @deprecated Method getMessageStructure is deprecated
     */

    public String getMessageStructure( String message )
        throws HL7Exception,
            EncodingNotSupportedException
    {
        return getStructure( message ).messageStructure;
    }


    private MessageStructure getStructure( String message )
        throws HL7Exception,
            EncodingNotSupportedException
    {
        EncodingCharacters ec = getEncodingChars( message );
        String messageStructure = null;
        boolean explicityDefined = true;
        try
        {
            String fields[] = split( message.substring( 0, Math.max( message.indexOf( "\r" ), message.length() ) ), String.valueOf( ec
                            .getFieldSeparator() ) );
            String wholeFieldNine = fields[8];
            String comps[] = split( wholeFieldNine, String.valueOf( ec.getComponentSeparator() ) );
            if ( comps.length >= 3 )
                messageStructure = comps[2];
            else if ( comps.length > 0 && comps[0] != null && comps[0].equals( "ACK" ) )
                messageStructure = "ACK";
            else if ( comps.length == 2 )
            {
                explicityDefined = false;
                messageStructure = comps[0] + "_" + comps[1];
            }
            else
            {
                StringBuffer buf = new StringBuffer( "Can't determine message structure from MSH-9: " );
                buf.append( wholeFieldNine );
                if ( comps.length < 3 )
                {
                    buf.append( " HINT: there are only " );
                    buf.append( comps.length );
                    buf.append( " of 3 components present" );
                }
                throw new HL7Exception( buf.toString(), ErrorCode.UNSUPPORTED_MESSAGE_TYPE);
            }
        }
        catch ( IndexOutOfBoundsException e )
        {
            throw new HL7Exception( "Can't find message structure (MSH-9-3): " + e.getMessage(), ErrorCode.UNSUPPORTED_MESSAGE_TYPE );
        }
        return new MessageStructure( messageStructure, explicityDefined );
    }


    private static EncodingCharacters getEncodingChars( String message )
    {
        return new EncodingCharacters( message.charAt( 3 ), message.substring( 4, 8 ) );
    }


    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Override
	protected Message doParse( String message, String version )
        throws HL7Exception,
            EncodingNotSupportedException
    {
        MessageStructure structure = getStructure( message );
        Message m = instantiateMessage( structure.messageStructure, version, structure.explicitlyDefined );
        MessageIterator messageIter = new MessageIterator( m, "MSH", true );
        ca.uhn.hl7v2.util.FilterIterator.Predicate segmentsOnly = new ca.uhn.hl7v2.util.FilterIterator.Predicate()
        {

            public boolean evaluate( Object obj )
            {
                try
                {
                    return ( CustomLabParser.class$ca$uhn$hl7v2$model$Segment != null ? CustomLabParser.class$ca$uhn$hl7v2$model$Segment
                                    : ( CustomLabParser.class$ca$uhn$hl7v2$model$Segment = CustomLabParser._mthclass$( "ca.uhn.hl7v2.model.Segment" ) ) )
                                    .isAssignableFrom( obj.getClass() );
                }
                catch ( Throwable e )
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                return false;
            }

        };
        FilterIterator segmentIter = new FilterIterator( messageIter, segmentsOnly );
        String segments[] = split( message, "\r" );
        char delim = '|';
        for ( int i = 0; i < segments.length; i++ )
        {
            if ( segments[i] != null && segments[i].length() > 0 && Character.isWhitespace( segments[i].charAt( 0 ) ) )
                segments[i] = stripLeadingWhitespace( segments[i] );
            if ( segments[i] == null || segments[i].length() < 3 )
                continue;
            final String name;
            if ( i == 0 )
            {
                name = segments[i].substring( 0, 3 );
                delim = segments[i].charAt( 3 );
            }
            else
            {
                name = segments[i].substring( 0, segments[i].indexOf( delim ) );
            }
            log.debug( "Parsing segment " + name );
            messageIter.setDirection( name );
            ca.uhn.hl7v2.util.FilterIterator.Predicate byDirection = new ca.uhn.hl7v2.util.FilterIterator.Predicate()
            {

                public boolean evaluate( Object obj )
                {
                    Structure s = ( Structure )obj;
                    CustomLabParser.log.debug( "PipeParser iterating message in direction " + name + " at " + s.getName() );
                    return s.getName().matches( name + "\\d*" );
                }
            };
            FilterIterator dirIter = new FilterIterator( segmentIter, byDirection );
            if ( dirIter.hasNext() )
                parse( ( Segment )dirIter.next(), segments[i], getEncodingChars( message ) );
        }

        return m;
    }

    private static boolean isDelimDefSegment( String theSegmentName )
    {
        boolean is = false;
        if ( theSegmentName.equals( "MSH" ) || theSegmentName.equals( "FHS" ) || theSegmentName.equals( "BHS" ) )
            is = true;
        return is;
    }


    @SuppressWarnings("unused")
	private static char getSeparator( boolean subComponents, EncodingCharacters encodingChars )
    {
        char separator;
        if ( subComponents )
            separator = encodingChars.getSubcomponentSeparator();
        else
            separator = encodingChars.getComponentSeparator();
        return separator;
    }


    public static String[] split( String composite, String delim )
    {
        ArrayList<String> components = new ArrayList<String>();
        if ( composite == null )
            composite = "";
        if ( delim == null )
            delim = "";
        StringTokenizer tok = new StringTokenizer( composite, delim, true );
        boolean previousTokenWasDelim = true;
        while ( tok.hasMoreTokens() )
        {
            String thisTok = tok.nextToken();
            if ( thisTok.equals( delim ) )
            {
                if ( previousTokenWasDelim )
                    components.add( null );
                previousTokenWasDelim = true;
            }
            else
            {
                components.add( thisTok );
                previousTokenWasDelim = false;
            }
        }
        String ret[] = new String[components.size()];
        for ( int i = 0; i < components.size(); i++ )
            ret[i] = ( String )components.get( i );

        return ret;
    }


    public static String encode( Type source, EncodingCharacters encodingChars )
    {
        StringBuffer field = new StringBuffer();
        for ( int i = 1; i <= Terser.numComponents( source ); i++ )
        {
            StringBuffer comp = new StringBuffer();
            for ( int j = 1; j <= Terser.numSubComponents( source, i ); j++ )
            {
                Primitive p = Terser.getPrimitive( source, i, j );
                comp.append( encodePrimitive( p, encodingChars ) );
                comp.append( encodingChars.getSubcomponentSeparator() );
            }

            field.append( stripExtraDelimiters( comp.toString(), encodingChars.getSubcomponentSeparator() ) );
            field.append( encodingChars.getComponentSeparator() );
        }

        return stripExtraDelimiters( field.toString(), encodingChars.getComponentSeparator() );
    }


    private static String encodePrimitive( Primitive p, EncodingCharacters encodingChars )
    {
        String val = p.getValue();
        if ( val == null )
            val = "";
        else
            val = ESCAPE.escape( val, encodingChars );
        return val;
    }


    private static String stripExtraDelimiters( String in, char delim )
    {
        char chars[] = in.toCharArray();
        int c = chars.length - 1;
        boolean found = false;
        do
        {
            if ( c < 0 || found )
                break;
            if ( chars[c-- ] != delim )
                found = true;
        }
        while ( true );
        String ret = "";
        if ( found )
            ret = String.valueOf( chars, 0, c + 2 );
        return ret;
    }


    

    public static String encode( Group source, EncodingCharacters encodingChars )
        throws HL7Exception
    {
        StringBuffer result = new StringBuffer();
        String names[] = source.getNames();
        for ( int i = 0; i < names.length; i++ )
        {
            Structure reps[] = source.getAll( names[i] );
            for ( int rep = 0; rep < reps.length; rep++ )
            {
                if ( reps[rep] instanceof Group )
                {
                    result.append( encode( ( Group )reps[rep], encodingChars ) );
                    continue;
                }
                String segString = encode( ( Segment )reps[rep], encodingChars );
                if ( segString.length() >= 4 )
                {
                    result.append( segString );
                    result.append( '\r' );
                }
            }

        }

        return result.toString();
    }


    public static String encode( Segment source, EncodingCharacters encodingChars )
    {
        StringBuffer result = new StringBuffer();
        result.append( source.getName() );
        result.append( encodingChars.getFieldSeparator() );
        int startAt = 1;
        if ( isDelimDefSegment( source.getName() ) )
            startAt = 2;
        int numFields = source.numFields();
        for ( int i = startAt; i <= numFields; i++ )
        {
            try
            {
                Type reps[] = source.getField( i );
                for ( int j = 0; j < reps.length; j++ )
                {
                    String fieldText = encode( reps[j], encodingChars );
                    if ( isDelimDefSegment( source.getName() ) && i == 2 )
                        fieldText = ESCAPE.unescape( fieldText, encodingChars );
                    result.append( fieldText );
                    if ( j < reps.length - 1 )
                        result.append( encodingChars.getRepetitionSeparator() );
                }

            }
            catch ( HL7Exception e )
            {
                log.error( "Error while encoding segment: ", e );
            }
            result.append( encodingChars.getFieldSeparator() );
        }

        return stripExtraDelimiters( result.toString(), encodingChars.getFieldSeparator() );
    }


    public static String stripLeadingWhitespace( String in )
    {
        StringBuffer out = new StringBuffer();
        char chars[] = in.toCharArray();
        int c;
        for ( c = 0; c < chars.length && Character.isWhitespace( chars[c] ); c++ )
            ;
        for ( int i = c; i < chars.length; i++ )
            out.append( chars[i] );

        return out.toString();
    }


    public Segment getCriticalResponseData( String message )
        throws HL7Exception
    {
        int locStartMSH = message.indexOf( "MSH" );
        if ( locStartMSH < 0 )
            throw new HL7Exception( "Couldn't find MSH segment in message: " + message, ErrorCode.SEGMENT_SEQUENCE_ERROR );
        int locEndMSH = message.indexOf( '\r', locStartMSH + 1 );
        if ( locEndMSH < 0 )
            locEndMSH = message.length();
        String mshString = message.substring( locStartMSH, locEndMSH );
        char fieldSep = mshString.charAt( 3 );
        String fields[] = split( mshString, String.valueOf( fieldSep ) );
        Segment msh = null;
        try
        {
            String encChars = fields[1];
            char compSep = encChars.charAt( 0 );
            String messControlID = fields[9];
            String procIDComps[] = split( fields[10], String.valueOf( compSep ) );
            String version = "2.4";
            try
            {
                version = getVersion( message );
            }
            catch ( Exception e )
            {
            }
            msh = Parser.makeControlMSH( version, getFactory() );
            Terser.set( msh, 1, 0, 1, 1, String.valueOf( fieldSep ) );
            Terser.set( msh, 2, 0, 1, 1, encChars );
            Terser.set( msh, 10, 0, 1, 1, messControlID );
            Terser.set( msh, 11, 0, 1, 1, procIDComps[0] );
            Terser.set( msh, 12, 0, 1, 1, version );
        }
        catch ( Exception e )
        {
            throw new HL7Exception( "Can't parse critical fields from MSH segment (" + e.getClass().getName() + ": " + e.getMessage() + "): "
                            + mshString, ErrorCode.REQUIRED_FIELD_MISSING, e );
        }
        return msh;
    }


    public String getAckID( String message )
    {
        String ackID = null;
        int startMSA = message.indexOf( "\rMSA" );
        if ( startMSA >= 0 )
        {
            int startFieldOne = startMSA + 5;
            char fieldDelim = message.charAt( startFieldOne - 1 );
            int start = message.indexOf( fieldDelim, startFieldOne ) + 1;
            int end = message.indexOf( fieldDelim, start );
            int segEnd = message.indexOf( String.valueOf( "\r" ), start );
            if ( segEnd > start && segEnd < end )
                end = segEnd;
            if ( end < 0 )
                if ( message.charAt( message.length() - 1 ) == '\r' )
                    end = message.length() - 1;
                else
                    end = message.length();
            if ( start > 0 && end > start )
                ackID = message.substring( start, end );
        }
        log.debug( "ACK ID: " + ackID );
        return ackID;
    }


    public String getVersion( String message )
        throws HL7Exception
    {
        int startMSH = message.indexOf( "MSH" );
        int endMSH = message.indexOf( "\r", startMSH );
        if ( endMSH < 0 )
            endMSH = message.length();
        String msh = message.substring( startMSH, endMSH );
        String fieldSep = null;
        if ( msh.length() > 3 )
            fieldSep = String.valueOf( msh.charAt( 3 ) );
        else
            throw new HL7Exception( "Can't find field separator in MSH: " + msh, ErrorCode.UNSUPPORTED_VERSION_ID );
        String fields[] = split( msh, fieldSep );
        String compSep = null;
        if ( fields.length >= 2 && fields[1] != null && fields[1].length() == 4 )
            compSep = String.valueOf( fields[1].charAt( 0 ) );
        else
            throw new HL7Exception( "Invalid or incomplete encoding characters - MSH-2 is " + fields[1], ErrorCode.REQUIRED_FIELD_MISSING );
        String version = null;
        if ( fields.length >= 12 )
        {
            String comp[] = split( fields[11], compSep );
            if ( comp.length >= 1 )
                version = comp[0];
            else
                throw new HL7Exception( "Can't find version ID - MSH.12 is " + fields[11], ErrorCode.REQUIRED_FIELD_MISSING );
        }
        else
        {
            throw new HL7Exception( "Can't find version ID - MSH has only " + fields.length + " fields.", ErrorCode.REQUIRED_FIELD_MISSING );
        }
        return version;
    }


    @SuppressWarnings("rawtypes")
	static Class _mthclass$( String x0 )
        throws Throwable
    {
        try
        {
            return Class.forName( x0 );
        }
        catch ( ClassNotFoundException x1 )
        {
            throw ( new NoClassDefFoundError() ).initCause( x1 );
        }
    }

    private static Log log;
    //private static final String segDelim = "\r";
    static Class<?> class$ca$uhn$hl7v2$model$Segment; /* synthetic field */

    static
    {
        log = LogFactory.getLog( CustomLabParser.class );
    }

	@Override
	public String doEncode(Segment structure, EncodingCharacters encodingCharacters) throws HL7Exception {
		// TODO Auto-generated method stub
		return encode(structure, encodingCharacters);
	}


	@Override
	public String doEncode(Type type, EncodingCharacters encodingCharacters) throws HL7Exception {
		// TODO Auto-generated method stub
		return encode(type, encodingCharacters);
	}
	
	protected String doEncode( Message source, String encoding )
	        throws HL7Exception,
	            EncodingNotSupportedException
	 {
	      if ( !supportsEncoding( encoding ) ){
	           throw new EncodingNotSupportedException( "This parser does not support the " + encoding + " encoding" );
	      }
	      else{
	           return encode( source );
	      }
	  }

		@Override
	    protected String doEncode( Message source )
	        throws HL7Exception
	    {
	        Segment msh = ( Segment )source.get( "MSH" );
	        String fieldSepString = Terser.get( msh, 1, 0, 1, 1 );
	        if ( fieldSepString == null )
	            throw new HL7Exception( "Can't encode message: MSH-1 (field separator) is missing" );
	        char fieldSep = '|';
	        if ( fieldSepString != null && fieldSepString.length() > 0 )
	            fieldSep = fieldSepString.charAt( 0 );
	        String encCharString = Terser.get( msh, 2, 0, 1, 1 );
	        if ( encCharString == null )
	            throw new HL7Exception( "Can't encode message: MSH-2 (encoding characters) is missing" );
	        if ( encCharString.length() != 4 )
	        {
	            throw new HL7Exception( "Encoding characters '" + encCharString + "' invalid -- must be 4 characters", ErrorCode.DATA_TYPE_ERROR );
	        }
	        else
	        {
	            EncodingCharacters en = new EncodingCharacters( fieldSep, encCharString );
	            return encode( source, en );
	        }
	    }
	
	    public void parse( Segment destination, String segment, EncodingCharacters encodingChars )
	            throws HL7Exception
	        {
	            int fieldOffset = 0;
	            if ( isDelimDefSegment( destination.getName() ) )
	            {
	                fieldOffset = 1;
	                Terser.set( destination, 1, 0, 1, 1, String.valueOf( encodingChars.getFieldSeparator() ) );
	            }
	            String fields[] = split( segment, String.valueOf( encodingChars.getFieldSeparator() ) );
	            for ( int i = 1; i < fields.length; i++ )
	            {
	                String reps[] = split( fields[i], String.valueOf( encodingChars.getRepetitionSeparator() ) );
	                if ( log.isDebugEnabled() )
	                    log.debug( reps.length + "reps delimited by: " + encodingChars.getRepetitionSeparator() );
	                boolean isMSH2 = isDelimDefSegment( destination.getName() ) && i + fieldOffset == 2;
	                if ( isMSH2 )
	                {
	                    reps = new String[1];
	                    reps[0] = fields[i];
	                }
	                for ( int j = 0; j < reps.length; j++ )
	                    try
	                    {
	                        StringBuffer statusMessage = new StringBuffer( "Parsing field " );
	                        statusMessage.append( i + fieldOffset );
	                        statusMessage.append( " repetition " );
	                        statusMessage.append( j );
	                        log.debug( statusMessage.toString() );
	                        Type field = destination.getField( i + fieldOffset, j );
	                        if ( isMSH2 )
	                            Terser.getPrimitive( field, 1, 1 ).setValue( reps[j] );
	                        else
	                            parse( field, reps[j], encodingChars );
	                        continue;
	                    }
	                    catch ( HL7Exception e )
	                    {
	                        e.setFieldPosition( i );
	                        e.setSegmentRepetition( MessageIterator.getIndex( destination.getParent(), destination ).rep );
	                        e.setSegmentName( destination.getName() );
	                        throw e;
	                    }

	            }

	            if ( destination.getClass().getName().indexOf( "OBX" ) >= 0 )
	                Varies.fixOBX5( destination, getFactory() );
	 }

	@Override
	public void parse( Type destinationField, String data, EncodingCharacters encodingCharacters )
	        throws HL7Exception
	    {
	        String components[] = split( data, String.valueOf( encodingCharacters.getComponentSeparator() ) );
	        for ( int i = 0; i < components.length; i++ )
	        {
	            String subcomponents[] = split( components[i], String.valueOf( encodingCharacters.getSubcomponentSeparator() ) );
	            for ( int j = 0; j < subcomponents.length; j++ )
	            {
	                String val = subcomponents[j];
	                if ( val != null )
	                    val = ESCAPE.unescape( val, encodingCharacters );
	                Terser.getPrimitive( destinationField, i + 1, j + 1 ).setValue( val );
	            }

	        }

	    }


	@Override
	public void parse(Message message, String string) throws HL7Exception {
		// TODO Auto-generated method stub
		//not used
		
	}
	
	
	@Override
	protected Message doParseForSpecificPackage(String arg0, String arg1, String arg2) throws HL7Exception {
		// TODO Auto-generated method stub
		return null;
	}

}
