<commit_before>package org.csstudio.archive.engine.model;

import java.util.Arrays;

import org.apache.log4j.Logger;
import org.csstudio.apputil.time.PeriodFormat;
import org.csstudio.platform.data.IDoubleValue;
import org.csstudio.platform.data.IEnumeratedValue;
import org.csstudio.platform.data.ILongValue;
import org.csstudio.platform.data.IStringValue;
import org.csstudio.platform.data.IValue;
import org.csstudio.platform.logging.CentralLogger;

/** An ArchiveChannel that stores value in a periodic scan.
 *  @author <NAME>
 */
@SuppressWarnings("nls")
public class ScannedArchiveChannel extends ArchiveChannel implements Runnable
{
    /** Scan period in seconds */
    final private double scan_period;
    final private int max_repeats;
    private int repeats = 0;
    private Logger log;
    
    /** @see ArchiveChannel#ArchiveChannel(String, int, IValue) */
    public ScannedArchiveChannel(final String name,
                                 Enablement enablement, final int buffer_capacity,
                                 final IValue last_archived_value,
                                 final double scan_period,
                                 final int max_repeats) throws Exception
    {
        super(name, enablement, buffer_capacity, last_archived_value);
        this.scan_period = scan_period;
        this.max_repeats = max_repeats;
        log = CentralLogger.getInstance().getLogger(this);
        if (! log.isDebugEnabled())
            log = null;
    }
    
    /** @return Scan period in seconds */
    final public double getPeriod()
    {
        return scan_period;
    }

    @Override
    public String getMechanism()
    {
        return PeriodFormat.formatSeconds(scan_period) + " scan, max. "
            + max_repeats + " repeats";
    }

    /** Invoked by periodic scanner.
     *  Try to add the current value to the archive.
     *  Skip repeated values, unless we exceed the max. repeat count.
     */
    final public void run()
    {
        if (! isEnabled())
            return;
        final IValue value;
        synchronized (this)
        {   // Have anything?
            if (most_recent_value == null)
            {
                if (log != null)
                    log.debug(getName() + " scan: No data");
                return;
            }
            // Is it a new value?
            if (isMatchingValue(last_archived_value, most_recent_value))
            {
                ++repeats ;
                if (repeats < max_repeats)
                {
                    if (log != null)
                        log.debug(getName() + ": " + most_recent_value + " repeat " + repeats);
                    return;
                }
            }
            // New value, or exceeded repeats
            repeats = 0;
            value = most_recent_value;
        }
        // unlocked w/ reference to most_recent_value
        final IValue updated = ValueButcher.transformTimestampToNow(value);
        if (updated == null)
            CentralLogger.getInstance().getLogger(this).error("Channel " + getName()
                            + ": Cannot handle value type "
                            + value.getClass().getName());
        if (addValueToBuffer(updated))
        {
            if (log != null)
                log.debug(getName() + " writes " + updated + " (orig. " + value.getTime() + ")");
        }
    }

