package game;

import openfl.media.SoundChannel;

import base.State;
import base.GameSprite;
import base.Fade;

import game.locations.Location;
import game.locations.Interactive;

import game.ui.Speech;

class Game extends State {
  public static var currentGame: Game;

  public var currentLocation: Location = null;

  var locationContainer: GameSprite = new GameSprite();
  var speech: Speech;

  var locationPool: Map<String, Location> = new Map<String, Location>();

  var music: SoundChannel = null;

  public function new() {
    super();

    addChild(locationContainer);

    currentGame = this;

    speech = new Speech();
    addChild(speech);

    setLocation(game.locations.alarmClock.AlarmClock);
  }

  public function startSoundTrack() {
    if(music != null) {
      music.stop();
    }
    music = playMusic('music/Beyond_the_Lows.ogg', true, 0.5).channel;
  }

  public function stopSoundTrack() {
    if(music != null) {
      music.stop();
      music = null;
    }
  }

  /**
   *  Get location instance by its class
   *  
   *  @param locationClass - Class of the location
   *  @return Location
   */
  public function getLocation(locationClass: Class<Location>): Location {
    var className: String = Type.getClassName(locationClass);
    if(locationPool.exists(className)) {
      return locationPool.get(className);
    } else {
      var location = Type.createInstance(locationClass, []);
      locationPool.set(className, location);
      return location;
    }

    return null;
  }

  /**
   *  Set location
   *  
   *  @param locationClass - Class of the location to set
   */
  public function setLocation(locationClass: Class<Location>, fade: Bool = false) {
    var location: Location;

    var className: String = Type.getClassName(locationClass);

    if(locationPool.exists(className)) {
      location = locationPool.get(className);
    } else {
      location = Type.createInstance(locationClass, []);
      locationPool.set(className, location);
    }

    if(fade) {
      addChild(new Fade('out', 0.5, true, function() {
        if(currentLocation != null) {
          currentLocation.leave();
          locationContainer.removeChild(currentLocation);
        }

        currentLocation = location;
        currentLocation.enter();

        locationContainer.addChild(currentLocation);

        addChild(new Fade('in', 0.5, true));
      }));
    } else {
      if(currentLocation != null) {
        currentLocation.leave();
        locationContainer.removeChild(currentLocation);
      }

      currentLocation = location;
      currentLocation.enter();

      locationContainer.addChild(currentLocation);
    }
  }

  /**
   *  Say something
   *  
   *  @param sentence - 
   *  @param time - 
   *  @param callback - 
   *  @param push - 
   */
  public function say(sentence: String, ?time: Null<Float> = null, ?callback: Void -> Void = null, ?push: Bool = true) {
    if(push || (!push && speech.current == null)) {
      speech.pushSentance(sentence, time, callback);
    } else {
      speech.now(sentence, time, callback);
    }
  }

  /**
   *  Say random sentence 
   *  
   *  @param sentences - Array of sentences to say
   */
  public function sayRandom(sentences: Array<String>) {
    say(sentences[Std.int(sentences.length * Math.random())], false);
  }

  /**
   *  Cancel everything 
   */
  public function sayCancel() {
    speech.stopAll();
  }

  public function hint(obj: Interactive) {
  }
}
