/**
 *  Copyright © 2020-2025, Luis Andrés Lange <https://javacomm.net>
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *  ----------------------------------------------------------------------------
 *
 *  Exhibit B - "Incompatible With Secondary Licenses" Notice
 *
 *  This Source Code Form is "Incompatible With Secondary Licenses",
 *  as defined by the Mozilla Public License, v. 2.0.
 *
 *  In short:
 *  - This file may be used, modified, and distributed under MPL 2.0 only.
 *  - It may NOT be relicensed under GPL, LGPL, AGPL, or any other Secondary License.
 *
 *  Rationale:
 *  - Ensures that the code remains MPL-2.0.
 *  - Avoids legal conflicts with GPL-licensed libraries (e.g., VideoLAN).
 *  - Maximizes usability for commercial and security-critical applications.
 *
 */
package net.javacomm.client.phone;

import com.github.trilarion.sound.vorbis.sampled.spi.VorbisAudioFileReader;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.javacomm.client.resource.Resource;

public final class SoundClip {

  private final static Logger log = LogManager.getLogger(SoundClip.class);
  private static Clip ringtoneClip;
  private static Clip dialtoneClip;
  private static Clip offhookClip;
  private static Clip modemClip;
  private static Clip busytoneClip;
  private static Class<? extends SoundClip> resource;
  private static VorbisAudioFileReader ringtoneReader;
  private static VorbisAudioFileReader busyReader;
  private static VorbisAudioFileReader dialingReader;
  private static VorbisAudioFileReader offhookReader;
  
  
  static {
    try {
      new SoundClip();
    }
    catch (LineUnavailableException e) {
      log.fatal(e.getMessage(), e.getCause());
      throw new RuntimeException(e.getMessage(), e.getCause());
    }
  }

  
  private SoundClip() throws LineUnavailableException {
    resource = getClass();
    ringtoneClip = AudioSystem.getClip();
    dialtoneClip = AudioSystem.getClip();
    offhookClip = AudioSystem.getClip();
    modemClip = AudioSystem.getClip();
    busytoneClip = AudioSystem.getClip();
  }

  
  /**
   * Die Resourcen aller Soundclips werden freigegeben.
   * 
   */
  public static void release() {
    ringtoneClip.close();
    dialtoneClip.close();
    offhookClip.close();
    modemClip.close();
    busytoneClip.close();
    stopModemtone();
  }

  
  
  public static void playBusytone() throws IOException, UnsupportedAudioFileException, LineUnavailableException {
    if (!busytoneClip.isOpen()) {
      busyReader = new VorbisAudioFileReader();
      try(AudioInputStream oggStream = busyReader
          .getAudioInputStream(resource.getResource(Resource.BUSYTONE));
          AudioInputStream audiostream = AudioSystem.getAudioInputStream(oggStream)) {

        AudioFormat busytoneFormat = oggStream.getFormat();
        AudioFormat pcmFormat = new AudioFormat(
            AudioFormat.Encoding.PCM_SIGNED, busytoneFormat.getSampleRate(), 16, busytoneFormat.getChannels(),
            busytoneFormat.getChannels() * 2, busytoneFormat.getSampleRate(), false
        );

        // konvertiert
        try(AudioInputStream targetStream = AudioSystem.getAudioInputStream(pcmFormat, oggStream);) {
          busytoneClip.open(targetStream);
        }
      }
    }
    busytoneClip.setFramePosition(0);
    busytoneClip.start();
  }
  
  
  
  public static void stopBusytone() {
    busytoneClip.stop();
    busytoneClip.close();
  }

  
  
  public static void playModemtone() throws IOException, UnsupportedAudioFileException, LineUnavailableException {
    if (!modemClip.isOpen()) {
      try(AudioInputStream audiostream = AudioSystem.getAudioInputStream(resource.getResource(Resource.MODEM_AIF))) {
        modemClip.open(audiostream);
      }
    }
    modemClip.setFramePosition(0);
    modemClip.start();
  }
  
  
  
