001package jmri.jmrix.loconet.sdf;
002
003import java.util.ArrayList;
004
005/**
006 * Implement the INITIATE_SOUND macro from the Digitrax sound definition
007 * language
008 *
009 * @author Bob Jacobsen Copyright (C) 2007
010 */
011public class InitiateSound extends SdfMacro {
012
013    public InitiateSound(int byte1, int byte2) {
014        this.byte1 = byte1;
015        this.byte2 = byte2;
016        this.trigger = byte2 & 0x7f;
017        this.prempt = (byte1 & 0x7) + (byte2 & 0x80);
018    }
019
020    @Override
021    public String name() {
022        return "INITIATE_SOUND"; // NOI18N
023    }
024
025    int prempt;
026    int trigger;
027    int byte1, byte2;
028
029    public int getTrigger() {
030        return trigger;
031    }
032
033    public void setTrigger(int t) {
034        trigger = t & 0x7f;
035        byte2 = (byte2 & 0x80) | (t & 0x7f);
036    }
037
038    public int getPrempt() {
039        return prempt;
040    }
041
042    public void setPrempt(int prempt) {
043        byte1 = (byte1 & 0xF8) | (prempt & 0x7);
044        byte2 = (byte2 & 0x7F) | (prempt & 0x80);
045        this.prempt = (byte1 & 0x7) + (byte2 & 0x80);
046    }
047
048    @Override
049    public int length() {
050        return 2;
051    }
052
053    String premptVal() {
054        return decodeFlags(prempt, premptCodes, premptMasks, premptNames);
055    }
056
057    String triggerVal() {
058        String trigName = jmri.util.StringUtil.getNameFromState(trigger, triggerCodes, triggerNames);
059        if (trigName != null) {
060            return trigName;
061        }
062        return "(trigger = 0x" + jmri.util.StringUtil.twoHexFromInt(trigger) + ")"; // NOI18N
063    }
064
065    static public SdfMacro match(SdfBuffer buff) {
066        if ((buff.getAtIndex() & 0xF8) != 0x90) {
067            return null;
068        }
069        int byte1 = buff.getAtIndexAndInc();
070        int byte2 = buff.getAtIndexAndInc();
071        InitiateSound result = new InitiateSound(byte1, byte2);
072
073        // gather leaves underneath
074        SdfMacro next;
075        while (buff.moreData()) {
076            // look ahead at next instruction
077            int peek = buff.getAtIndex() & 0xFF;
078
079            // if SKEME_START, CHANNEL_START, done
080            // Note that INITIATE_SOUND can be nested, so isn't here
081            if (peek == 0xF1
082                    || peek == 0x81) {
083                break;
084            }
085
086            // if this is a INITIATE_SOUND, process it _without_
087            // allowing recursion
088            if ((peek & 0xF8) == 0x90) {
089                // manually create next
090                byte1 = buff.getAtIndexAndInc();
091                byte2 = buff.getAtIndexAndInc();
092                next = new InitiateSound(byte1, byte2);
093            } else {
094                // next is leaf, keep it
095                next = decodeInstruction(buff);
096            }
097            if (result.children == null) {
098                result.children = new ArrayList<SdfMacro>(); // make sure it's initialized
099            }
100            result.children.add(next);
101
102            // if this was an END_SOUND, we're done now that we've included it
103            if (peek == 0x00) {
104                break;
105            }
106        }
107        return result;
108    }
109
110    /**
111     * Store into a buffer.
112     */
113    @Override
114    public void loadByteArray(SdfBuffer buffer) {
115        // data
116        buffer.setAtIndexAndInc(byte1);
117        buffer.setAtIndexAndInc(byte2);
118
119        // store children
120        super.loadByteArray(buffer);
121    }
122
123    @Override
124    public String toString() {
125        return "Define Sequence " + triggerVal() + "," + premptVal() + '\n';
126    }
127
128    @Override
129    public String oneInstructionString() {
130        return name() + " " + triggerVal() + "," + premptVal() + '\n';
131    }
132
133    @Override
134    public String allInstructionString(String indent) {
135        StringBuilder output = new StringBuilder(indent);
136        output.append(oneInstructionString());
137        if (children == null) {
138            return output.toString();
139        }
140        for (int i = 0; i < children.size(); i++) {
141            output.append(children.get(i).allInstructionString(indent + "  "));
142        }
143        return output.toString();
144    }
145}