package ru.m.puzzlez.render;

import haxework.signal.Signal;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.geom.Point;
import haxework.view.SpriteView;
import openfl.Assets;
import ru.m.puzzlez.core.GameEvent;
import ru.m.puzzlez.core.GameState;

class Render extends SpriteView implements IRender {

    public var signal(default, null):Signal<GameEvent>;

    private var state:GameState;
    private var image:BitmapData;

    private var table:Sprite;
    private var parts:Map<Int, PartView>;
    private var activePart:PartView;
    private var activePoint:Point;

    public function new() {
        super();
        signal = new Signal();
        table = new Sprite();
        table.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
        content.addChild(table);
        parts = new Map();
    }

    public function onGameEvent(event:GameEvent):Void {
        switch event {
            case START(state):
                onStart(state);
            case PART_MOVE(id, point):
                var part = parts[id];
                part.x = point.x;
                part.y = point.y;
        }
    }

    private function onStart(state:GameState):Void {
        clean();
        image = Assets.getBitmapData(state.preset.image);
        image = RenderUtil.cropImage(image, state.preset.imageRect);
        for (part in state.parts) {
            var partImage = RenderUtil.cropImagePart(image, part.gridX, part.gridY, part.rect);
            var partView = new PartView(part.id, partImage);
            partView.x = part.rect.x;
            partView.y = part.rect.y;
            parts.set(part.id, partView);
            table.addChild(partView);
        }
        table.scaleX = table.scaleY = 0.25;
    }

    private function onMouseDown(event:MouseEvent):Void {
        if (Std.is(event.target, PartView)) {
            activePart = event.target;
            table.setChildIndex(activePart, table.numChildren - 1);
            activePoint = table.globalToLocal(new Point(event.stageX, event.stageY));
            table.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
            table.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
        }
    }

    private function onMouseMove(event:MouseEvent):Void {
        var newPoint = table.globalToLocal(new Point(event.stageX, event.stageY));
        var partPosition = new Point(
        activePart.x + newPoint.x - activePoint.x,
        activePart.y + newPoint.y - activePoint.y
        );
        signal.emit(GameEvent.PART_MOVE(activePart.id, partPosition));
        activePoint = newPoint;
    }

    private function onMouseUp(event:MouseEvent):Void {
        table.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
        table.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
        activePart = null;
        activePoint = null;
    }

    private function clean() {
        for (partView in parts) {
            table.removeChild(partView);
        }
        parts = new Map();
    }
}
