package org.artisanlogiciel.games.maze.persist;

import org.artisanlogiciel.games.maze.Brick;
import org.artisanlogiciel.games.maze.LabyLayers;
import org.artisanlogiciel.games.maze.LabyModel;
import org.artisanlogiciel.games.minetest.*;

import java.io.*;

import static org.artisanlogiciel.games.minetest.Material.GRASS_MATERIAL;

public class MazePersistWorldEdit {

    private LabyModel model;
    private WorlEditGenerator generator;

    public MazePersistWorldEdit(LabyModel model) {
        this.model = model;
    }

    public MazePersistWorldEdit() {
        //
    }

    void addNode(Node node)
    {
        if (node != null )
        {
            generator.writeNode(node);
        }
    }

    private Node newNode(int x, int y, String material)
    {
        // x,y,z => x,z,y in minetest
        return new Node(x,0, y, Material.getMaterialByName(material));
    }

    void addWalls(int pX, int pY) {
        short walls = model.getWalls(pX, pY);
        short wdrawn = 0;
        // todo
        int w = 2;
        int h = 2;
        int ox = 0;
        int oy = 0;
        int z = 0;

        String material = GRASS_MATERIAL;

        int x = ox + (pX * w);
        int y = oy + (pY * h);

        // copied from drawing, where order did matter, might not be the case here...
        //if ((pY == 0) && LabyModel.isFlagSet(walls, Brick.UP)) {
        if (LabyModel.isFlagSet(walls, Brick.UP)) {
            for ( int dx = 0; dx < w; dx++) {
                addNode(newNode(x + dx, y,material));
            }
            wdrawn |= Brick.UP;
        }
        /*
        if (LabyModel.isFlagSet(walls, Brick.RIGHT)) {
            if (!LabyModel.isFlagSet(wdrawn, Brick.UP)) {
                addNode(new Node(x + (int) w, y, 0, material));
            }
            addNode(new Node(x + (int) w, y + (int) h, z, material));
            wdrawn |= Brick.RIGHT;
        }
        if (LabyModel.isFlagSet(walls, Brick.DOWN)) {
            if (!LabyModel.isFlagSet(wdrawn, Brick.RIGHT)) {
                addNode(new Node(x + (int) w, y + (int) h, z, material));
            }
            addNode(new Node(x, y + (int) h, z, material));
            wdrawn |= Brick.DOWN;
        }
        */
        //if ((pX == 0) && LabyModel.isFlagSet(walls, Brick.LEFT)) {
        if (LabyModel.isFlagSet(walls, Brick.LEFT)) {
            for (int dy = 0; dy < h; dy ++) {
                addNode(newNode(x, y + dy, material));
            }
            wdrawn |= Brick.LEFT;
        }
    }


    public void streamOut(String pFormat, OutputStream pOut) throws IOException {
        // WIP using WorldEditGenerator
        if ((pFormat == null) || (pFormat.equals("we"))) {

            Node refNode = new Node(0,0,0);
            StringBuilder builder = new StringBuilder();
            generator = new WorlEditGenerator(builder,refNode);
            generator.writeStart();
            // first raw format, not smart.
            DataOutputStream dataOut = new DataOutputStream(pOut);
            dataOut.flush();
            for (int y = 0; y < model.getHeight(); y++) {
                for (int x = 0; x < model.getWidth(); x++) {
                    addWalls(x,y);
                }
            }
            generator.writeEnd();
            dataOut.write(builder.toString().getBytes());
            dataOut.flush();
        } else {
            throw new IOException("Format " + pFormat + " Not yet implemented.");
        }
    }


    public LabyLayers parseInputStream(String pFormat, InputStream pIn) throws IOException {
        // TODO using WorldEditGenerator
        if ((pFormat == null) || (pFormat.equals("we"))) {
            // DataInputStream in = new DataInputStream(pIn);
            WorldEditReader reader = new WorldEditReader(pIn);
            // skip header "5.return " hacky way ...
            byte[] b = new byte[9];
            pIn.read(b);
            // System.out.println(new String(b));
            World world = reader.read();
            // need to convert world into a LabyModel ...
            // get level z = 0
            LabyLayers layers = new LabyLayers();
            if ( ! world.isEmpty()) {
                for (int level = world.getMin(); level <= world.getMax(); level++) {
                    Slice ground = world.getSlice(level);
                    if (ground != null) {
                        model = getModelFromSlice(ground);
                        model.setOnewaywall(true);
                        layers.addLabyModel(level, model);
                        System.out.println(model);
                    } else {
                        System.err.println("no ground !");
                    }
                }
            }
            return layers;
        } else {
            throw new IOException("Format " + pFormat + " Not yet implemented.");
        }

    }

    private LabyModel getModelFromSlice(Slice ground) {
        // TODO
        if ( ! ground.isEmpty() )
        {
            int width = ground.getRangeSize();
            Range rawRange = ground.getRawRange();
            int height =  rawRange.getRangeSize();
            int up = rawRange.getMin();

            short [][] t = new short[width][height];
            if ( ! ground.isEmpty() ) {
                int left = ground.getMin();
                for (int x = ground.getMin(); x <= ground.getMax(); x++) {
                    // work on raws ...
                    Raw raw = ground.getRaw(new Integer(x));
                    if ( raw != null) {
                        if (!raw.isEmpty()) {
                            for (int y = raw.getMin(); y <= raw.getMax(); y++) {
                                // full closed place ... ( lazzy ... )
                                Node node = raw.getNode(y);
                                short move = LabyModel.EMPTY | 32;
                                if (node != null) {
                                    move = 0;
                                }
                                int newx = x - left;
                                int newy = y - up;
                                System.out.println(" " + newx + " " + newy + " =" + move);
                                t[newx][newy] = move;
                            }
                        }
                    }
                }
            }
            model = new LabyModel(width,height, t);
            return model;
        }
        else
        {
            System.out.println("empty ground");
        }

        return null;
    }

}
