package game.locations.phoneLock;

import openfl.display.Bitmap;
import openfl.display.BitmapData;
import openfl.events.MouseEvent;
import openfl.events.Event;
import openfl.geom.Rectangle;
import openfl.geom.Point;
import openfl.Assets;
import openfl.media.SoundChannel;

import base.GameSprite;

import game.locations.Location;

import aseprite.Aseprite;

class PhoneButton extends GameSprite {
  var anim: Aseprite;
  var digits = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '0', '#'];
  public var digit: String;
  var sndChannel: SoundChannel = null;

  public function new(digit: String) {
    super();

    this.digit = digit;

    anim = new Aseprite('assets/locations/phoneLock/button');
    addChild(anim);

    var i:Int = digits.indexOf(digit);

    if(i != -1) {
      var buttons = Assets.getBitmapData('assets/locations/phoneLock/buttons.png');

      var bx: Int = i % 3;
      var by: Int = Std.int(i / 3);

      var bd = new BitmapData(9, 9);

      bd.copyPixels(buttons, new Rectangle(bx * 9, by * 9, 9, 9), new Point(0, 0));

      addChild(new Bitmap(bd));
    }

    addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
    addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
    addEventListener(MouseEvent.MOUSE_OUT, onMouseUp);

    buttonMode = true;

  }

  function onMouseDown(e: MouseEvent) {
    dispatchEvent(new Event('dial'));
    anim.play('down');

    var snd = digit;

    if(digit == '*') {
      snd = 'star';
    }

    if(digit == '#') {
      snd = 'hash';
    }
    sndChannel = Game.currentGame.playSound('sound/dtmf/' + snd + '.wav', true);
  }

  function onMouseUp(e: MouseEvent) {
    anim.play('up');
    if(sndChannel != null) {
      sndChannel.stop();
      sndChannel = null;
    }
  }
}

/**
 *  Dial
 *  
 */
class PhoneDial extends GameSprite {
  public var dialed: String = '';

  var digits: Array<Array<String>> = [
    ['1', '2', '3'],
    ['4', '5', '6'],
    ['7', '8', '9'],
    ['*', '0', '#']
  ];

  public function new() {
    super();

    for(j in 0...digits.length) {
      for(i in 0...digits[j].length) {
        var button = new PhoneButton(digits[j][i]);
        button.x = i * 9;
        button.y = j * 9;
        button.addEventListener('dial', onDial);
        addChild(button);
      }
    }
  }

  public function reset() {
    dialed = '';
  }

  function onDial(e: Event) {
    var button: PhoneButton = cast e.target;
    dialed += button.digit;
    dispatchEvent(new Event('dialed'));
  }
}

/**
 *  The Phone
 */
class Phone extends GameSprite {
  public static inline var OPEN_NUMBER: String = '667#';
  public static inline var SEQUENCE: String = '0831';
  public static inline var FAX_NUMBER: String = '1800343';

  var downWire: GameSprite;
  var upWire: GameSprite;
  var handSet: GameSprite;
  var body: GameSprite;
  var dial: PhoneDial;

  var ringback: SoundChannel = null;
  var dialTone: SoundChannel = null;
  var busyTone: SoundChannel = null;
  var staticSound: SoundChannel = null;
  var speech: SoundChannel = null;

  var dialDelay: Null<Float> = null;

  var mode: String = 'free_line';

  public function new() {
    super();

    downWire = new GameSprite('assets/locations/phoneLock/phone_wire.png');
    addChild(downWire);

    upWire = new GameSprite('assets/locations/phoneLock/phone_wire_pickedup.png');
    upWire.x = -147;
    upWire.y = 57;
    upWire.visible = false;
    addChild(upWire);

    body = new GameSprite('assets/locations/phoneLock/phone_body.png');
    body.mouseEnabled = body.buttonMode = true;
    body.addEventListener(MouseEvent.MOUSE_DOWN, dropHandset);
    addChild(body);

    dial = new PhoneDial();
    dial.x = 5;
    dial.y = 11;
    addChild(dial);

    dial.addEventListener('dialed', function(e: Event) {
      if(['free_line', 'awaiting_sequence'].indexOf(mode) != -1) {
        if(dialTone != null) {
          dialTone.stop();
        }
        dialDelay = 0;
      }
    });

    handSet = new GameSprite('assets/locations/phoneLock/phone_handset.png');
    handSet.mouseEnabled = handSet.buttonMode = true;
    handSet.addEventListener(MouseEvent.MOUSE_DOWN, pickUpHandset);
    addChild(handSet);
  }

  function busy() {
    mode = 'busy';
    busyTone = Game.currentGame.playSound('sound/phone_busy.ogg', true);
  }

  function hang() {
    dial.reset();
    Game.currentGame.playSound('sound/phone_click.ogg').addEventListener(Event.SOUND_COMPLETE, function(e: Event){
      dialTone = Game.currentGame.playSound('sound/dial_tone.ogg', true);
      mode = 'free_line';
    });
  }

