package org.yamcs.xtceproc;

import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.Set;
import java.util.SortedSet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yamcs.ContainerExtractionResult;
import org.yamcs.xtce.RateInStream;
import org.yamcs.xtce.SequenceContainer;
import org.yamcs.xtce.SequenceEntry;
import org.yamcs.xtceproc.ContainerProcessingContext.ContainerProcessingPosition;
import org.yamcs.xtceproc.ContainerProcessingContext.ContainerProcessingResult;

public class SequenceContainerProcessor {
    Logger log = LoggerFactory.getLogger(this.getClass().getName());
    ContainerProcessingContext pcontext;
    SequenceContainerProcessor(ContainerProcessingContext pcontext) {
        this.pcontext = pcontext;
    }

    public void extract(SequenceContainer seq) {
        ContainerProcessingResult result = pcontext.result;
        ContainerProcessingPosition position = pcontext.position;
        ByteBuffer bb = position.bb;
        //First add it to the result
        result.containers.add(new ContainerExtractionResult(seq, bb.asReadOnlyBuffer(), 
                position.bitPosition, result.acquisitionTime, result.generationTime));

        RateInStream ris = seq.getRateInStream();
        if((ris != null) && ris.getMaxInterval()>0) {
            result.expireMillis = ris.getMaxInterval();
        }
        int maxposition = position.bitPosition;

        //then extract the entries
        SortedSet<SequenceEntry> entries = pcontext.subscription.getEntries(seq);
        if(entries!=null) {
            for (SequenceEntry se:entries) {
                try {
                    switch(se.getReferenceLocation()) {
                    case previousEntry:
                        position.bitPosition+=se.getLocationInContainerInBits();
                        break;
                    case containerStart:
                        position.bitPosition=se.getLocationInContainerInBits();
                    }
                    
                    if(pcontext.ignoreOutOfContainerEntries && (position.bitPosition >= position.bb.capacity()*8)) {
                        //the next entry is outside of the packet
                        break;
                    }

                    if(se.getRepeatEntry()==null) {
                        pcontext.sequenceEntryProcessor.extract(se);
                    } else { //this entry is repeated several times
                        long n = pcontext.valueProcessor.getValue(se.getRepeatEntry().getCount());
                        for (int i=0; i<n; i++) {
                            pcontext.sequenceEntryProcessor.extract(se);
                            position.bitPosition += se.getRepeatEntry().getOffsetSizeInBits();
                        }
                    }
                } catch (BufferUnderflowException|BufferOverflowException|IndexOutOfBoundsException e) {
                    log.warn("Got "+e.getClass().getName()+" when extracting from the buffer of length "+bb.capacity()+" bytes bitPosition "+position.bitPosition+" entry: "+se);
                    break;
                } 
                if(position.bitPosition>maxposition) {
                    maxposition = position.bitPosition;
                }
            }
        }

        Set<SequenceContainer> inheritingContainers = pcontext.subscription.getInheritingContainers(seq);
        boolean hasDerived=false;

        if(inheritingContainers!=null) {
            //And then any derived containers
            int bitp = position.bitPosition;
            for(SequenceContainer sc:inheritingContainers) {

                if(sc.getRestrictionCriteria() == null)
                {
                    log.warn("Container "+sc.getName()+" inherits without defining an inheritance condition. Ignoring the container.");
                    continue;
                }
                if(sc.getRestrictionCriteria().isMet(pcontext.criteriaEvaluator)) {
                    hasDerived=true;
                    position.bitPosition=bitp;
                    extract(sc);
                    if(position.bitPosition>maxposition) {
                        maxposition = position.bitPosition;
                    }
                }
            }
        }
        position.bitPosition=maxposition;
        //Finaly update the stats. We add the packet into the statistics only if it doesn't have a derived container
        if(!hasDerived && (result.stats != null)) {
            result.stats.newPacket(seq.getName(), (entries==null)?0:entries.size(), 
                    result.acquisitionTime, result.generationTime);
        }
    }
}

@@ -3662,17 +3662,16 @@
 ners) %7B%0A
-%0A
         
@@ -3717,32 +3717,16 @@
 == null)
-%0A               
  %7B%0A     
@@ -3764,24 +3764,10 @@
 ner 
-%22+sc.getName()+%22
+%7B%7D
  inh
@@ -3839,16 +3839,30 @@
 tainer.%22
+, sc.getName()
 );%0A     

Update SequenceContainerProcessor.java