    /** Check if values match in status, severity, and value. Time is ignored.
     *  @param val1 One value
     *  @param val2 Other value
     *  @return <code>true</code> if they match
     */
    private boolean isMatchingValue(final IValue val1, final IValue val2)
    {
        // Compare data type and value
        if (val1 instanceof IDoubleValue)
        {
            if (! (val2 instanceof IDoubleValue))
                return false;
            final double v1[] = ((IDoubleValue) val1).getValues();
            final double v2[] = ((IDoubleValue) val2).getValues();
            if (!Arrays.equals(v1, v2))
                return false;
        }
        else if (val1 instanceof IEnumeratedValue)<commit_msg>scan = write most recent<commit_after>package org.csstudio.archive.engine.model;

import java.util.Arrays;

import org.apache.log4j.Logger;
import org.csstudio.apputil.time.PeriodFormat;
import org.csstudio.platform.data.IDoubleValue;
import org.csstudio.platform.data.IEnumeratedValue;
import org.csstudio.platform.data.ILongValue;
import org.csstudio.platform.data.IStringValue;
import org.csstudio.platform.data.IValue;
import org.csstudio.platform.logging.CentralLogger;

/** An ArchiveChannel that stores value in a periodic scan.
 *  @author <NAME>
 */
@SuppressWarnings("nls")
public class ScannedArchiveChannel extends ArchiveChannel implements Runnable
{
    /** Scan period in seconds */
    final private double scan_period;
    final private int max_repeats;
    private int repeats = 0;
    private Logger log;
    
    /** @see ArchiveChannel#ArchiveChannel(String, int, IValue) */
    public ScannedArchiveChannel(final String name,
                                 Enablement enablement, final int buffer_capacity,
                                 final IValue last_archived_value,
                                 final double scan_period,
                                 final int max_repeats) throws Exception
    {
        super(name, enablement, buffer_capacity, last_archived_value);
        this.scan_period = scan_period;
        this.max_repeats = max_repeats;
        log = CentralLogger.getInstance().getLogger(this);
        if (! log.isDebugEnabled())
            log = null;
    }
    
    /** @return Scan period in seconds */
    final public double getPeriod()
    {
        return scan_period;
    }

    @Override
    public String getMechanism()
    {
        return PeriodFormat.formatSeconds(scan_period) + " scan, max. "
            + max_repeats + " repeats";
    }

    // Just for debugging...
    @Override
    protected boolean handleNewValue(final IValue value)
    {
        final boolean written = super.handleNewValue(value);
        if (! written  &&   log != null)
            log.debug(getName() + ": cached " + value);
        return written;
    }

    /** Invoked by periodic scanner.
     *  Try to add the most recent value to the archive.
     *  Skip repeated values, unless we exceed the max. repeat count.
     */
    final public void run()
    {
        if (! isEnabled())
            return;
        final IValue value;
        synchronized (this)
        {   // Have anything?
            if (most_recent_value == null)
            {
                if (log != null)
                    log.debug(getName() + " scan: No data");
                return;
            }
            // Is it a new value?
            if (isMatchingValue(last_archived_value, most_recent_value))
            {
                ++repeats ;
                if (repeats < max_repeats)
                {
                    if (log != null)
                        log.debug(getName() + " skips  " + most_recent_value + ": repeat " + repeats);
                    return;
                }
                // No new value, but we'd like to write a sample every once in a while
                value = ValueButcher.transformTimestampToNow(most_recent_value);
                if (log != null)
                    log.debug(getName() + " writes " + most_recent_value + " as " + value.getTime());
                if (value == null)
                {
                    CentralLogger.getInstance().getLogger(this).error("Channel " + getName()
                                    + ": Cannot handle value type "
                                    + most_recent_value.getClass().getName());
                    return;
                }
            }
            else
            {   // It's a new value, so we should be able to write it
                // "as is"
                value = most_recent_value;
                if (log != null)
                    log.debug(getName() + " writes " + value);
            }
            // New value, or exceeded repeats
            repeats = 0;
        }
        // unlocked, should have 'value'
        addValueToBuffer(value);
    }

    /** Check if values match in status, severity, and value. Time is ignored.
     *  @param val1 One value
     *  @param val2 Other value
     *  @return <code>true</code> if they match
     */
    private boolean isMatchingValue(final IValue val1, final IValue val2)
    {
        // Compare data type and value
        if (val1 instanceof IDoubleValue)
        {
            if (! (val2 instanceof IDoubleValue))
                return false;
            final double v1[] = ((IDoubleValue) val1).getValues();
            final double v2[] = ((IDoubleValue) val2).getValues();
            if (!Arrays.equals(v1, v2))
                return false;
        }
        else if (val1 instanceof IEnumeratedValue)
{'fraction_non_alphanumeric': 0.09344225604297225, 'fraction_numerical': 0.0035810205908683975, 'mean_word_length': 1.7330275229357799, 'pattern_counts': {'":': 5, '<': 11, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 11, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4829709', 'n_tokens_mistral': 2435, 'n_tokens_neox': 2345, 'n_words': 643}