package base;

import openfl.Assets;
import openfl.events.Event;
import openfl.media.Sound;
import openfl.media.SoundChannel;
import openfl.media.SoundTransform;
import openfl.ui.Keyboard;
import openfl.Lib;

typedef PlayingSoundDescriptor = {
  id: String,
  type: String,
  sound: Sound,
  channel: SoundChannel,
  position: Float,
  looping: Bool,
  playing: Bool
};

class State extends GameSprite {
  public static var globalMute: Bool = false;

  public var mute(default, set): Bool = false;
  public var machine: StateMachine;

  public var keys:Array<Null<Int>> = [for (i in 0...256) null];

  var nowPlaying: Array<PlayingSoundDescriptor> = [];

  public function new() {
    super();
  }

  /**
   * Mute setter
   */
  function set_mute(value: Bool): Bool {
    if(!mute && value) {
      pauseAll();
    }

    if(mute && !value) {
      resumeAll();
    }

    return globalMute = mute = value;
  }

  public function pauseAll() {
    for(playing in nowPlaying) {
      playing.position = playing.channel.position;
      playing.channel.removeEventListener('soundComplete', removePlaying);
      playing.channel.stop();
      playing.playing = false;
    }
  }

  public function resumeAll() {
    for(playing in nowPlaying) {
      if(!playing.playing) {
        playing.channel = playing.sound.play(playing.position, playing.looping ? 9999 : 1);
        playing.channel.addEventListener('soundComplete', removePlaying);
      }
    }
  }

  public function stopMusic() {
    for(playing in nowPlaying) {
      if(playing.type == 'music') {
        playing.channel.stop();
        nowPlaying.remove(playing);
      }
    }
  }

  public function leave() {
    pauseAll();
  }

  public function enter() {
    resumeAll();
  }

  /**
    Play sound effect
   **/
  public function playSound(id: String, ?vol: Float = 1.0, ?pan: Float = 0.0, ?looped: Bool = false) {
    var sound: Sound = Assets.getSound(id);

    if((!mute) && (!globalMute)) {
      var channel = sound.play(0, looped ? 99999 : 1);

      channel.addEventListener('soundComplete', removePlaying);

      nowPlaying.push({
        id: id,
        type: 'sound',
        sound: sound,
        channel: channel,
        position: 0,
        looping: false,
        playing: true
      });

      return channel;
    }

    return null;
  }

  /**
   *  Stop playing sound
   *  
   *  @param channel - 
   */
  public function stopSound(channel: SoundChannel) {
    for(playing in nowPlaying) {
      if(playing.channel == channel) {
        nowPlaying.remove(playing);
        return;
      }
    }
  }

  /**
    Remove playing channel
   **/
  function removePlaying(e: Event) {
    var channel: SoundChannel = cast e.target;

    for(playing in nowPlaying) {
      if(playing.channel == channel) {
        nowPlaying.remove(playing);
        return;
      }
    }
  }

  /**
    Play Music
   **/
  public function playMusic(id: String, looping: Bool = true, vol: Float = 1.0, pan: Float = 0.0) {
    if(Assets.exists(id)) {
    var music: Sound = Assets.getSound(id);

    if((!mute) && (!globalMute)) {
      var channel = music.play(0, looping ? 9999 : 1);

      var playing:PlayingSoundDescriptor = {
        id: id,
        type: 'music',
        sound: music,
        channel: channel,
        position: 0,
        looping: looping,
        playing: true
      };

      nowPlaying.push(playing);

      channel.addEventListener('soundComplete', removePlaying);
      return playing;
    } else {
      return null;
    }
    } else {
      trace('Music not found: ${id}');
      return null;
    }
  }

  override public function keyDown(keyCode: Int, ctrl: Bool, alt: Bool, shift: Bool) {
    keys[keyCode] = keys[keyCode] == null ? Lib.getTimer() : keys[keyCode];
    super.keyDown(keyCode, ctrl, alt, shift);
  }

  override public function keyUp(keyCode: Int, ctrl: Bool, alt: Bool, shift: Bool) {
    keys[keyCode] = null;
    super.keyUp(keyCode, ctrl, alt, shift);
  }
}
