All Downloads are FREE. Search and download functionalities are using the official Maven repository.

decodes.decoder.FieldOperation Maven / Gradle / Ivy

Go to download

A collection of software for aggregatting and processing environmental data such as from NOAA GOES satellites.

The newest version!
/*
*  $Id$
*/
package decodes.decoder;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.StringTokenizer;
import java.util.Date;
import java.util.TimeZone;

import ilex.util.Logger;
import ilex.util.ArrayUtil;
import ilex.util.ByteUtil;
import ilex.util.IDateFormat;
import ilex.var.TimedVariable;
import ilex.var.Variable;
import ilex.var.IFlags;

import decodes.db.*;
import hec.util.TextUtil;

/**
FieldOperation is a DecodesOperation that extracts and parses a field 
from the data stream. There are several kinds of fields. See the sub-chapter
on fields in the DECODES User Guide for details.
*/
class FieldOperation extends DecodesOperation
{
	/** field-type is the 1st arg inside the parenthesis for the field op */
	private String field_type;

	/** data-type is the 2nd arg inside the parenthesis for the field op */
	private char data_type;

	/** length is the 3rd argument inside the parenthesis for the field op */
	private int field_length;

//	/** length may be optionally folled by a delimiter */
//	private byte field_delimiter;

	/** Any character in this string can serve as a delimiter */
	private String delimiter;

	/** used if necessary to parse numbers */
	private NumberParser numberParser;

	/** the script that this op belongs to */
	private DecodesScript decodesScript;

	/** Used if field is specified as string */
	private String sensorName;

	/** Number of sensor. */
	private int sensorNumber;

	/** Signifies that time is an event. */
	private boolean event;

	/** Set by the 'x' suffix to the sensor number. */
	private boolean supressOutput = false;

	/** Signifies that time is an AM time. */
	private boolean AMSet = false;

	/** Signifies that time is a  PM time. */
	private boolean PMSet = false;

	/** current field **/
	private String currentField;
	
	private SimpleDateFormat loggerDateFmt = 
		new SimpleDateFormat("yyyy MMM/dd HH:mm:ss");
	
	private boolean isBinary = false;
	
	private String literalData = null;

	/** 3-char month abbreviations */
	static final String mn[] = 
	{ "---", "jan", "feb", "mar", "apr", "may", "jun",
	         "jul", "aug", "sep", "oct", "nov", "dec"
	};

	/** @return code for field type operations. */
	public char getType() { return 'f'; }

