ArduinoValues.java

/*******************************************************************************
 * jArduino: Arduino C++ Code Generation From Java
 * Copyright 2020 Tony Washer
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
package net.sourceforge.jarduino.message;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

import net.sourceforge.jarduino.ArduinoException;
import net.sourceforge.jarduino.message.ArduinoParser.ArduinoParserException;

/**
 * Values.
 */
public class ArduinoValues {
    /**
     * The Marker.
     */
    static final String MARKER = "VAL_";

    /**
     * Owning signal.
     */
    private final ArduinoSignal theOwner;

    /**
     * The values map.
     */
    private final Map<Number, String> theValues;

    /**
     * Constructor.
     * @param pOwner the owning signal
     * @param pValues the value map
     */
    ArduinoValues(final ArduinoSignal pOwner,
                  final Map<Number, String> pValues) {
        theOwner = pOwner;
        theValues = pValues;
    }

    /**
     * Obtain the owner.
     * @return the owner
     */
    public ArduinoSignal getOwner() {
        return theOwner;
    }

    /**
     * Obtain the values.
     * @return the values
     */
    public Map<Number, String> getValues() {
        return theValues;
    }

    /**
     * Obtain the description for the value.
     * @param pValue the value
     * @return the description
     */
    public String getDescriptionForValue(final Number pValue) {
        return theValues.get(pValue);
    }

    /**
     * parse the values definition.
     * @param pSystem the system
     * @param pValuesDef the values definition
     * @throws ArduinoException on error
     */
    public static void parseValues(final ArduinoSystem pSystem,
                                   final String pValuesDef) throws ArduinoException {
        /* Marker is first token in header */
        final String myMarker = ArduinoParser.nextToken(pValuesDef);
        String myDef = ArduinoParser.stripToken(pValuesDef, myMarker);
        if (!myMarker.equals(MARKER)) {
            throw new ArduinoException("Invalid marker", pValuesDef);
        }

        /* Split out msgId/comment */
        final String myMsgId = ArduinoParser.nextToken(myDef);
        myDef = ArduinoParser.stripToken(myDef, myMsgId);
        final String myName = ArduinoParser.nextToken(myDef);
        myDef = ArduinoParser.stripToken(myDef, myName);

        /* Protect against parser exceptions */
        try {
            /* Find the signal */
            final ArduinoSignal mySignal = pSystem.findSignalByIdAndName(myMsgId, myName);

            /* Build the value map */
            final Map<Number, String> myValueMap = buildValueMap(myDef);

            /* Create Values and assign to signal */
            final ArduinoValues myValues = new ArduinoValues(mySignal, myValueMap);
            mySignal.setValues(myValues);

            /* Handle parser exceptions */
        } catch (ArduinoParserException e) {
            throw new ArduinoException(e.getMessage() + ArduinoChar.COLON + e.getDetail(), pValuesDef);
        }
    }

    /**
     * Build the valueMap.
     * @param pMapDef the mapDefinition
     * @return the map
     * @throws ArduinoParserException on error
     */
    private static Map<Number, String> buildValueMap(final String pMapDef) throws ArduinoParserException {
        String myValues = pMapDef;
        if (myValues.length() == 0 || myValues.charAt(myValues.length() - 1) != ArduinoChar.SEMICOLON) {
            throw new ArduinoParserException("Invalid ValuesTable", pMapDef);
        }
        myValues = myValues.substring(0, myValues.length() - 1);

        /* Loop through the tokens */
        final Map<Number, String> myMap = new LinkedHashMap<>();
        while (myValues.length() > 0) {
            /* Access the value */
            final String myValue = ArduinoParser.nextToken(myValues);
            myValues = ArduinoParser.stripToken(myValues, myValue);
            final Number myNumber = ArduinoParser.parseNumber(myValue);

            /* Access description */
            final String myDesc = ArduinoParser.nextQuotedToken(myValues);
            myValues = ArduinoParser.stripQuotedToken(myValues, myDesc);

            /* Add to the table */
            myMap.put(myNumber, myDesc);
        }

        /* Return the map */
        return myMap;
    }

    @Override
    public String toString() {
        /* Handle headers */
        final StringBuilder myBuilder = new StringBuilder();
        myBuilder.append(MARKER);
        myBuilder.append(ArduinoChar.BLANK);
        myBuilder.append(theOwner.getOwner().getId());
        myBuilder.append(ArduinoChar.BLANK);
        myBuilder.append(theOwner.getName());

        /* Loop through the values */
        for (Entry<Number, String> myEntry : theValues.entrySet()) {
            myBuilder.append(ArduinoChar.BLANK);
            myBuilder.append(myEntry.getKey());
            myBuilder.append(ArduinoChar.BLANK);
            myBuilder.append(ArduinoChar.QUOTE);
            myBuilder.append(myEntry.getValue());
            myBuilder.append(ArduinoChar.QUOTE);
        }

        /* Terminate and return */
        myBuilder.append(ArduinoChar.SEMICOLON);
        return myBuilder.toString();
    }
}