

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


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.Composite;
import ca.uhn.hl7v2.model.DataTypeException;
import ca.uhn.hl7v2.model.GenericComposite;
import ca.uhn.hl7v2.model.Message;
import ca.uhn.hl7v2.model.Primitive;
import ca.uhn.hl7v2.model.Segment;
import ca.uhn.hl7v2.model.Type;
import ca.uhn.hl7v2.model.Varies;
import ca.uhn.hl7v2.util.SegmentFinder;


public class CustomTerser
{
    private class PathSpec
    {
        public String pattern;
        public boolean isGroup;
        public boolean find;
        public int rep;


        private PathSpec( )
        {
            /* 400 */super();
        }
    }


    public CustomTerser( Message message )
    {
        /* <-MISALIGNED-> *//* 78 */finder = new SegmentFinder( message );
    }


    public static String get( Segment segment, int field, int rep, int component, int subcomponent )
        throws HL7Exception
    {
        /* <-MISALIGNED-> *//* 90 */Primitive prim = getPrimitive( segment, field, rep, component, subcomponent );
        /* <-MISALIGNED-> *//* 91 */return prim.getValue();
    }


    public static void set( Segment segment, int field, int rep, int component, int subcomponent, String value )
        throws HL7Exception
    {
        /* <-MISALIGNED-> *//* 98 */Primitive prim = getPrimitive( segment, field, rep, component, subcomponent );
        /* <-MISALIGNED-> *//* 99 */prim.setValue( value );
    }


    private static Primitive getPrimitive( Segment segment, int field, int rep, int component, int subcomponent )
        throws HL7Exception
    {
        /* <-MISALIGNED-> *//* 106 */Type type = segment.getField( field, rep );
        /* <-MISALIGNED-> *//* 107 */return getPrimitive( type, component, subcomponent );
    }


    public static Primitive getPrimitive( Type type, int component, int subcomponent )
    {
        /* <-MISALIGNED-> *//* 117 */Type comp = getComponent( type, component );
        /* <-MISALIGNED-> *//* 118 */Type sub = getComponent( comp, subcomponent );
        /* <-MISALIGNED-> *//* 119 */return getPrimitive( sub );
    }


    private static Primitive getPrimitive( Type type )
    {
        /* <-MISALIGNED-> *//* 127 */Primitive p = null;
        /* <-MISALIGNED-> *//* 128 */if ( ( ca.uhn.hl7v2.model.Varies.class ).isAssignableFrom( type.getClass() ) )
            /* <-MISALIGNED-> *//* 129 */p = getPrimitive( ( ( Varies )type ).getData() );
        /* <-MISALIGNED-> *//* 130 */else
        /* <-MISALIGNED-> *//* 130 */if ( ( ca.uhn.hl7v2.model.Composite.class ).isAssignableFrom( type.getClass() ) )
            /* <-MISALIGNED-> *//* 132 */try
            {
                /* <-MISALIGNED-> *//* 132 */p = getPrimitive( ( ( Composite )type ).getComponent( 0 ) );
            }
            /* <-MISALIGNED-> *//* 133 */catch ( HL7Exception e )
            {
                /* <-MISALIGNED-> *//* 134 */throw new Error( "Internal error: HL7Exception thrown on Composite.getComponent(0)." );
            }
        /* <-MISALIGNED-> *//* 136 */else
        /* <-MISALIGNED-> *//* 136 */if ( type instanceof Primitive )
            /* <-MISALIGNED-> *//* 137 */p = ( Primitive )type;
        /* <-MISALIGNED-> *//* 139 */return p;
    }


