<commit_before>package org.intellimate.izou.system.sound;

import org.intellimate.izou.IzouModule;
import org.intellimate.izou.addon.AddOnModel;
import org.intellimate.izou.identification.Identification;
import org.intellimate.izou.main.Main;

import javax.sound.sampled.*;
import java.util.concurrent.Future;
import java.util.function.Consumer;

/**
 * the base class for every IzouSoundLine, provides basic implementation of the Methods defined int IzouSoundLine and
 * delegates to Line, AutoCloseable etc.
 * @author LeanderK
 * @version 1.0
 */
public class IzouSoundLineBaseClass extends IzouModule implements Line, AutoCloseable, IzouSoundLine {
    protected final Line line;
    private Future<?> closingThread;
    private boolean isPermanent;
    protected final SoundManager soundManager;
    private final AddOnModel addOnModel;
    private boolean isMutedFromSystem = false;
    private boolean isMutedFromUser = false;
    private Consumer<Void> closeCallback = null;
    private boolean muteIfNonPermanent = true;
    private Consumer<Void> muteCallback = null;
    private Identification responsibleID;

    public IzouSoundLineBaseClass(Line line, Main main, boolean isPermanent, AddOnModel addOnModel) {
        super(main, false);
        this.line = line;
        this.isPermanent = isPermanent;
        this.addOnModel = addOnModel;
        if (!isPermanent) {
            closingThread = getClosingThread(line, main, addOnModel);
        } else {
            closingThread = null;
        }
        soundManager = null;
    }

    private Future<?> getClosingThread(Line line, Main main, AddOnModel addOnModel) {
        return main.getThreadPoolManager().getIzouThreadPool().submit(() -> {
            try {
                Thread.sleep(600000);
            } catch (InterruptedException e) {
                error("interrupted while sleeping, canceling");
                return;
            }
            if (line.isOpen()) {
                debug("closing line " + line + "for Addon " + addOnModel);
                line.close();
            }
        });
    }

    /**
     * Obtains the <code>Line.Info</code> object describing this
     * line.
     * @return description of the line
     */
    @Override
    public Info getLineInfo() {
        return line.getLineInfo();
    }

    /**
     * Opens the line, indicating that it should acquire any required
     * system resources and become operational.
     * If this operation
     * succeeds, the line is marked as open, and an <code>OPEN</code> event is dispatched
     * to the line's listeners.
     * <p>
     * Note that some lines, once closed, cannot be reopened.  Attempts
     * to reopen such a line will always result in an <code>LineUnavailableException</code>.
     * <p>
     * Some types of lines have configurable properties that may affect
     * resource allocation.   For example, a <code>DataLine</code> must
     * be opened with a particular format and buffer size.  Such lines
     * should provide a mechanism for configuring these properties, such
     * as an additional <code>open</code> method or methods which allow
     * an application to specify the desired settings.
     * <p>
     * This method takes no arguments, and opens the line with the current
     * settings.  For <code>SourceDataLine</code> and
     * <code>TargetDataLine</code> objects, this means that the line is
     * opened with default settings.  For a <code>Clip</code>, however,
     * the buffer size is determined when data is loaded.  Since this method does not
     * allow the application to specify any data to load, an IllegalArgumentException
     * is thrown. Therefore, you should instead use one of the <code>open</code> methods
     * provided in the <code>Clip</code> interface to load data into the <code>Clip</code>.
     * <p>
     * For <code>DataLine</code>'s, if the <code>DataLine.Info</code>
     * object which was used to retrieve the line, specifies at least
     * one fully qualified audio format, the last one will be used
     * as the default format.
     *
     * @throws IllegalArgumentException if this method is called on a Clip instance.
     * @throws LineUnavailableException if the line cannot be
     * opened due to resource restrictions.
     * @throws SecurityException if the line cannot be
     * opened due to security restrictions.
     *
     * @see #close
     * @see #isOpen
     */
    @Override
    public void open() throws LineUnavailableException {
        if (!line.isOpen() && !isPermanent && muteCallback != null)
            muteCallback.accept(null);
        line.open();
    }

    /**
     * Closes the line, indicating that any system resources
     * in use by the line can be released.  If this operation
     * succeeds, the line is marked closed and a <code>CLOSE</code> event is dispatched
     * to the line's listeners.
     * @throws SecurityException if the line cannot be
     * closed due to security restrictions.
     *
     * @see #open
     * @see #isOpen
     */
    @Override
    public void close() {
        if (line.isOpen() && closeCallback != null)
            closeCallback.accept(null);
        line.close();
    }