  function connect() {
    if(mode == 'free_line') {
      if(dial.dialed == OPEN_NUMBER) {
        mode = 'in_call';
        ringback = Game.currentGame.playSound('sound/US_ringback_tone.ogg', true);

        timer(5, function() {
          ringback.stop();
          ringback = null;

          Game.currentGame.playSound('sound/phone_click.ogg').addEventListener(Event.SOUND_COMPLETE, function(e: Event) {
            speech = Game.currentGame.playSound('sound/phoneLock/sequence_request.ogg');
            speech.addEventListener(Event.SOUND_COMPLETE, function(e: Event) {
              speech = null;
              mode = 'awaiting_sequence';
              dial.reset();
            });
          });
        });
      } else if(dial.dialed == FAX_NUMBER) {
        mode = 'in_call';
        ringback = Game.currentGame.playSound('sound/US_ringback_tone.ogg', true);

        timer(5, function() {
          ringback.stop();
          ringback = null;
          var table: game.locations.phoneLock.PhoneLockTable = cast Game.currentGame.getLocation(game.locations.phoneLock.PhoneLockTable);

          table.showMesaage();

          Game.currentGame.playSound('sound/phone_click.ogg').addEventListener(Event.SOUND_COMPLETE, function(e: Event) {
            speech = Game.currentGame.playSound('sound/phoneLock/fax.ogg');
            speech.addEventListener(Event.SOUND_COMPLETE, function(e: Event) {
              hang();
            });
          });
        });
      } else {
        busy();
      }
    } else if(mode == 'awaiting_sequence') {
      mode = 'in_call';

      if(dial.dialed == SEQUENCE) {
        speech = Game.currentGame.playSound('sound/phoneLock/access_granted.ogg');
        speech.addEventListener(Event.SOUND_COMPLETE, function(e: Event) {
          timer(1, function() {
            dropHandset();

            handSet.mouseEnabled = handSet.buttonMode = false;
            handSet.removeEventListener(MouseEvent.MOUSE_DOWN, pickUpHandset);

            dispatchEvent(new Event('open'));
          });
        });
      } else {
        speech = Game.currentGame.playSound('sound/phoneLock/access_denied.ogg');
        speech.addEventListener(Event.SOUND_COMPLETE, function(e: Event) {
          hang();
        });
      }
    }
  }

  /**
   *  Update 
   *  
   *  @param delta - 
   */
  override function update(delta: Float) {
    super.update(delta);

    if(dialDelay != null){
      if(dialDelay >= 1.25) {
        dialDelay = null;
        connect();
      } else {
        dialDelay += delta;
      }
    }
  }

  /**
   *  Положить трубку
   *  
   *  @param e - 
   */
  function dropHandset(e: MouseEvent = null) {
    Game.currentGame.playSound('sound/elevator/phone_drop.ogg');
    handSet.visible = true;
    downWire.visible = true;
    upWire.visible = false;
    dial.reset();
    dialDelay = null;

    mode = 'free_line';

    if(busyTone != null) {
      busyTone.stop();
    }

    if(ringback != null) {
      ringback.stop();
      ringback = null;
    }

    if(dialTone != null) {
      dialTone.stop();
      dialTone = null;
    }

    if(staticSound != null) {
      staticSound.stop();
      staticSound = null;
    }

    if(speech != null) {
      speech.stop();
      speech = null;
    }

    Game.currentGame.startSoundTrack();

    dispatchEvent(new Event('hang'));
  }

  /**
   *  Поднять трубку
   *  
   *  @param e - 
   */
  function pickUpHandset(e: MouseEvent) {
    Game.currentGame.playSound('sound/elevator/phone_pick_up.ogg');
    Game.currentGame.stopSoundTrack();
    staticSound = Game.currentGame.playSound('sound/static.ogg', true);
    dialTone = Game.currentGame.playSound('sound/dial_tone.ogg', true);
    handSet.visible = false;
    downWire.visible = false;
    upWire.visible = true;
    dispatchEvent(new Event('pickup'));
  }
}

class PhoneLockDoor extends Location {
  public function new() {
    super();

    id = 'phoneLock';

    addBmpLayer('bg');

    var doorInside: Interactive = new Interactive(false, game.locations.finalExit.FinalExit);
    doorInside.gotoFade = true;
    doorInside.initBitmap(bmpPath('door_inside'));
    doorInside.x = 78;
    addChild(doorInside);

    var door = addBmpLayer('door', 78, 0);

    var phone = new Phone();
    phone.x = 70;
    phone.y = 65;
    door.addChild(phone);

    phone.addEventListener('pickup', function(e: Event) {
      navigation = false;
    });

    phone.addEventListener('hang', function(e: Event) {
      navigation = true;
    });

    phone.addEventListener('open', function(e: Event) {
      navigation = false;

      timer(1, function() {
        Game.currentGame.playSound('sound/entrance/door.ogg');
        door.tween({ scaleX: 0.6 }, 1).then(function() {
          doorInside.actionable = true;
        });
      });
    });

    downLocation = game.locations.phoneLock.PhoneLockRoom;
    leftLocation = game.locations.phoneLock.PhoneLockTv;
  }
}