    private static Type getComponent( Type type, int comp )
    {
        /* <-MISALIGNED-> *//* 151 */Type ret = null;
        /* <-MISALIGNED-> *//* 152 */if ( ( ca.uhn.hl7v2.model.Varies.class ).isAssignableFrom( type.getClass() ) )
        {
            /* <-MISALIGNED-> *//* 153 */Varies v = ( Varies )type;
            /* <-MISALIGNED-> *//* 156 */try
            {
                /* <-MISALIGNED-> *//* 156 */if ( comp > 1
                                && ( ca.uhn.hl7v2.model.GenericPrimitive.class ).isAssignableFrom( v.getData().getClass() ) )
                    /* <-MISALIGNED-> *//* 157 */v.setData( new GenericComposite( v.getMessage() ) );
            }
            /* <-MISALIGNED-> *//* 158 */catch ( DataTypeException de )
            {
                /* <-MISALIGNED-> *//* 159 */String message = "Unexpected exception copying data to generic composite: " + de.getMessage();
                /* <-MISALIGNED-> *//* 160 */log.error( message, de );
                /* <-MISALIGNED-> *//* 161 */throw new Error( message );
            }
            /* <-MISALIGNED-> *//* 164 */ret = getComponent( v.getData(), comp );
        }
        else
        /* <-MISALIGNED-> *//* 166 */if ( ( ca.uhn.hl7v2.model.Primitive.class ).isAssignableFrom( type.getClass() ) && comp == 1 )
            /* <-MISALIGNED-> *//* 167 */ret = type;
        /* <-MISALIGNED-> *//* 168 */else
        /* <-MISALIGNED-> *//* 168 */if ( ( ca.uhn.hl7v2.model.GenericComposite.class ).isAssignableFrom( type.getClass() )
                        || ( ca.uhn.hl7v2.model.Composite.class ).isAssignableFrom( type.getClass() ) && comp <= numStandardComponents( type ) )
            /* <-MISALIGNED-> *//* 173 */try
            {
                /* <-MISALIGNED-> *//* 173 */ret = ( ( Composite )type ).getComponent( comp - 1 );
            }
            /* <-MISALIGNED-> *//* 174 */catch ( Exception e )
            {
                /* <-MISALIGNED-> *//* 175 */throw new Error(
                                "Internal error: HL7Exception thrown on getComponent(x) where x < # standard components.", e );
            }
        /* <-MISALIGNED-> *//* 178 */else
            /* <-MISALIGNED-> *//* 178 */ret = type.getExtraComponents().getComponent( comp - numStandardComponents( type ) - 1 );
        /* <-MISALIGNED-> *//* 181 */return ret;
    }


    public String get( String spec )
        throws HL7Exception
    {
        /* <-MISALIGNED-> *//* 193 */StringTokenizer tok = new StringTokenizer( spec, "-", false );
        /* <-MISALIGNED-> *//* 194 */Segment segment = getSegment( tok.nextToken() );
        /* <-MISALIGNED-> *//* 196 */int ind[] = getIndices( spec );
        /* <-MISALIGNED-> *//* 197 */return get( segment, ind[0], ind[1], ind[2], ind[3] );
    }


    public Segment getSegment( String segSpec )
        throws HL7Exception
    {
        /* <-MISALIGNED-> *//* 204 */Segment seg = null;
        /* <-MISALIGNED-> *//* 206 */if ( segSpec.substring( 0, 1 ).equals( "/" ) )
            /* <-MISALIGNED-> *//* 207 */getFinder().reset();
        /* <-MISALIGNED-> *//* 210 */StringTokenizer tok = new StringTokenizer( segSpec, "/", false );
        /* <-MISALIGNED-> *//* 211 */SegmentFinder finder = getFinder();
        /* <-MISALIGNED-> *//* 212 */while ( tok.hasMoreTokens() )
        {
            /* <-MISALIGNED-> *//* 213 */String pathSpec = tok.nextToken();
            /* <-MISALIGNED-> *//* 214 */PathSpec ps = parsePathSpec( pathSpec );
            /* <-MISALIGNED-> *//* 215 */if ( tok.hasMoreTokens() )
                /* <-MISALIGNED-> *//* 216 */ps.isGroup = true;
            /* <-MISALIGNED-> *//* 218 */else
                /* <-MISALIGNED-> *//* 218 */ps.isGroup = false;
            /* <-MISALIGNED-> *//* 221 */if ( ps.isGroup )
            {
                /* <-MISALIGNED-> *//* 222 */ca.uhn.hl7v2.model.Group g = null;
                /* <-MISALIGNED-> *//* 223 */if ( ps.find )
                    /* <-MISALIGNED-> *//* 224 */g = finder.findGroup( ps.pattern, ps.rep );
                /* <-MISALIGNED-> *//* 226 */else
                    /* <-MISALIGNED-> *//* 226 */g = finder.getGroup( ps.pattern, ps.rep );
                /* <-MISALIGNED-> *//* 228 */finder = new SegmentFinder( g );
            }
            else
            /* <-MISALIGNED-> *//* 230 */if ( ps.find )
                /* <-MISALIGNED-> *//* 231 */seg = finder.findSegment( ps.pattern, ps.rep );
            /* <-MISALIGNED-> *//* 233 */else
                /* <-MISALIGNED-> *//* 233 */seg = finder.getSegment( ps.pattern, ps.rep );
        }
        /* <-MISALIGNED-> *//* 238 */return seg;
    }