    /**
     * Indicates whether the line is open, meaning that it has reserved
     * system resources and is operational, although it might not currently be
     * playing or capturing sound.
     * @return <code>true</code> if the line is open, otherwise <code>false</code>
     *
     * @see #open()
     * @see #close()
     */
    @Override
    public boolean isOpen() {
        return line.isOpen();
    }

    /**
     * currently not implemented, throws an UnsupportedOperationException.
     * @return an error
     */
    @Override
    public Control[] getControls() {
        throw new UnsupportedOperationException("method not available");
    }

    /**
     * currently not implemented, throws an UnsupportedOperationException.
     * @param control the control to check
     * @return an error
     */
    @Override
    public boolean isControlSupported(Control.Type control) {
        throw new UnsupportedOperationException("method not available");
    }

    /**
     * currently not implemented, throws an UnsupportedOperationException.
     * @param control the control
     * @return an error
     */
    @Override
    public Control getControl(Control.Type control) {
        if (control.toString().equals(BooleanControl.Type.MUTE.toString())) {
            return new FakeMuteControl();
        } else {
            return line.getControl(control);
        }
    }

    /**
     * follows no predictable behaviour, can be seen as not implemented.
     * @param listener the listener
     */
    @Override
    public void addLineListener(LineListener listener) {
        line.addLineListener(listener);
    }

    /**
     * follows no predictable behaviour, can be seen as not implemented.
     * @param listener the listener
     */
    @Override
    public void removeLineListener(LineListener listener) {
        line.removeLineListener(listener);
    }

    /**
     * returns whether the line is permanently-available.
     * If a line is not permanently available, it will close after max. 10 minutes
     * @return true if permanent.<commit_msg>added functionality to the Sound API<commit_after>package org.intellimate.izou.system.sound;

import org.intellimate.izou.IzouModule;
import org.intellimate.izou.addon.AddOnModel;
import org.intellimate.izou.identification.Identification;
import org.intellimate.izou.main.Main;

import javax.sound.sampled.*;
import java.util.concurrent.Future;
import java.util.function.Consumer;

/**
 * the base class for every IzouSoundLine, provides basic implementation of the Methods defined int IzouSoundLine and
 * delegates to Line, AutoCloseable etc.
 * @author LeanderK
 * @version 1.0
 */
public class IzouSoundLineBaseClass extends IzouModule implements Line, AutoCloseable, IzouSoundLine {
    protected final Line line;
    private Future<?> closingThread;
    private boolean isPermanent;
    protected final SoundManager soundManager;
    private final AddOnModel addOnModel;
    private boolean isMutedFromSystem = false;
    private boolean isMutedFromUser = false;
    private Consumer<Void> closeCallback = null;
    private boolean muteIfNonPermanent = true;
    private Consumer<Void> muteCallback = null;
    private Identification responsibleID;

    public IzouSoundLineBaseClass(Line line, Main main, boolean isPermanent, AddOnModel addOnModel) {
        super(main, false);
        this.line = line;
        this.isPermanent = isPermanent;
        this.addOnModel = addOnModel;
        if (!isPermanent) {
            closingThread = getClosingThread(line, main, addOnModel);
        } else {
            closingThread = null;
        }
        soundManager = null;
    }

    private Future<?> getClosingThread(Line line, Main main, AddOnModel addOnModel) {
        return main.getThreadPoolManager().getIzouThreadPool().submit(() -> {
            try {
                Thread.sleep(600000);
            } catch (InterruptedException e) {
                error("interrupted while sleeping, canceling");
                return;
            }
            if (line.isOpen()) {
                debug("closing line " + line + "for Addon " + addOnModel);
                line.close();
            }
        });
    }

    /**
     * Obtains the <code>Line.Info</code> object describing this
     * line.
     * @return description of the line
     */
    @Override
    public Info getLineInfo() {
        return line.getLineInfo();
    }