  public static void stopModemtone() {
    modemClip.stop();
    modemClip.close();
  }

  

  public static void playOffhooktone() throws IOException, UnsupportedAudioFileException, LineUnavailableException {
    if (!offhookClip.isOpen()) {
      offhookReader = new VorbisAudioFileReader();
      try(AudioInputStream oggStream = offhookReader
          .getAudioInputStream(resource.getResource(Resource.OFFHOOK));
          AudioInputStream audiostream = AudioSystem.getAudioInputStream(oggStream)) {

        AudioFormat offhookFormat = oggStream.getFormat();
        AudioFormat pcmFormat = new AudioFormat(
            AudioFormat.Encoding.PCM_SIGNED, offhookFormat.getSampleRate(), 16, offhookFormat.getChannels(),
            offhookFormat.getChannels() * 2, offhookFormat.getSampleRate(), false
        );

        // konvertiert
        try(AudioInputStream targetStream = AudioSystem.getAudioInputStream(pcmFormat, oggStream);) {
          offhookClip.open(targetStream);
        }
      }
    }
    offhookClip.setFramePosition(0);
    offhookClip.start();
  }
  
  
  
  public static void stopOffhooktone() {
    offhookClip.stop();
    offhookClip.close();
  }


  
  
  
  public static void playDialtone() throws IOException, UnsupportedAudioFileException, LineUnavailableException {
    if (!dialtoneClip.isOpen()) {
      dialingReader = new VorbisAudioFileReader();
      try(AudioInputStream oggStream = dialingReader
          .getAudioInputStream(resource.getResource(Resource.DIALTONE));
          AudioInputStream audiostream = AudioSystem.getAudioInputStream(oggStream)) {

        AudioFormat dialingFormat = oggStream.getFormat();
        AudioFormat pcmFormat = new AudioFormat(
            AudioFormat.Encoding.PCM_SIGNED, dialingFormat.getSampleRate(), 16, dialingFormat.getChannels(),
            dialingFormat.getChannels() * 2, dialingFormat.getSampleRate(), false
        );

        // konvertiert
        try(AudioInputStream targetStream = AudioSystem.getAudioInputStream(pcmFormat, oggStream);) {
          dialtoneClip.open(targetStream);
        }
      }
    }
    dialtoneClip.setFramePosition(0);
    dialtoneClip.start();
  }
  
  
  
  public static void stopDialtone() {
    dialtoneClip.stop();
    dialtoneClip.close();
  }

  
  
  public static void playRingtone() throws IOException, UnsupportedAudioFileException, LineUnavailableException {
    if (!ringtoneClip.isOpen()) {
      ringtoneReader = new VorbisAudioFileReader();
      try(AudioInputStream oggStream = ringtoneReader
          .getAudioInputStream(resource.getResource(Resource.RINGTONE));
          AudioInputStream audiostream = AudioSystem.getAudioInputStream(oggStream)) {

        AudioFormat ringtoneFormat = oggStream.getFormat();
        AudioFormat pcmFormat = new AudioFormat(
            AudioFormat.Encoding.PCM_SIGNED, ringtoneFormat.getSampleRate(), 16, ringtoneFormat.getChannels(),
            ringtoneFormat.getChannels() * 2, ringtoneFormat.getSampleRate(), false
        );

        // konvertiert
        try(AudioInputStream targetStream = AudioSystem.getAudioInputStream(pcmFormat, oggStream);) {
          ringtoneClip.open(targetStream);
        }
      }
    }
    ringtoneClip.setFramePosition(0);
    ringtoneClip.start();
  }
  
  

  /**
   * Der Klingelton wird abgestellt.
   */
  public static void stopRingtone() {
    ringtoneClip.stop();
    ringtoneClip.close();
  }
  

  
  
}