    private PathSpec parsePathSpec( String spec )
        throws HL7Exception
    {
        /* <-MISALIGNED-> *//* 243 */PathSpec ps = new PathSpec();
        /* <-MISALIGNED-> *//* 245 */if ( spec.startsWith( "." ) )
        {
            /* <-MISALIGNED-> *//* 246 */ps.find = true;
            /* <-MISALIGNED-> *//* 247 */spec = spec.substring( 1 );
        }
        else
        {
            /* <-MISALIGNED-> *//* 249 */ps.find = false;
        }
        /* <-MISALIGNED-> *//* 252 */if ( spec.length() == 0 )
            /* <-MISALIGNED-> *//* 253 */throw new HL7Exception( "Invalid path (some path element is either empty or contains only a dot)" );
        /* <-MISALIGNED-> *//* 255 */StringTokenizer tok = new StringTokenizer( spec, "()", false );
        /* <-MISALIGNED-> *//* 256 */ps.pattern = tok.nextToken();
        /* <-MISALIGNED-> *//* 257 */if ( tok.hasMoreTokens() )
        {
            /* <-MISALIGNED-> *//* 258 */String repString = tok.nextToken();
            /* <-MISALIGNED-> *//* 260 */try
            {
                /* <-MISALIGNED-> *//* 260 */ps.rep = Integer.parseInt( repString );
            }
            /* <-MISALIGNED-> *//* 261 */catch ( NumberFormatException e )
            {
                /* <-MISALIGNED-> *//* 262 */throw new HL7Exception( repString + " is not a valid rep #", ErrorCode.APPLICATION_INTERNAL_ERROR );
            }
        }
        else
        {
            /* <-MISALIGNED-> *//* 265 */ps.rep = 0;
        }
        /* <-MISALIGNED-> *//* 267 */return ps;
    }


    public static int[] getIndices( String spec )
        throws HL7Exception
    {
        /* <-MISALIGNED-> *//* 275 */StringTokenizer tok = new StringTokenizer( spec, "-", false );
        /* <-MISALIGNED-> *//* 276 */tok.nextToken();
        /* <-MISALIGNED-> *//* 277 */if ( !tok.hasMoreTokens() )
            /* <-MISALIGNED-> *//* 278 */throw new HL7Exception( "Must specify field in spec " + spec, ErrorCode.APPLICATION_INTERNAL_ERROR );
        /* <-MISALIGNED-> *//* 280 */int ret[] = null;
        /* <-MISALIGNED-> *//* 282 */try
        {
            /* <-MISALIGNED-> *//* 282 */StringTokenizer fieldSpec = new StringTokenizer( tok.nextToken(), "()", false );
            /* <-MISALIGNED-> *//* 283 */int fieldNum = Integer.parseInt( fieldSpec.nextToken() );
            /* <-MISALIGNED-> *//* 284 */int fieldRep = 0;
            /* <-MISALIGNED-> *//* 285 */if ( fieldSpec.hasMoreTokens() )
                /* <-MISALIGNED-> *//* 286 */fieldRep = Integer.parseInt( fieldSpec.nextToken() );
            /* <-MISALIGNED-> *//* 289 */int component = 1;
            /* <-MISALIGNED-> *//* 290 */if ( tok.hasMoreTokens() )
                /* <-MISALIGNED-> *//* 291 */component = Integer.parseInt( tok.nextToken() );
            /* <-MISALIGNED-> *//* 294 */int subcomponent = 1;
            /* <-MISALIGNED-> *//* 295 */if ( tok.hasMoreTokens() )
                /* <-MISALIGNED-> *//* 296 */subcomponent = Integer.parseInt( tok.nextToken() );
            /* <-MISALIGNED-> *//* 298 */int result[] = {
            /* <-MISALIGNED-> *//* 298 */fieldNum, fieldRep, component, subcomponent };
            /* <-MISALIGNED-> *//* 299 */ret = result;
        }
        /* <-MISALIGNED-> *//* 300 */catch ( NumberFormatException e )
        {
            /* <-MISALIGNED-> *//* 301 */throw new HL7Exception( "Invalid integer in spec " + spec, ErrorCode.APPLICATION_INTERNAL_ERROR );
        }
        /* <-MISALIGNED-> *//* 304 */return ret;
    }