    /**
     * Opens the line, indicating that it should acquire any required
     * system resources and become operational.
     * If this operation
     * succeeds, the line is marked as open, and an <code>OPEN</code> event is dispatched
     * to the line's listeners.
     * <p>
     * Note that some lines, once closed, cannot be reopened.  Attempts
     * to reopen such a line will always result in an <code>LineUnavailableException</code>.
     * <p>
     * Some types of lines have configurable properties that may affect
     * resource allocation.   For example, a <code>DataLine</code> must
     * be opened with a particular format and buffer size.  Such lines
     * should provide a mechanism for configuring these properties, such
     * as an additional <code>open</code> method or methods which allow
     * an application to specify the desired settings.
     * <p>
     * This method takes no arguments, and opens the line with the current
     * settings.  For <code>SourceDataLine</code> and
     * <code>TargetDataLine</code> objects, this means that the line is
     * opened with default settings.  For a <code>Clip</code>, however,
     * the buffer size is determined when data is loaded.  Since this method does not
     * allow the application to specify any data to load, an IllegalArgumentException
     * is thrown. Therefore, you should instead use one of the <code>open</code> methods
     * provided in the <code>Clip</code> interface to load data into the <code>Clip</code>.
     * <p>
     * For <code>DataLine</code>'s, if the <code>DataLine.Info</code>
     * object which was used to retrieve the line, specifies at least
     * one fully qualified audio format, the last one will be used
     * as the default format.
     *
     * @throws IllegalArgumentException if this method is called on a Clip instance.
     * @throws LineUnavailableException if the line cannot be
     * opened due to resource restrictions.
     * @throws SecurityException if the line cannot be
     * opened due to security restrictions.
     *
     * @see #close
     * @see #isOpen
     */
    @Override
    public void open() throws LineUnavailableException {
        if (!line.isOpen() && !isPermanent && muteCallback != null)
            muteCallback.accept(null);
        line.open();
    }

    /**
     * Closes the line, indicating that any system resources
     * in use by the line can be released.  If this operation
     * succeeds, the line is marked closed and a <code>CLOSE</code> event is dispatched
     * to the line's listeners.
     * @throws SecurityException if the line cannot be
     * closed due to security restrictions.
     *
     * @see #open
     * @see #isOpen
     */
    @Override
    public void close() {
        if (line.isOpen() && closeCallback != null)
            closeCallback.accept(null);
        line.close();
    }

    /**
     * Indicates whether the line is open, meaning that it has reserved
     * system resources and is operational, although it might not currently be
     * playing or capturing sound.
     * @return <code>true</code> if the line is open, otherwise <code>false</code>
     *
     * @see #open()
     * @see #close()
     */
    @Override
    public boolean isOpen() {
        return line.isOpen();
    }

    /**
     * Obtains the set of controls associated with this line. Some controls may only be available when the line is open.
     * If there are no controls, this method returns an array of length 0.
     * The mute-control operation may be overridden by the System.
     * @return the array of controls
     * @see #isMutedFromSystem()
     */
    @Override
    public Control[] getControls() {
        Control[] controls = line.getControls();
        for (int i = 0; i < controls.length; i++) {
            Control control = controls[i];
            if (control.getType().toString().equals(BooleanControl.Type.MUTE.toString())) {
                controls[i] = new FakeMuteControl();
            }
        }
        return controls;
    }

    /**
     * Indicates whether the line supports a control of the specified type. Some controls may only be available when the line is open.
     * @param control the type of the control for which support is queried
     * @return true if at least one control of the specified type is supported, otherwise false.
     */
    @Override
    public boolean isControlSupported(Control.Type control) {
        return line.isControlSupported(control);
    }

    /**
     * Obtains a control of the specified type, if there is any.
     * Some controls may only be available when the line is open.
     * The mute-control operation may be overridden by the System.
     * @param control the type of the requested control
     * @return a control of the specified type
     * @throws IllegalArgumentException - if a control of the specified type is not supported
     * @see #isMutedFromSystem()
     */
    @Override
    public Control getControl(Control.Type control) throws IllegalArgumentException {
        if (control.toString().equals(BooleanControl.Type.MUTE.toString())) {
            return new FakeMuteControl();
        } else {
            return line.getControl(control);
        }
    }

    /**
     * follows no predictable behaviour, can be seen as not implemented.
     * @param listener the listener
     */
    @Override
    public void addLineListener(LineListener listener) {
        line.addLineListener(listener);
    }

    /**
     * follows no predictable behaviour, can be seen as not implemented.
     * @param listener the listener
     */
    @Override
    public void removeLineListener(LineListener listener) {
        line.removeLineListener(listener);
    }

    /**
     * returns whether the line is permanently-available.
     * If a line is not permanently available, it will close after max. 10 minutes
     * @return true if permanent.
{'fraction_non_alphanumeric': 0.08392374082184723, 'fraction_numerical': 0.0014169779724333377, 'mean_word_length': 2.6176607642124883, 'pattern_counts': {'":': 0, '<': 84, '<?xml version=': 0, '>': 85, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4760356', 'n_tokens_mistral': 4103, 'n_tokens_neox': 3996, 'n_words': 1509}