package game.locations.celestialLock;

import openfl.events.MouseEvent;
import openfl.events.Event;

import base.GameSprite;

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

/**
 *  Puzzle start
 */
class CelestialLockDoorPuzzleStar extends GameSprite {
  public var connectionName: Int;

  /**
   *  Constructor
   *  
   *  @param nx - new x position
   *  @param ny - new y position
   */
  public function new(connectionName: Int, nx: Float, ny: Float) {
    super('assets/locations/celestialLock/puzzle_star.png', -3, -3);
    this.connectionName = connectionName;
    x = nx;
    y = ny;

    addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
    addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
  }

  function onMouseOver(e: MouseEvent) {
    dispatchEvent(new Event('connect_try'));
  }

  function onMouseDown(e: MouseEvent) {
    dispatchEvent(new Event('select'));
  }
}

/**
 *  The Puzzle
 */
class CelestialLockDoorPuzzle extends Interactive {
  public var locked(default, set): Bool = true;

  var stars: Array<CelestialLockDoorPuzzleStar> = [];
  var beginingStar: CelestialLockDoorPuzzleStar = null;
  var connectToStar: CelestialLockDoorPuzzleStar = null;
  var connections: Array<{
    from: CelestialLockDoorPuzzleStar,
    to: CelestialLockDoorPuzzleStar
  }> = [];

  var positions: Array<Array<Float>> = [
    [70, 7],
    [92, 29],
    [47, 40],
    [21, 47],
    [84, 62],
    [58, 68],
    [30, 77]
  ];

  var correctConnections: Array<Array<Int>> = [
    [1, 2],
    [2, 5],
    [2, 3],
    [3, 6],
    [3, 4],
    [5, 6],
    [6, 7]
  ];

  var connectionsLayer: GameSprite = new GameSprite();
  var activeLine: GameSprite = new GameSprite();
  var hightlightLayer: GameSprite;

  /**
   *  Constructor
   */
  public function new() {
    super();

    initBitmap('assets/locations/celestialLock/puzzle_bg.png');

    hightlightLayer = new GameSprite('assets/locations/celestialLock/highlight.png');
    addChild(hightlightLayer);

    hightlightLayer.alpha = 0;

    addChild(connectionsLayer);

    var num: Int = 0;
    for(pos in positions) {
      var star = new CelestialLockDoorPuzzleStar(++num, pos[0], pos[1]);
      stars.push(star);
      addChild(star);
    }

    locked = true;

    activeLine.mouseEnabled = false;
    addChild(activeLine);

    addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
  }

  function set_locked(value: Bool): Bool {
    if(value) {
      for(star in stars) {
        star.addEventListener('select', onStarSelect);
        star.addEventListener('connect_try', onStarTryConnect);
        star.addEventListener(MouseEvent.MOUSE_OUT, onStarMouseOut);
        star.buttonMode = true;
      }
    } else {
      for(star in stars) {
        star.removeEventListener('select', onStarSelect);
        star.removeEventListener('connect_try', onStarTryConnect);
        star.removeEventListener(MouseEvent.MOUSE_OUT, onStarMouseOut);
        star.buttonMode = false;
      }
    }
    return actionable = locked = value;
  }

  function onStarMouseOut(e: MouseEvent) {
    connectToStar = null;
  }

  function onMouseUp(e: MouseEvent) {
    if((beginingStar != null)&&(connectToStar != null)) {
      var existing = connections.filter(function(item) {
        return ((item.from == beginingStar && item.to == connectToStar) || (item.to == beginingStar && item.from == connectToStar));
      });

      if(existing.length == 0) {
        connections.push({
          from: beginingStar.connectionName < connectToStar.connectionName ? beginingStar : connectToStar,
          to: beginingStar.connectionName < connectToStar.connectionName ? connectToStar : beginingStar 
        });
      } else {
        for(con in existing){
          connections.remove(con);
        }
      }

      connections.sort(function(a, b) {
        return a.from.connectionName > b.from.connectionName ? 1 : -1;
      });

      updateConnections();

      if(checkConnections()) {
        locked = false;
        Game.currentGame.playSound('sound/entrance/code-ok.ogg');
        hightlightLayer.tween({ alpha: 0.9 }, 0.1).then(function() {
          timer(0.1, function() {
            hightlightLayer.tween({ alpha: 0 }, 1).then(function() {
              dispatchEvent(new Event('unlocked'));
            });
          });
        });
      }
    }

    connectToStar = null;
    beginingStar = null;
    activeLine.graphics.clear();
  }

  function checkConnections(): Bool {
    var sorter = function(a: Array<Int>, b: Array<Int>) {
      return a[0] + a[1] < b[0] + b[1] ? -1 : 1;
    }

    var toTest:Array<Array<Int>> = connections.map(function(con) {
      return [con.from.connectionName, con.to.connectionName];
    });

    toTest.sort(sorter);
    correctConnections.sort(sorter);

    if(toTest.length == correctConnections.length) {
      for(i in 0...toTest.length) {
        if(!((toTest[i][0] == correctConnections[i][0])&&(toTest[i][1] == correctConnections[i][1]))) {
          return false;
        }
      }
    } else {
      return false;
    }

    return true;
  }

  function updateConnections() {
    connectionsLayer.graphics.clear();
    connectionsLayer.graphics.lineStyle(1, 0x68887e);

    for(con in connections) {
      connectionsLayer.graphics.moveTo(con.from.x, con.from.y);
      connectionsLayer.graphics.lineTo(con.to.x, con.to.y);
    }
  }

  function onStarTryConnect(e: Event) {
    var star: CelestialLockDoorPuzzleStar = cast e.target;

    if(star != beginingStar) {
      connectToStar = star;
    }
  }

  function onStarSelect(e: Event) {
    if(beginingStar == null) {
      beginingStar = cast e.target;
    }
  }

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

    if(beginingStar != null) {
      activeLine.graphics.clear();
      activeLine.graphics.lineStyle(1, 0xfbf236);
      activeLine.graphics.moveTo(beginingStar.x + 0.5, beginingStar.y + 0.5);
      activeLine.graphics.lineTo(mouseX, mouseY);
    }
  }
}

/**
 *  Location
 */
class CelestialLockDoor extends Location {
  public function new() {
    super();
    id = 'celestialLock';

    addBmpLayer('bg');
    var doorInside = new Interactive(game.locations.phoneLock.PhoneLockRoom);
    doorInside.gotoFade = true;
    doorInside.initBitmap(bmpPath('door_inside'));
    doorInside.x = 78;
    doorInside.actionable = false;
    addChild(doorInside);

    addBmpLayer('frame');
    var door = addBmpLayer('door', 89);

    var puzzle = new CelestialLockDoorPuzzle();
    puzzle.x = Math.floor((door.width - puzzle.width) / 2);
    puzzle.y = 54;
    puzzle.addEventListener('unlocked', function(e: Event) {
      navigation = false;
      Game.currentGame.playSound('sound/entrance/door.ogg');
      door.tween({ scaleX: 0.6 }, 1).then(function() {
        doorInside.actionable = true;
      });
    });
    door.addChild(puzzle);

    leftLocation = game.locations.celestialLockBasement.CelestialLockBasement;
  }
}