    public void set( String spec, String value )
        throws HL7Exception
    {
        /* <-MISALIGNED-> *//* 311 */StringTokenizer tok = new StringTokenizer( spec, "-", false );
        /* <-MISALIGNED-> *//* 312 */Segment segment = getSegment( tok.nextToken() );
        /* <-MISALIGNED-> *//* 314 */int ind[] = getIndices( spec );
        /* <-MISALIGNED-> *//* 315 */if ( log.isDebugEnabled() )
            /* <-MISALIGNED-> *//* 316 */log.debug( "Setting " + spec + " seg: " + segment.getName() + " ind: " + ind[0] + " " + ind[1] + " "
                            + ind[2] + " " + ind[3] );
        /* <-MISALIGNED-> *//* 318 */set( segment, ind[0], ind[1], ind[2], ind[3], value );
    }


    public static int numSubComponents( Type type, int component )
    {
        /* <-MISALIGNED-> *//* 338 */int n = -1;
        /* <-MISALIGNED-> *//* 339 */if ( component == 1 && ( ca.uhn.hl7v2.model.Primitive.class ).isAssignableFrom( type.getClass() ) )
        {
            /* <-MISALIGNED-> *//* 343 */n = 1;
        }
        else
        {
            /* <-MISALIGNED-> *//* 345 */Type comp = getComponent( type, component );
            /* <-MISALIGNED-> *//* 346 */n = numComponents( comp );
        }
        /* <-MISALIGNED-> *//* 348 */return n;
    }


    public static int numComponents( Type type )
    {
        /* <-MISALIGNED-> *//* 370 */if ( ( ca.uhn.hl7v2.model.Varies.class ).isAssignableFrom( type.getClass() ) )
            /* <-MISALIGNED-> *//* 371 */return numComponents( ( ( Varies )type ).getData() );
        /* <-MISALIGNED-> *//* 373 */else
            /* <-MISALIGNED-> *//* 373 */return numStandardComponents( type ) + type.getExtraComponents().numComponents();
    }


    private static int numStandardComponents( Type t )
    {
        /* <-MISALIGNED-> *//* 378 */int n = 0;
        /* <-MISALIGNED-> *//* 379 */if ( ( ca.uhn.hl7v2.model.Varies.class ).isAssignableFrom( t.getClass() ) )
            /* <-MISALIGNED-> *//* 380 */n = numStandardComponents( ( ( Varies )t ).getData() );
        /* <-MISALIGNED-> *//* 381 */else
        /* <-MISALIGNED-> *//* 381 */if ( ( ca.uhn.hl7v2.model.Composite.class ).isAssignableFrom( t.getClass() ) )
            /* <-MISALIGNED-> *//* 382 */n = ( ( Composite )t ).getComponents().length;
        /* <-MISALIGNED-> *//* 384 */else
            /* <-MISALIGNED-> *//* 384 */n = 1;
        /* <-MISALIGNED-> *//* 386 */return n;
    }


    public SegmentFinder getFinder( )
    {
        /* <-MISALIGNED-> *//* 396 */return finder;
    }
    private SegmentFinder finder;
    private static Log log;
    static
    {
        log = LogFactory.getLog( CustomTerser.class );
    }
}