	/**
	  Constructor.
	  @param  repetitions number of times to repeat this operation
	  @param  args complete string inside the parens
	  @param  ds the DecodesScript that this operation belongs to
	  @throws ScriptFormatException if syntax error detected in arguments
	*/
	public FieldOperation(int repetitions, String args, DecodesScript ds)
		throws ScriptFormatException
	{
		super(repetitions);
		loggerDateFmt.setTimeZone(TimeZone.getTimeZone("UTC"));
		currentField = "f("+args+")";
		decodesScript = ds;

		// set defaults
		data_type = 'a';
		field_length = 0;
		sensorNumber = -1;
		delimiter = null;
		event = false;

		FieldArgsTokenizer fat = new FieldArgsTokenizer(args);

		String s = fat.nextToken();
		if ( s == null || s.length() == 0 ) {
			throw new ScriptFormatException(
				"Field operation with no field_type");
		}
		field_type = s.toLowerCase();

		s = fat.nextToken();
		if (s == null || s.length() == 0)
			throw new ScriptFormatException(
				"Field operation with no data-type");
		if (fat.wasDoubleQuoted)
		{
			data_type = NumberParser.ASCII_FMT;
			literalData = s;
		}
		else if (s.length() == 1)
			data_type = s.charAt(0);
		else if (s.equalsIgnoreCase("bc"))
			data_type = NumberParser.CAMPBELL_BINARY_FMT;
		else if (s.equalsIgnoreCase("bt") || s.equalsIgnoreCase("bd"))
			data_type = NumberParser.SIGNBIT_BINARY_FMT;
		else if (s.equalsIgnoreCase("bin"))
		{
			data_type = NumberParser.BIN_SIGNED_MSB;
			isBinary = true;
		}
		else if (s.equalsIgnoreCase("ubin"))
		{
			data_type = NumberParser.BIN_UNSIGNED_MSB;
			isBinary = true;
		}
		else if (s.equalsIgnoreCase("binl"))
		{
			data_type = NumberParser.BIN_SIGNED_LSB;
			isBinary = true;
		}
		else if (s.equalsIgnoreCase("ubinl"))
		{
			data_type = NumberParser.BIN_UNSIGNED_LSB;
			isBinary = true;
		}
		else
			data_type = s.charAt(0);

		s = fat.nextToken();
		if (literalData != null)
			field_length = literalData.length();
		else
		{
			if (s == null)
				throw new ScriptFormatException(
					"Field operation with no length");
			int pos = -1;
			for(pos=0; pos= 2 && delimiter.indexOf('\\') > -1) {
			delimiter = delimiter.replace("\\t","\t");
			delimiter = delimiter.replace("\\n","\n");
			delimiter = delimiter.replace("\\r","\r");
		}	
		// If delimiter contains either sign, add the other one.
		if (delimiter != null)
		{
			boolean hasMinus = (delimiter.indexOf('-') >= 0);
			boolean hasPlus  = (delimiter.indexOf('+') >= 0);
			if (hasMinus && !hasPlus)
				delimiter = delimiter + "+";
			else if (hasPlus && !hasMinus)
				delimiter = delimiter + "-";
		}
		// If delimiter is a single 'S' or 's', it means either sign.
		if (delimiter != null
		 && (delimiter.equals("S") || delimiter.equals("s")))
			delimiter = "+=";

		// If delimiter is a hex representation
		if (delimiter != null && delimiter.length() == 3
			&& (delimiter.equals("X") || delimiter.equals("x"))
			&& ByteUtil.isHexChar((byte)delimiter.charAt(1))
			&& ByteUtil.isHexChar((byte)delimiter.charAt(2)))
		{
			int x = Integer.parseInt(delimiter.substring(1,3), 16);
			delimiter = "" + ((char)x);
		}
	}


	/**
	  Executes this operation using the context provided.
	  @param dd holds the raw data and context.
	  @param msg store decoded values here.
	  @throws DecoderException or subclass if error detected.
	*/
	public void execute(DataOperations dd, DecodedMessage msg) 
		throws DecoderException
	{
		if (sensorNumber == -1 && (field_type.equals("s") || event))
			throw new ScriptException("Invalid sensor number in field "+currentField);
//			throw new ScriptException("No time-series for sensor " 
//				+ sensorNumber);

//		Logger.instance().log(Logger.E_DEBUG3,
//			"Executing FieldOperation, type=" + field_type
//			+ ", sensor=" + sensorNumber
//			+ ", repetitions=" + repetitions
//			+ ", length=" + field_length 
//		 	+ ", delim='" + (field_delimiter==0 ? 'N' : (char)field_delimiter) 
//			+ "'");

		boolean isString = (data_type=='S'||data_type=='s');
		for (int n=0; n < repetitions; n++) 
		{
			int fieldStart = dd.getBytePos();
			int lineNum = dd.getCurrentLine();
			byte field[];
			boolean isZformat=false;
			if (literalData != null)
				field = literalData.getBytes();
			
			else if (data_type=='Z'||data_type=='z')
			{
				isZformat=true;
				field = dd.getField( field_length, delimiter, isBinary, isZformat);			
			}
			else if(data_type=='R'|| data_type=='r')
			{
				field = dd.getField(msg.getRawMessage().getData().length+2, delimiter, isBinary, isString);
			}
			else if(data_type=='N'|| data_type=='n')
			{
				field = dd.getField(msg.getRawMessage().getData().length+2, delimiter, isBinary, isString);
			}
			else if(data_type=='K' || data_type == 'k')
			{
				field = dd.getField(msg.getRawMessage().getData().length, delimiter, isBinary, isString);
			}
			else
				field = dd.getField(field_length, delimiter, isBinary, isString);


			if (field != null && numberParser != null)
				Logger.instance().log(Logger.E_DEBUG3,
				"Field Parse: data='" + new String(field) + "', fieldType="
				+ field_type + ", dataType=" + numberParser.getDataType());

			
			if ( is_blank(field) && !isString && !isZformat )
				continue;
			
			if (field_type.equals("s")) // Sensor Field
			{
				Variable v;
				String s = new String(field).trim();

				try
				{
					if (isMissingSymbol(s))
					{
						v = new Variable("m");
						v.setFlags(v.getFlags() | IFlags.IS_MISSING);
						Logger.instance().debug3("found missing symbol '" + s + "'");
					}
					else
					{
						v = numberParser.parseDataValue(field);
						Logger.instance().debug3("field parsed to '" + v + "'");
					}
				}
				catch(FieldParseException ex)
				{
					if(isZformat && s!=null && s.equalsIgnoreCase(""))
						s = "//";
					Logger.instance().debug1("Field Parse Exception: "
						+ ex.getMessage());
					v = new Variable("e");
					v.setFlags(v.getFlags() | IFlags.IS_ERROR);
				}
				if (!supressOutput)
				{
					TimedVariable tv = msg.addSample(sensorNumber, v, lineNum);
					if (tv != null && DecodesScript.trackDecoding)
					{
						DecodedSample ds = new DecodedSample(this, 
							fieldStart, dd.getBytePos(),
							tv, msg.getTimeSeries(sensorNumber));
						formatStatement.getDecodesScript().addDecodedSample(ds);
					}
				}
				RecordedTimeStamp rts = msg.getTimer();
				rts.dayJustSet = false;
			}
			else if (field_type.equals("f")) // Format Label Field
			{
				String label = new String(field);
				Logger.instance().log(Logger.E_DEBUG3,
					"Searching for format label '" + label + "'");
				FormatStatement newFormat = 
					decodesScript.getFormatStatement(label);
				if (newFormat == null)
				{
					// Try to find an error handler
					newFormat = decodesScript.getFormatStatement("ERROR");
					if (newFormat == null)
						throw new FieldParseException("No such format label '"
							+ label + "', and no ERROR statement.");
				}
				throw new SwitchFormatException(newFormat);
			}
			else if (field_type.equals("jdy") || field_type.equals("jdy+")) 
			{
				boolean increment = field_type.equals("jdy+");
				int t = numberParser.parseIntValue(field);
				if (t < 1 || t > 366)
					throw new FieldParseException("Invalid Julian Date: " + t);
				int stat = msg.getTimer().getStatus();
				RecordedTimeStamp rts = msg.getTimer();

				/*
				  The increment flag means that this is the day just ending.
				  Conversely, (!increment) means that this is the day just starting.
				  Therefore, before fixing-up partial dates, decrement day
				  if !increment. Then set it back.
				*/
				if ( t == 366 ) {
					int curYear = rts.getYear();
					GregorianCalendar gc = new GregorianCalendar();
					if ( curYear != 1970 && !gc.isLeapYear(curYear) ) {
						throw new FieldParseException("Found day 366 for non-leap year "+curYear+" - value ignored.");
					}
				}
				rts.setDayOfYear(t);
				if (!increment)
					rts.decrementDay();
				if (stat != rts.getStatus())
					msg.upgradeStoredTimes();
				rts.incrementDay();
				rts.setHour(0);
				rts.setMinute(0);
				rts.setSecond(0);
				rts.dayJustSet = true;
				msg.justGotNonYearField();
			}
			else if ( field_type.equals("dy") )  // Day of Month
			{
				int t = numberParser.parseIntValue(field);
				RecordedTimeStamp rts = msg.getTimer();
				int stat = rts.getStatus();
				if (stat != rts.setDayOfMonth(t))
				{
					// stat can now be SecOfYear or Complete.
					// A new day is starting. Assume already-retrieved times
					// were for yesterday.
					rts.decrementDay();
					msg.upgradeStoredTimes();
					rts.incrementDay();
				}
				rts.dayJustSet = true;
				msg.justGotNonYearField();
			}
			else if ( field_type.equals("yr") ) 
			{
				for(int i=0; i= 3)
					t = indexOfMonth(field);
				int stat = msg.getTimer().getStatus();
				if (stat != msg.getTimer().setMonth(t))
				{
					// stat can no be SecOfYear or Complete.
					// Assume a new day is starting. Assume already-retrieved
					// Times were for yesterday.
					msg.getTimer().decrementDay();
					msg.upgradeStoredTimes();
					msg.getTimer().incrementDay();
				}
				msg.justGotNonYearField();
			}
			else if ( field_type.equals("hr") ) 
			{
				int t = numberParser.parseIntValue(field);
				int stat = msg.getTimer().getStatus();
				if (stat != msg.getTimer().setHour(t))
					msg.upgradeStoredTimes();
				msg.justGotNonYearField();
			}
			else if ( field_type.equals("min") ) 
			{
				int t = numberParser.parseIntValue(field);
				int stat = msg.getTimer().getStatus();
				if (stat != msg.getTimer().setMinute(t))
					msg.upgradeStoredTimes();
				msg.justGotNonYearField();
			}
			else if (field_type.equals("sec") ) 
			{
				int t = numberParser.parseIntValue(field);
				int stat = msg.getTimer().getStatus();
				if (stat != msg.getTimer().setSecond(t))
					msg.upgradeStoredTimes();
				msg.justGotNonYearField();
			}
			else if (field_type.equals("t") ) 
			{
				RecordedTimeStamp rts = msg.getTimer();
				int stat = rts.getStatus();
				long msec = rts.getMsec();
				parseTime(field, rts);
				msg.justGotNonYearField();

				if ( PMSet ) 
					msg.getTimer().setPM(true);
				else if ( AMSet )
					msg.getTimer().setPM(false);
				// Special EDL case - just have time, supposed to be ascending,
				// and time jumps backward. Assume we bump day by one.
				if (stat == RecordedTimeStamp.COMPLETE
				 && msec > rts.getMsec()
				 && decodesScript.getDataOrder()==Constants.dataOrderAscending
				 && !rts.dayJustSet)
					rts.incrementDay();
				rts.dayJustSet = false;

				if (stat != msg.getTimer().getStatus())
					msg.upgradeStoredTimes();

				if (sensorNumber != -1 && event)
					msg.addSample(sensorNumber, new Variable(1.0), lineNum);
				msg.justGotNonYearField();
			}
			else if (field_type.equals("mht") )  // Message Header Time
			{
				// See comment for "mhd" above
				RecordedTimeStamp rts = new RecordedTimeStamp();
				Date messageTime = msg.getMessageTime();
				rts.setComplete(messageTime);
				
				parseTime(field, rts);

				Logger.instance().debug3("Setting message time messageTime=" + rts.getTime() 
					+ ", currentTime=" + msg.getTimer().getTime() + ", timeWasTruncated=" + msg.timeWasTruncated);
				msg.setMessageTime(rts.getTime());
			}
			else if (field_type.equals("ti") ) 
			{
				if (sensorNumber == -1)
					throw new ScriptFormatException(
						"Time-Interval field must have sensor number");
				try
				{
					int sod = IDateFormat.getSecondOfDay(new String(field));
					msg.setTimeInterval(sensorNumber, sod);
				}
				catch(IllegalArgumentException ex)
				{
					throw new FieldParseException("Bad time interval value");
				}
			}
 			// Minute Interval (positive or negative)
			else if (field_type.equals("mint") 
			      || field_type.equals("mint-") )
			{
				if (sensorNumber == -1)
					throw new ScriptFormatException(
						"Minute-Interval field must have sensor number");
				try
				{
					int m = numberParser.parseIntValue(field);
					if (field_type.equals("mint-") 
					 && decodesScript.getDataOrder() == Constants.dataOrderAscending)
						m = -m;
					Logger.instance().log(Logger.E_DEBUG3,
						"Setting interval for sensor " + sensorNumber + " to " + (m*60) + " seconds.");
					msg.setTimeInterval(sensorNumber, m*60);
				}
				catch(IllegalArgumentException ex)
				{
					throw new FieldParseException("Bad minute interval value");
				}
			}
			else if (field_type.equals("moff") )  // Minute Offset
			{
				try
				{
					int m = numberParser.parseIntValue(field);

					// Reset 'current' time to 'message' time minus offset.
					Date msgTime = msg.getUntruncatedMessageTime();
					if (msgTime == null) msgTime = new Date();
					long msec = msgTime.getTime();
					// moff implies that we truncate to minute boundary
					msec = (msec / 60000L) * 60000L;
					msec -= (m * 60000L);
					Date timeStamp = new Date(msec);
					msg.getTimer().setComplete(timeStamp);
					Logger.instance().log(Logger.E_DEBUG3,
						"Set Minute OFFset to " + m + ", current timer="
						+ loggerDateFmt.format(timeStamp));
				}
				catch(IllegalArgumentException ex)
				{
					throw new FieldParseException("Bad minute interval value");
				}
			}
			else if (field_type.equals("to") ) 
			{
			}
			else if (field_type.equals("a") ) 
			{
				char c = (char)field[0];
				if (c == 'A' || c == 'a')  // AM
					msg.getTimer().setPM(false);
				else if (c == 'P' || c == 'p')  // PM
					msg.getTimer().setPM(true);
			}
			else if (field_type.equals("tz") )  // Time Zone Field
			{
				String sfield = new String(field);
				String tzid = mapSpecialTz(sfield);
				if (tzid == null)
					tzid = sfield;
				msg.getTimer().setTimeZoneName(tzid);
				Logger.instance().debug3("Set Time Zone to '" + tzid + "' (" + msg.getTimer().getTimeZoneName() + ")");
			}
		}
	}
	
	private static HashMap specialTzMap = null;
	
	private String mapSpecialTz(String tzid)
	{
		if (specialTzMap == null)
		{
			specialTzMap = new HashMap();
			specialTzMap.put("EDT", "EST5EDT");
			specialTzMap.put("CDT", "CST6CDT");
			specialTzMap.put("MDT", "MST7MDT");
			specialTzMap.put("PDT", "PST8PDT");
			specialTzMap.put("-0400", "GMT-04:00");
			specialTzMap.put("-04:00", "GMT-04:00");
			specialTzMap.put("-0500", "GMT-05:00");
			specialTzMap.put("-05:00", "GMT-05:00");
			specialTzMap.put("-0600", "GMT-06:00");
			specialTzMap.put("-06:00", "GMT-06:00");
			specialTzMap.put("-0700", "GMT-07:00");
			specialTzMap.put("-07:00", "GMT-07:00");
			specialTzMap.put("-0800", "GMT-08:00");
			specialTzMap.put("-08:00", "GMT-08:00");
		}
		return specialTzMap.get(tzid);
	}
	
	


	private boolean is_blank(byte f[])
	{
		int i;
		for(i=0; i < f.length; i++ ) 
		{
			if ( f[i] != (byte)' ' )
				return(false);
		}
		return(true);
	}

	/** Debug method dumps field data to stdout. */
  	void dump_field(byte[] field)
  	{
          int i;

          for (i=0; i < field.length; i++ )
            System.out.print((char)field[i]);
          System.out.println("");
          System.out.println("size = " + field.length);
          System.out.println("");
	}

	private void parseDate(byte[] field, DecodedMessage msg, boolean increment)
		throws DecoderException
	{
		int y, m, d;

		// Get the timer & save the status before any updates.
		RecordedTimeStamp rts = msg.getTimer();
		int stat = msg.getTimer().getStatus();
		
		// Note sensorNumber doubles as field_id for date ops
		switch(sensorNumber)
		{
		case 1:  // YYMMDD or YY/MM/DD or YYYY/MM/DD
			parseDate(field, rts);

			msg.setJustGotFullDateTime(true);
			if (!increment)
				rts.decrementDay();
			if (stat != msg.getTimer().getStatus())
				msg.upgradeStoredTimes();
			rts.incrementDay();
			break;

		case 2: // ddd, yyddd, yy/ddd, or yyyyddd
			parseDate(field, rts);

			if (rts.getHaveYear())
				msg.setJustGotFullDateTime(true);
			else
				msg.justGotNonYearField();

			if (!increment)  // see comment above for jdy field type.
				rts.decrementDay();
			if (stat != msg.getTimer().getStatus())
				msg.upgradeStoredTimes();
			rts.incrementDay();
			break;

		case 3: // mmdd or mm/dd
			parseDate(field, rts);
			
			if ( !increment )
				rts.decrementDay();
			if (stat != msg.getTimer().getStatus())
				msg.upgradeStoredTimes();
			Logger.instance().debug3("After M field with month=" + rts.getMonth() + ", day=" + rts.getDayOfMonth() + ", dayOfYear=" + rts.getDayOfYear() + ", incr=" + increment);
			rts.incrementDay();
			msg.justGotNonYearField();
			break;

		case 4: // mmddyy, mm/dd/yy
			parseDate(field, rts);

			if (!increment)
				rts.decrementDay();
			if (stat != msg.getTimer().getStatus())
				msg.upgradeStoredTimes();
			rts.incrementDay();
			msg.setJustGotFullDateTime(true);
			break;

		default:
			throw new ScriptException("Unknown date format " + sensorNumber);
		}
	}

	private void parseDate(byte[] field, RecordedTimeStamp rts)
		throws DecoderException
	{
		int y, m, d;
		
		// Note sensorNumber doubles as field_id for date ops
		switch(sensorNumber)
		{
		case 1:  // YYMMDD or YY/MM/DD or YYYY/MM/DD
			if (field_length == 6)
			{
				y = numberParser.parseIntValue(ArrayUtil.getField(field, 0, 2));
				m = numberParser.parseIntValue(ArrayUtil.getField(field, 2, 2));
				d = numberParser.parseIntValue(ArrayUtil.getField(field, 4, 2));
			}
			else if (field_length == 8)
			{
				y = numberParser.parseIntValue(ArrayUtil.getField(field, 0, 2));
				m = numberParser.parseIntValue(ArrayUtil.getField(field, 3, 2));
				d = numberParser.parseIntValue(ArrayUtil.getField(field, 6, 2));
			}
			else if (field_length == 10)
			{
				y = numberParser.parseIntValue(ArrayUtil.getField(field, 0, 4));
				m = numberParser.parseIntValue(ArrayUtil.getField(field, 5, 2));
				d = numberParser.parseIntValue(ArrayUtil.getField(field, 8, 2));
			}
			else
				throw new FieldParseException(
					"Date format 1 bad date format '" + field + "'");

			rts.setYear(y);
			rts.setMonth(m);
			rts.setDayOfMonth(d);
			break;

		case 2: // ddd, yyddd, yy/ddd, or yyyyddd
			y = -1;
			if (field_length <= 4)
			{
				d = numberParser.parseIntValue(field);
			}
			else if (field_length == 5)
			{
				y = numberParser.parseIntValue(ArrayUtil.getField(field, 0, 2));
				d = numberParser.parseIntValue(ArrayUtil.getField(field, 2, 3));
			}
			else if (field_length == 6)
			{
				y = numberParser.parseIntValue(ArrayUtil.getField(field, 0, 2));
				d = numberParser.parseIntValue(ArrayUtil.getField(field, 3, 3));
			}
			else if (field_length == 7)
			{
				y = numberParser.parseIntValue(ArrayUtil.getField(field, 0, 4));
				d = numberParser.parseIntValue(ArrayUtil.getField(field, 4, 3));
			}
			else
				throw new FieldParseException(
					"Date format 2 bad data '" + field + "'");

			if (y != -1)
				rts.setYear(y);

			if ( d == 366 ) 
			{
				int curYear = rts.getYear();
				GregorianCalendar gc = new GregorianCalendar();
				if ( curYear != 1970 && !gc.isLeapYear(curYear) )
				{
					throw new FieldParseException("Found day 366 for non-leap year "+curYear+".");
				}
			}
			rts.setDayOfYear(d);
			break;

		case 3: // mmdd or mm/dd
			if (field_length == 4)
			{
				m = numberParser.parseIntValue(ArrayUtil.getField(field, 0, 2));
				d = numberParser.parseIntValue(ArrayUtil.getField(field, 2, 2));
			}
			else if (field_length == 5)
			{
				m = numberParser.parseIntValue(ArrayUtil.getField(field, 0, 2));
				d = numberParser.parseIntValue(ArrayUtil.getField(field, 3, 2));
			}
			else
				throw new FieldParseException(
					"Date format 3 bad data '" + field + "'");

			rts.setMonth(m);
			rts.setDayOfMonth(d);
			Logger.instance().debug3("After M field with month=" + m + ", day=" + d + ", dayOfYear=" + rts.getDayOfYear());
			break;

		case 4: // mmddyy, mm/dd/yy
			m = numberParser.parseIntValue(ArrayUtil.getField(field, 0, 2));
			if (field_length == 6)
			{
				d = numberParser.parseIntValue(ArrayUtil.getField(field, 2, 2));
				y = numberParser.parseIntValue(ArrayUtil.getField(field, 4, 2));
			}
			else if (field_length == 8 || field_length == 10)
			{
				d = numberParser.parseIntValue(ArrayUtil.getField(field, 3, 2));
				y = numberParser.parseIntValue(ArrayUtil.getField(field, 6, 
					field_length == 8 ? 2 : 4));
			}
			else
				throw new FieldParseException(
					"Date format 4 bad data '" + field + "'");

			rts.setYear(y);
			rts.setMonth(m);
			rts.setDayOfMonth(d);
			break;

		default:
			throw new ScriptException("Unknown date format " + sensorNumber);
		}
	}

	private int indexOfMonth(byte [] field)
		throws FieldParseException
	{
		String name = new String(field);
		if (name.length() > 3)
			name = name.substring(0, 3);
		name = name.toLowerCase();

		for(int i=1; i 0 ) {
			AMSet = true;
			PMSet = false;
			tf = tf.substring(0, ampmIndex);
		} else {
			ampmIndex = tf.toLowerCase().indexOf("pm");
			if ( ampmIndex > 0 ) {
				PMSet = true;
				AMSet = false;
				tf = tf.substring(0, ampmIndex);
			}
		}

//	Eliminate trailing spaces

		int spaceIndex = tf.lastIndexOf(' ');
		while ( spaceIndex == tf.length()-1 )
		{
			tf = tf.substring(0,spaceIndex);
			spaceIndex = tf.lastIndexOf(' ');
		}

//	See if there are standard delimiters

    String tm[] = tf.split(delimiters);
		if ( tm.length == 1 ) {

//		No delimiters - analyze length to determine field format

			field = tf.getBytes();
			if (field.length <= 2) // m or mm
			{
				m = numberParser.parseIntValue(ArrayUtil.getField(field, 0,
					field.length));
			}
			else if (field.length == 3) // HMM
			{
				h = numberParser.parseIntValue(ArrayUtil.getField(field, 0, 1));
				m = numberParser.parseIntValue(ArrayUtil.getField(field, 1, 2));
			}
			else // some combo of HH MM and optionally SS.
			{
				if ( field.length > 0 && field.length <= 8 ) {
					h = numberParser.parseIntValue(ArrayUtil.getField(field, 0, 2));
					if (field.length == 4) // hhmm
						m = numberParser.parseIntValue(ArrayUtil.getField(field, 2, 2));
					else if (field.length == 5) // hh:mm
						m = numberParser.parseIntValue(ArrayUtil.getField(field, 3, 2));
					else if (field.length == 6) // hhmmss
					{
						m = numberParser.parseIntValue(ArrayUtil.getField(field, 2, 2));
						s = numberParser.parseIntValue(ArrayUtil.getField(field, 4, 2));
					}
					else if (field.length == 8) // hh:mm:ss
					{
						m = numberParser.parseIntValue(ArrayUtil.getField(field, 3, 2));
						s = numberParser.parseIntValue(ArrayUtil.getField(field, 6, 2));
					}
				}
			}
		} else if ( tm.length > 1 ) {
//		Has delimeter(:,.,-,or space)
			if ( tm.length > 2 ) 		// Has a second
				s = numberParser.parseIntValue(tm[2].getBytes());
			if ( tm.length > 1 ) 	 //  Has a minute
				m = numberParser.parseIntValue(tm[1].getBytes());
			h = numberParser.parseIntValue(tm[0].getBytes());
		}
		if ( h < 0 || h > 24 || m < 0 || m > 59 || s < 0 || s >59 ) 
					throw new FieldParseException("Bad time format '" + 
						new String(field) + "'");
		rts.setHour(h);
		rts.setMinute(m);
		rts.setSecond(s);
	}
	
	/**
	 * @param s the field data
	 * @return true if the field data represents a placeholder for a missing value.
	 */
	private boolean isMissingSymbol(String s)
	{
		return s.startsWith("//") 
		 || (s.startsWith("??") && data_type == NumberParser.ASCII_FMT)
		 || s.startsWith("---")
		 || (s.equalsIgnoreCase("M") && data_type == NumberParser.ASCII_FMT)
		 || decodesScript.isMissingSymbol(s);
	}

	public static void main(String args[])
	{
		FieldArgsTokenizer fat = new FieldArgsTokenizer(args[0]);
		String tok;
		int i=0;
		while((tok = fat.nextToken()) != null)
			System.out.println("Token[" + (i++) + "] = '" + tok + "'");
	}
}

class FieldArgsTokenizer
{
	String str;
	int pos;
	int length;
	boolean quoted;
	boolean doubleQuoted;
	boolean wasDoubleQuoted;

	public FieldArgsTokenizer(String inputstr)
	{
		str = inputstr.trim();
		pos = 0;
		length = str.length();
	}

	public String nextToken()
	{
		int start = pos;
		quoted = false;
		doubleQuoted = false;
		wasDoubleQuoted = false;
		StringBuffer ret = new StringBuffer();
		while(pos < length)
		{
			char c = str.charAt(pos++);
			if (quoted)
			{
				if (c == '\'')
				{
					quoted = false;
					continue;
				}
			}
			else if (doubleQuoted)
			{
				if (c == '"')
				{
					doubleQuoted = false;
					continue;
				}
			}
			else if (c == ',')
				break;
			else if (c == '\'')
			{
				quoted = true;
				continue;
			}
			else if (c == '"')
			{
				doubleQuoted = true;
				wasDoubleQuoted = true;
				continue;
			}
			else if (c == ' ')  // delete unquoted spaces.
				continue;
			ret.append(c);
		}
		if (pos > start)
			return ret.toString();
		else
			return null;
	}
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy